diff --git a/Plugins/Victory/Binaries/Win64/UE4Editor-VictoryBPLibrary.dll b/Plugins/Victory/Binaries/Win64/UE4Editor-VictoryBPLibrary.dll new file mode 100644 index 00000000..121b8130 Binary files /dev/null and b/Plugins/Victory/Binaries/Win64/UE4Editor-VictoryBPLibrary.dll differ diff --git a/Plugins/Victory/Binaries/Win64/UE4Editor-VictoryBPLibrary.pdb b/Plugins/Victory/Binaries/Win64/UE4Editor-VictoryBPLibrary.pdb new file mode 100644 index 00000000..5307bf40 Binary files /dev/null and b/Plugins/Victory/Binaries/Win64/UE4Editor-VictoryBPLibrary.pdb differ diff --git a/Plugins/Victory/Binaries/Win64/UE4Editor.modules b/Plugins/Victory/Binaries/Win64/UE4Editor.modules new file mode 100644 index 00000000..72c6d4fd --- /dev/null +++ b/Plugins/Victory/Binaries/Win64/UE4Editor.modules @@ -0,0 +1,7 @@ +{ + "BuildId": "13144385", + "Modules": + { + "VictoryBPLibrary": "UE4Editor-VictoryBPLibrary.dll" + } +} \ No newline at end of file diff --git a/Plugins/Victory/Resources/Icon128.png b/Plugins/Victory/Resources/Icon128.png new file mode 100644 index 00000000..155480ac Binary files /dev/null and b/Plugins/Victory/Resources/Icon128.png differ diff --git a/Plugins/Victory/Resources/Thumbs.db b/Plugins/Victory/Resources/Thumbs.db new file mode 100644 index 00000000..c37cb4ec Binary files /dev/null and b/Plugins/Victory/Resources/Thumbs.db differ diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Private/TKMathFunctionLibrary.cpp b/Plugins/Victory/Source/VictoryBPLibrary/Private/TKMathFunctionLibrary.cpp new file mode 100644 index 00000000..3c5bc225 --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Private/TKMathFunctionLibrary.cpp @@ -0,0 +1,429 @@ +/* + By TK-Master +*/ +#include "VictoryBPLibraryPrivatePCH.h" + +#include "TKMathFunctionLibrary.h" + +#include "StaticMeshResources.h" + +//UTKMathFunctionLibrary + +float UTKMathFunctionLibrary::GetConsoleVariableFloat(FString VariableName) +{ + const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataFloat(*VariableName); + + if (CVar) + { + return CVar->GetValueOnGameThread(); + //return CVar->GetValueOnAnyThread(); + } + + return 0.f; +} + +int32 UTKMathFunctionLibrary::GetConsoleVariableInt(FString VariableName) +{ + const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(*VariableName); + + if (CVar) + { + return CVar->GetValueOnGameThread(); + //return CVar->GetValueOnAnyThread(); + } + return 0; +} + +float UTKMathFunctionLibrary::NegateFloat(float A) +{ + return -A; +} + +int32 UTKMathFunctionLibrary::NegateInt(int32 A) +{ + return -A; +} + +FVector2D UTKMathFunctionLibrary::NegateVector2D(FVector2D A) +{ + return -A; +} + +FVector UTKMathFunctionLibrary::SetVectorLength(FVector A, float size) +{ + return A.GetSafeNormal() * size; +} + +FVector UTKMathFunctionLibrary::VectorRadiansToDegrees(FVector RadVector) +{ + return FVector::RadiansToDegrees(RadVector); +} + +FVector UTKMathFunctionLibrary::VectorDegreesToRadians(FVector DegVector) +{ + return FVector::DegreesToRadians(DegVector); +} + +int32 UTKMathFunctionLibrary::RoundToLowerMultiple(int32 A, int32 Multiple, bool skipSelf) +{ + int32 result = (A / Multiple) * Multiple; + if (skipSelf && result == A && result != 0) + { + return ((A-1) / Multiple) * Multiple; + } + return result; +} + +int32 UTKMathFunctionLibrary::RoundToUpperMultiple(int32 A, int32 Multiple, bool skipSelf) +{ + if (skipSelf || FMath::Fmod(A, Multiple) != 0) + { + A = ((A + Multiple) / Multiple) * Multiple; + } + return A; +} + +int32 UTKMathFunctionLibrary::RoundToNearestMultiple(int32 A, int32 Multiple) +{ + return ((A + Multiple / 2) / Multiple) * Multiple; +} + +bool UTKMathFunctionLibrary::IsPowerOfTwo(int32 x) +{ + //return x && ((x&-x) == x); + return FMath::IsPowerOfTwo(x); +} + +bool UTKMathFunctionLibrary::IsMultipleOf(int32 A, int32 Multiple) +{ + return FMath::Fmod(A, Multiple) == 0; +} + +bool UTKMathFunctionLibrary::IsEvenNumber(float A) +{ + return FMath::Fmod(A, 2) == 0; +} + +FVector UTKMathFunctionLibrary::ClosestPointOnSphereToLine(FVector SphereOrigin, float SphereRadius, FVector LineOrigin, FVector LineDir) +{ + static FVector OutClosestPoint; + FMath::SphereDistToLine(SphereOrigin, SphereRadius, LineOrigin, LineDir.GetSafeNormal(), OutClosestPoint); + return OutClosestPoint; +} + +FVector UTKMathFunctionLibrary::ClosestPointOnLineSeqment(FVector Point, FVector LineStart, FVector LineEnd) +{ + return FMath::ClosestPointOnLine(LineStart, LineEnd, Point); +} + +bool UTKMathFunctionLibrary::IsPointInsideBox(FVector Point, FVector BoxOrigin, FVector BoxExtent) +{ + FBox Box = FBox::BuildAABB(BoxOrigin, BoxExtent); + return FMath::PointBoxIntersection(Point, Box); +} + +bool UTKMathFunctionLibrary::SphereBoxIntersection(FVector SphereOrigin, float SphereRadius, FVector BoxOrigin, FVector BoxExtent) +{ + FBox Box = FBox::BuildAABB(BoxOrigin, BoxExtent); + return FMath::SphereAABBIntersection(SphereOrigin, FMath::Square(SphereRadius), Box); +} + +bool UTKMathFunctionLibrary::IsLineInsideSphere(FVector LineStart, FVector LineDir, float LineLength, FVector SphereOrigin, float SphereRadius) +{ + return FMath::LineSphereIntersection(LineStart, LineDir, LineLength, SphereOrigin, SphereRadius); +} + +bool UTKMathFunctionLibrary::LineExtentBoxIntersection(FBox inBox, FVector Start, FVector End, FVector Extent, FVector& HitLocation, FVector& HitNormal, float& HitTime) +{ + return FMath::LineExtentBoxIntersection(inBox, Start, End, Extent, HitLocation, HitNormal, HitTime); +} + +float UTKMathFunctionLibrary::SignedDistancePlanePoint(FVector planeNormal, FVector planePoint, FVector point) +{ + return FVector::DotProduct(planeNormal, (point - planePoint)); +} + +FVector UTKMathFunctionLibrary::ProjectPointOnLine(FVector LineOrigin, FVector LineDirection, FVector Point) +{ + //FVector linePointToPoint = point - linePoint; + //float t = FVector::DotProduct(linePointToPoint, lineDir); + //return linePoint + lineDir * t; + + //FVector closestPoint; + //OutDistance = FMath::PointDistToLine(point, lineDir, linePoint, closestPoint); + //return closestPoint; + + FVector SafeDir = LineDirection.GetSafeNormal(); + return LineOrigin + (SafeDir * ((Point - LineOrigin) | SafeDir)); +} + +void UTKMathFunctionLibrary::ClosestPointsOfLineSegments(FVector Line1Start, FVector Line1End, FVector Line2Start, FVector Line2End, FVector& LinePoint1, FVector& LinePoint2) +{ + FMath::SegmentDistToSegmentSafe(Line1Start, Line1End, Line2Start, Line2End, LinePoint1, LinePoint2); +} + +bool UTKMathFunctionLibrary::LineToLineIntersection(FVector& IntersectionPoint, FVector LinePoint1, FVector LineDir1, FVector LinePoint2, FVector LineDir2) +{ + //Are lines coplanar? + if (!FVector::Coplanar(LinePoint1, LineDir1, LinePoint2, LineDir2, DELTA)) + { + return false; + } + + FVector LineDir3 = LinePoint2 - LinePoint1; + FVector CrossDir1And2 = FVector::CrossProduct(LineDir1, LineDir2); + FVector CrossDir3And2 = FVector::CrossProduct(LineDir3, LineDir2); + + float s = FVector::DotProduct(CrossDir3And2, CrossDir1And2) / CrossDir1And2.SizeSquared(); + + if (s > 1.0f || s < 0.0f) + { + return false; + } + else + { + IntersectionPoint = LinePoint1 + (LineDir1 * s); + return true; + } +} + +bool UTKMathFunctionLibrary::ClosestPointsOnTwoLines(FVector& closestPointLine1, FVector& closestPointLine2, FVector linePoint1, FVector lineVec1, FVector linePoint2, FVector lineVec2) +{ + float a = FVector::DotProduct(lineVec1, lineVec1); + float b = FVector::DotProduct(lineVec1, lineVec2); + float e = FVector::DotProduct(lineVec2, lineVec2); + + float d = a*e - b*b; + + //lines are not parallel + if (d != 0.0f) + { + FVector r = linePoint1 - linePoint2; + float c = FVector::DotProduct(lineVec1, r); + float f = FVector::DotProduct(lineVec2, r); + + float s = (b*f - c*e) / d; + float t = (a*f - c*b) / d; + + closestPointLine1 = linePoint1 + lineVec1 * s; + closestPointLine2 = linePoint2 + lineVec2 * t; + + return true; + } + else + { + return false; + } +} + +int32 UTKMathFunctionLibrary::PointOnWhichSideOfLineSegment(FVector linePoint1, FVector linePoint2, FVector point) +{ + FVector lineVec = linePoint2 - linePoint1; + FVector pointVec = point - linePoint1; + + float dot = FVector::DotProduct(pointVec, lineVec); + + //point is on side of linePoint2, compared to linePoint1 + if (dot > 0) + { + //point is on the line segment + if (pointVec.Size() <= lineVec.Size()) + { + return 0; + } + + //point is not on the line segment and it is on the side of linePoint2 + else + { + return 2; + } + } + + //Point is not on side of linePoint2, compared to linePoint1. + //Point is not on the line segment and it is on the side of linePoint1. + else + { + return 1; + } +} + +bool UTKMathFunctionLibrary::AreLineSegmentsCrossing(FVector pointA1, FVector pointA2, FVector pointB1, FVector pointB2) +{ + FVector closestPointA; + FVector closestPointB; + int32 sideA; + int32 sideB; + + FVector lineVecA = pointA2 - pointA1; + FVector lineVecB = pointB2 - pointB1; + + bool valid = ClosestPointsOnTwoLines(closestPointA, closestPointB, pointA1, lineVecA.GetSafeNormal(), pointB1, lineVecB.GetSafeNormal()); + + //lines are not parallel + if (valid) + { + sideA = PointOnWhichSideOfLineSegment(pointA1, pointA2, closestPointA); + sideB = PointOnWhichSideOfLineSegment(pointB1, pointB2, closestPointB); + + if ((sideA == 0) && (sideB == 0)) + { + return true; + } + else + { + return false; + } + } + + //lines are parallel + else + { + return false; + } +} + +FVector UTKMathFunctionLibrary::GridSnap(FVector A, float Grid) +{ + return A.GridSnap(Grid); +} + +void UTKMathFunctionLibrary::ConvertAnchorToAnchor(UObject* WorldContextObject, FAnchors CurrentAnchor, FMargin Offsets, FAnchors TargetAnchor, FMargin& ConvertedOffsets) +{ + if (CurrentAnchor.Minimum == TargetAnchor.Minimum && CurrentAnchor.Maximum == TargetAnchor.Maximum) + { + ConvertedOffsets = Offsets; + return; + } + + FVector2D View = FVector2D(1, 1); + UWorld* World = GEngine->GetWorldFromContextObjectChecked(WorldContextObject); + if (World && World->IsGameWorld()) + { + if (UGameViewportClient* ViewportClient = World->GetGameViewport()) + { + ViewportClient->GetViewportSize(View); + } + } + + FMargin ZeroAnchorOffsets = Offsets; + //Convert to 0,0 anchor first. + if (CurrentAnchor.Minimum != FVector2D(0, 0) || CurrentAnchor.Maximum != FVector2D(0, 0)) + { + ZeroAnchorOffsets.Left = View.X * CurrentAnchor.Minimum.X + Offsets.Left; + ZeroAnchorOffsets.Top = View.Y * CurrentAnchor.Minimum.Y + Offsets.Top; + + if (CurrentAnchor.Minimum.X != CurrentAnchor.Maximum.X) + { + ZeroAnchorOffsets.Right = View.X * CurrentAnchor.Maximum.X - (Offsets.Right + Offsets.Left); + } + if (CurrentAnchor.Minimum.Y != CurrentAnchor.Maximum.Y) + { + ZeroAnchorOffsets.Bottom = View.Y * CurrentAnchor.Maximum.Y - (Offsets.Bottom + Offsets.Top); + } + + if (TargetAnchor.Minimum == FVector2D(0, 0) && TargetAnchor.Maximum == FVector2D(0, 0)) + { + ConvertedOffsets = ZeroAnchorOffsets; + return; + } + } + + //Convert 0,0 anchor offsets to target anchor offsets. + ConvertedOffsets.Left = (-View.X) * TargetAnchor.Minimum.X + ZeroAnchorOffsets.Left; + ConvertedOffsets.Top = (-View.Y) * TargetAnchor.Minimum.Y + ZeroAnchorOffsets.Top; + + ConvertedOffsets.Right = TargetAnchor.Minimum.X != TargetAnchor.Maximum.X ? View.X * TargetAnchor.Maximum.X - (ZeroAnchorOffsets.Left + ZeroAnchorOffsets.Right) : ZeroAnchorOffsets.Right; + ConvertedOffsets.Bottom = TargetAnchor.Minimum.Y != TargetAnchor.Maximum.Y ? View.Y * TargetAnchor.Maximum.Y - (ZeroAnchorOffsets.Top + ZeroAnchorOffsets.Bottom) : ZeroAnchorOffsets.Bottom; +} + + +float UTKMathFunctionLibrary::ConvertPhysicsLinearVelocity(FVector Velocity, TEnumAsByte SpeedUnit) +{ + if (Velocity.IsZero()) return 0.f; + + float unit = 0; + switch (SpeedUnit) + { + case CentimeterPerSecond: + unit = 1; + break; + case FootPerSecond: + unit = 0.03280839895013; + break; + case MeterPerSecond: + unit = 0.01; + break; + case MeterPerMinute: + unit = 0.6; + break; + case KilometerPerSecond: + unit = 0.00001; + case KilometerPerMinute: + unit = 0.0006; + break; + case KilometerPerHour: + unit = 0.036; + break; + case MilePerHour: + unit = 0.02236936292054; + break; + case Knot: + unit = 0.01943844492441; + break; + case Mach: + unit = 0.00002915451895044; + break; + case SpeedOfLight: + unit = 3.335640951982E-11; + break; + case YardPerSecond: + unit = 0.01093613298338; + break; + default: + break; + }; + + return Velocity.Size() * unit; +} + +FVector UTKMathFunctionLibrary::GetVelocityAtPoint(UPrimitiveComponent* Target, FVector Point, FName BoneName, bool DrawDebugInfo) +{ + + //FTransform Transform = Target->GetComponentTransform(); + //FVector LocalLinearVelocity = Transform.InverseTransformVectorNoScale(Target->GetPhysicsLinearVelocity()); + //FVector LocalAngularVelocity = Transform.InverseTransformVectorNoScale(Target->GetPhysicsAngularVelocity()); + //FVector ResultPointVelocity = LocalLinearVelocity + FVector::CrossProduct(FVector::DegreesToRadians(LocalAngularVelocity), Transform.InverseTransformVectorNoScale(Point - Target->GetCenterOfMass())); + + + if (!Target) return FVector::ZeroVector; + + //You can actually get it from the physx body instance instead. + FBodyInstance* BI = Target->GetBodyInstance(BoneName); + if (BI && BI->IsValidBodyInstance()) + { + FVector PointVelocity = BI->GetUnrealWorldVelocityAtPoint(Point); + + UWorld* TheWorld = Target->GetWorld(); + if (DrawDebugInfo && TheWorld) + { + FColor DefaultColor(255,200,0); + DrawDebugPoint(TheWorld, Point, 10, DefaultColor); + DrawDebugString(TheWorld, Point, FString::SanitizeFloat(PointVelocity.Size()), NULL, FColor::White, 0.0f); + } + + return PointVelocity; + } + return FVector::ZeroVector; +} + +void UTKMathFunctionLibrary::SetCenterOfMassOffset(UPrimitiveComponent* Target, FVector Offset, FName BoneName) +{ + if (!Target) return; + + FBodyInstance* BI = Target->GetBodyInstance(BoneName); + if (BI && BI->IsValidBodyInstance()) + { + BI->COMNudge = Offset; + BI->UpdateMassProperties(); + } +} diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPFunctionLibrary.cpp b/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPFunctionLibrary.cpp new file mode 100644 index 00000000..6e814410 --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPFunctionLibrary.cpp @@ -0,0 +1,5668 @@ +/* + 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 "Runtime/Engine/Public/VorbisAudioInfo.h" + + +#include "StaticMeshResources.h" + +#include "HeadMountedDisplay.h" + +#include "GenericTeamAgentInterface.h" + +//For PIE error messages +#include "Runtime/Core/Public/Logging/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_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 +#include + +#include + +/* + ~~~ Rama File Operations CopyRight ~~~ + + If you use any of my file operation code below, + please credit me somewhere appropriate as "Rama" +*/ +template +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 +PlatformFileFunctor MakeDirectoryVisitor(Functor&& FunctorInstance) +{ + return PlatformFileFunctor(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& 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 +){ + //! See .h deprecation + + /* + 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; + + ULevelStreamingDynamic* StreamingLevel = NewObject(World, ULevelStreamingDynamic::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->SetShouldBeVisible(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; + */ + return nullptr; + } + +//~~~~~~~ +// AI +//~~~~~~~ +EPathFollowingRequestResult::Type UVictoryBPFunctionLibrary::Victory_AI_MoveToWithFilter( + APawn* Pawn, + const FVector& Dest, + TSubclassOf FilterClass , + float AcceptanceRadius , + bool bProjectDestinationToNavigation , + bool bStopOnOverlap , + bool bCanStrafe +){ + if(!Pawn) + { + return EPathFollowingRequestResult::Failed; + } + + AAIController* AIControl = Cast(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 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 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 & Children) +{ + Children.Empty(); + + const int32 NumBones = ReferenceSkeleton.GetNum(); + for(int32 ChildIndex=ParentBoneIndex+1; ChildIndex& ChildBoneNames) +{ + TArray 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& 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& 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& 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 Files; //false = not recursive, not expecting subdirectories + bool Success = GetFiles(ScreenShotsDir, Files, false); + + if(!Success) + { + return false; + } + + //Filter + TArray 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 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& Out) +{ + if(!WorldContextObject) return; + + UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull); + if(!World) return; + //~~~~~~~~~~~ + + Out.Empty(); + for(TActorIterator Itr(World); Itr; ++Itr) + { + Out.Add(*Itr); + } +} + +void UVictoryBPFunctionLibrary::VictoryISM_ConvertToVictoryISMActors( + UObject* WorldContextObject, + TSubclassOf ActorClass, + TArray& 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 > VictoryISMMap; + + //Note the ActorClass filter on the Actor Iterator! -Rama + for (TActorIterator Itr(World, ActorClass); Itr; ++Itr) + { + //Get Static Mesh Component! + UStaticMeshComponent* Comp = Itr->FindComponentByClass(); + 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 >::TIterator It(VictoryISMMap); It; ++It) + { + //Get the Actor Array for this particular Static Mesh Asset! + TArray& ActorArray = It.Value(); + + //No entries? + if(ActorArray.Num() < MinCountToCreateISM) continue; + //~~~~~~~~~~~~~~~~~~ + + //Get the Root + UStaticMeshComponent* RootSMC = ActorArray[0]->FindComponentByClass(); + if(!RootSMC) continue; + //~~~~~~~~~~ + + //Gather transforms! + TArray 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::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& FileNames) +{ + FileNames.Empty(); + FString Path = VictoryPaths__SavedDir() + "SaveGames"; + GetFiles(Path,FileNames); //see top of this file, my own file IO code - Rama +} + +void UVictoryBPFunctionLibrary::SaveGameObject_GetMostRecentSaveSlotFileName(FString& FileName, bool& bFound) +{ + FileName.Empty(); + bFound = false; + + const FString Path = VictoryPaths__SavedDir() + "SaveGames"; + + IFileManager& FileManager = IFileManager::Get(); + + TArray> FileTimeStamps; + + FString Str; + auto FilenamesVisitor = MakeDirectoryVisitor( + [&](const TCHAR* FilenameOrDirectory, bool bIsDirectory) + { + //Files + if (!bIsDirectory) + { + FString CleanFileName = FPaths::GetCleanFilename(FilenameOrDirectory); + + //Filter by Extension + if (FPaths::GetExtension(CleanFileName).ToLower() == "sav") + { + FDateTime LastModified = FileManager.GetTimeStamp(FilenameOrDirectory); + FileTimeStamps.Add(TTuple(LastModified, CleanFileName)); + } + } + return true; + } + ); + + FPlatformFileManager::Get().GetPlatformFile().IterateDirectory(*Path, FilenamesVisitor); + + if (FileTimeStamps.Num() > 0) + { + FileTimeStamps.Sort([](const TTuple& LeftHandSide, const TTuple& RightHandSide) { return LeftHandSide.Key > RightHandSide.Key; }); + + FileName = FileTimeStamps[0].Value; + + bFound = true; + } +} + +//~~~ 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& Bindings) +{ + Bindings.Empty(); + + const UInputSettings* Settings = GetDefault(); + if(!Settings) return; + + const TArray& Axi = Settings->GetAxisMappings(); + + for(const FInputAxisKeyMapping& Each : Axi) + { + Bindings.Add(FVictoryInputAxis(Each)); + } +} +void UVictoryBPFunctionLibrary::VictoryRemoveAxisKeyBind(FVictoryInputAxis ToRemove) +{ + //GetMutableDefault + UInputSettings* Settings = GetMutableDefault(); + if(!Settings) return; + + TArray& Axi = const_cast&>(Settings->GetAxisMappings()); + + 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 It; It; ++It) + { + It->ForceRebuildingKeyMaps(true); + } + } +} + +void UVictoryBPFunctionLibrary::VictoryGetAllActionKeyBindings(TArray& Bindings) +{ + Bindings.Empty(); + + const UInputSettings* Settings = GetDefault(); + if(!Settings) return; + + const TArray& Actions = Settings->GetActionMappings(); + + for(const FInputActionKeyMapping& Each : Actions) + { + Bindings.Add(FVictoryInput(Each)); + } +} + +void UVictoryBPFunctionLibrary::VictoryRemoveActionKeyBind(FVictoryInput ToRemove) +{ + //GetMutableDefault + UInputSettings* Settings = GetMutableDefault(); + if(!Settings) return; + + TArray& Actions = const_cast&>(Settings->GetActionMappings()); + + 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 It; It; ++It) + { + It->ForceRebuildingKeyMaps(true); + } + } +} + +void UVictoryBPFunctionLibrary::VictoryGetAllAxisAndActionMappingsForKey(FKey Key, TArray& ActionBindings, TArray& AxisBindings) +{ + ActionBindings.Empty(); + AxisBindings.Empty(); + + const UInputSettings* Settings = GetDefault(); + if(!Settings) return; + + const TArray& Actions = Settings->GetActionMappings(); + + for(const FInputActionKeyMapping& Each : Actions) + { + if(Each.Key == Key) + { + ActionBindings.Add(FVictoryInput(Each)); + } + } + + const TArray& Axi = Settings->GetAxisMappings(); + + for(const FInputAxisKeyMapping& Each : Axi) + { + if(Each.Key == Key) + { + AxisBindings.Add(FVictoryInputAxis(Each)); + } + } +} +bool UVictoryBPFunctionLibrary::VictoryReBindAxisKey(FVictoryInputAxis Original, FVictoryInputAxis NewBinding) +{ + UInputSettings* Settings = const_cast(GetDefault()); + if(!Settings) return false; + + TArray& Axi = const_cast&>(Settings->GetAxisMappings()); + + //~~~ + + 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(Settings)->SaveKeyMappings(); + + //REBUILDS INPUT, creates modified config in Saved/Config/Windows/Input.ini + for (TObjectIterator It; It; ++It) + { + It->ForceRebuildingKeyMaps(true); + } + } + return Found; +} + +bool UVictoryBPFunctionLibrary::VictoryReBindActionKey(FVictoryInput Original, FVictoryInput NewBinding) +{ + UInputSettings* Settings = const_cast(GetDefault()); + if(!Settings) return false; + + TArray& Actions = const_cast&>(Settings->GetActionMappings()); + + //~~~ + + 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(Settings)->SaveKeyMappings(); + + //REBUILDS INPUT, creates modified config in Saved/Config/Windows/Input.ini + for (TObjectIterator It; It; ++It) + { + It->ForceRebuildingKeyMaps(true); + } + } + return Found; +} + +void UVictoryBPFunctionLibrary::GetAllWidgetsOfClass(UObject* WorldContextObject, TSubclassOf WidgetClass, TArray& 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 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 WidgetClass) +{ + if(!WidgetClass) return; + if(!WorldContextObject) return; + + UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull); + if(!World) return; + //~~~~~~~~~~~ + + for(TObjectIterator 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 WidgetClass) +{ + if(!WidgetClass) return false; + if(!WorldContextObject) return false; + + UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull); + if(!World) return false; + //~~~~~~~~~~~ + + for(TObjectIterator 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 bSkipNotifyPlayers) +{ + if(!WorldContextObject) return; + + UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull); + if(!World) return; + //~~~~~~~~~~~ + + World->ServerTravel(MapName,false,bSkipNotifyPlayers); //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 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& IntArray, TArray& IntArrayRef) +{ + IntArray.Sort(); + IntArrayRef = IntArray; +} +void UVictoryBPFunctionLibrary::VictorySortFloatArray(UPARAM(ref) TArray& FloatArray, TArray& 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 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 ThePC; + if(!ThePC) return -1; + if(!ThePC->PlayerState) return -1; + //~~~~~~~~~~~~~~~~~~~ + + return ThePC->PlayerState->GetPlayerId(); +} +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(World,TheObjectClass); + */ +} +UPrimitiveComponent* UVictoryBPFunctionLibrary::CreatePrimitiveComponent( + UObject* WorldContextObject, + TSubclassOf 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(World, Name); + if(!NewComp) return NULL; + //~~~~~~~~~~~~~ + + NewComp->SetWorldLocation(Location); + NewComp->SetWorldRotation(Rotation); + NewComp->RegisterComponentWithWorld(World); + + return NewComp; +} + +AActor* UVictoryBPFunctionLibrary::SpawnActorIntoLevel(UObject* WorldContextObject, TSubclassOf 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->GetStreamingLevels()) + { + 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& 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->GetStreamingLevels()) + { + 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 ThePC; + if(!ThePC) return FVector2D::ZeroVector; + + ULocalPlayer* LocalPlayer = Cast(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& 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& StringArray, int32& ArraySize, FString FullFilePath, bool ExcludeEmptyLines) +{ + ArraySize = 0; + + if(FullFilePath == "" || FullFilePath == " ") return false; + + //Empty any previous contents! + StringArray.Empty(); + + TArray 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 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 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 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 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& SelectedActors, FVector2D AnchorPoint,FVector2D DraggedPoint,TSubclassOf 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 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(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->GetPlayerId(); + + 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 = false;//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& FloatArray, int32& IndexOfMaxValue, float& MaxValue) +{ + MaxValue = UVictoryBPFunctionLibrary::Max(FloatArray,&IndexOfMaxValue); +} + +void UVictoryBPFunctionLibrary::MaxOfIntArray(const TArray& IntArray, int32& IndexOfMaxValue, int32& MaxValue) +{ + MaxValue = UVictoryBPFunctionLibrary::Max(IntArray,&IndexOfMaxValue); +} + +void UVictoryBPFunctionLibrary::MinOfFloatArray(const TArray& FloatArray, int32& IndexOfMinValue, float& MinValue) +{ + MinValue = UVictoryBPFunctionLibrary::Min(FloatArray,&IndexOfMinValue); +} + +void UVictoryBPFunctionLibrary::MinOfIntArray(const TArray& 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& Widths, TArray& Heights, TArray& RefreshRates,bool IncludeRefreshRates) +{ + //Clear any Previous + Widths.Empty(); + Heights.Empty(); + RefreshRates.Empty(); + + TArray 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(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 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(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(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(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 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(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(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& 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 Itr(World); Itr; ++Itr ) + { + if (World->GetTimeSeconds() - Itr->GetLastRenderTime() <= MinRecentTime) + { + CurrentlyRenderedActors.Add( * Itr); + } + } +} +void UVictoryBPFunctionLibrary::Visibility__GetNotRenderedActors(UObject* WorldContextObject, TArray& 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 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 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, + bool AllowAppend +){ + 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; + } + } + + if (AllowAppend) + { + SaveText += "\n"; + return FFileHelper::SaveStringToFile(SaveText, * SaveDirectory, + FFileHelper::EEncodingOptions::AutoDetect,&IFileManager::Get(), EFileWrite::FILEWRITE_Append); + } + return FFileHelper::SaveStringToFile(SaveText, * SaveDirectory); +} +bool UVictoryBPFunctionLibrary::FileIO__SaveStringArrayToFile(FString SaveDirectory, FString JoyfulFileName, TArray SaveText, bool AllowOverWriting, bool AllowAppend) +{ + //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; + } + + if (AllowAppend) + { + FinalStr += "\n"; + return FFileHelper::SaveStringToFile(FinalStr, * SaveDirectory, + FFileHelper::EEncodingOptions::AutoDetect,&IFileManager::Get(), EFileWrite::FILEWRITE_Append); + } + + return FFileHelper::SaveStringToFile(FinalStr, * SaveDirectory); + +} +float UVictoryBPFunctionLibrary::Calcs__ClosestPointToSourcePoint(const FVector & Source, const TArray& 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& BoneLocations) +{ + ACharacter * Source = Cast(TheCharacter); + if (!Source) return false; + + if (!Source->GetMesh()) return false; + //~~~~~~~~~~~~~~~~~~~~~~~~~ + TArray 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(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(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 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 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.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(HitActor); + if (!AsCharacter) return HitActor; + + //Mesh + if (!AsCharacter->GetMesh()) return HitActor; + + //Component Trace + FHitResult Hit; + IsValid = AsCharacter->GetMesh()->K2_LineTraceComponent( + TraceStart, + TraceEnd, + true, + false, + 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.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(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, + false, + OutImpactPoint, + OutImpactNormal, + BoneName, + Hit + )) return HitActor; + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Socket Names + TArray 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(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(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(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(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(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(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(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 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(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(TheCharacter); + if (!AsCharacter) return false; + + //Mesh? + if (!AsCharacter->GetMesh()) return false; + + TArray 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(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(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 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 UVictoryBPFunctionLibrary::JoyGraphicsSettings__FullScreen_Get() +{ + return TEnumAsByte(JoyGraphics_FullScreen_GetFullScreenType()); +} + +void UVictoryBPFunctionLibrary::JoyGraphicsSettings__FullScreen_Set(TEnumAsByte 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 dis(0, 1); + return dis(rand_DRE); + } + /** Random Integer - Uniform distribution */ + int32 UVictoryBPFunctionLibrary::RandInt_MINMAX_uniDis(int32 iMin, int32 iMax) + { + std::uniform_int_distribution dis(iMin, iMax); + return dis(rand_DRE); + } + + /** Random Float - Zero to One Uniform distribution */ + float UVictoryBPFunctionLibrary::RandFloat_uniDis() + { + std::uniform_real_distribution 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 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 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 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 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 dis(iMin, iMax); + return dis(rand_MT); + } +//----------------------------------------------------------------------------------------------ENDRANDOM + + + +void UVictoryBPFunctionLibrary::String__ExplodeString(TArray& 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 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(FName("ImageWrapper")); + TSharedPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper(GetJoyImageFormat(ImageFormat)); + + //Load From File + TArray RawFileData; + if (!FFileHelper::LoadFileToArray(RawFileData, *FullFilePath)) return NULL; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + //Create T2D! + if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(RawFileData.GetData(), RawFileData.Num())) + { + TArray UncompressedBGRA; + 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& OutPixels) +{ + //Clear any previous data + OutPixels.Empty(); + + IsValid = false; + UTexture2D* LoadedT2D = NULL; + + IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked(FName("ImageWrapper")); + TSharedPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper(GetJoyImageFormat(ImageFormat)); + + //Load From File + TArray RawFileData; + if (!FFileHelper::LoadFileToArray(RawFileData, *FullFilePath)) return NULL; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + //Create T2D! + if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(RawFileData.GetData(), RawFileData.Num())) + { + TArray UncompressedRGBA ; + 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& 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& 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& 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 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 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(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; + } + + + //~~~ + if(T2D->CompressionSettings != TC_VectorDisplacementmap) + { + #if WITH_EDITOR + FMessageLog("PIE").Error(FText::Format(LOCTEXT("Victory_GetPixelFromT2D", "UVictoryBPFunctionLibrary::Victory_GetPixelFromT2D >> Texture Compression must be VectorDisplacementmap <3 Rama: {0}'"), FText::FromString(T2D->GetName()))); + #endif // WITH_EDITOR + 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; + + //Safety check! + if (X >= TextureWidth || Y >= TextureHeight) + { + #if WITH_EDITOR + FMessageLog("PIE").Error(FText::Format(LOCTEXT("Victory_GetPixelFromT2D", "UVictoryBPFunctionLibrary::Victory_GetPixelFromT2D >> X or Y is outside of texture bounds! <3 Rama: {0}'"), FText::FromString(FString::FromInt(TextureWidth) + " x " + FString::FromInt(TextureHeight) ))); + #endif // WITH_EDITOR + return false; + } + + FByteBulkData* RawImageData = &MipsMap.BulkData; + + if(!RawImageData) + { + return false; + } + + int32 TotalCount = RawImageData->GetElementCount(); + if(TotalCount < 1) + { + return false; + } + + uint8* RawByteArray = (uint8*)RawImageData->Lock(LOCK_READ_ONLY); + + //TC_VectorDisplacementmap UMETA(DisplayName="VectorDisplacementmap (RGBA8)"), + //! 4 because includes alpha <3 Rama + /* + for(int32 v = 0; v < TextureWidth * TextureHeight * RawImageData->GetElementSize() * 4; v++) + { + DebugString += FString::FromInt(RawByteArray[v]) + " "; + } + */ + + //Texture.cpp + /* + else if (FormatSettings.CompressionSettings == TC_VectorDisplacementmap) + { + TextureFormatName = NameBGRA8; + } + */ + + //Get!, converting FColor to FLinearColor + FColor ByteColor; + ByteColor.B = RawByteArray[Y * TextureWidth * 4 + (X * 4) ]; + ByteColor.G = RawByteArray[Y * TextureWidth * 4 + (X * 4) + 1]; + ByteColor.R = RawByteArray[Y * TextureWidth * 4 + (X * 4) + 2]; + ByteColor.A = RawByteArray[Y * TextureWidth * 4 + (X * 4) + 3]; + + //Set! + PixelColor = ByteColor.ReinterpretAsLinear(); + + RawImageData->Unlock(); + + return true; +} + + +bool UVictoryBPFunctionLibrary::Victory_GetPixelsArrayFromT2D(UTexture2D* T2D, int32& TextureWidth, int32& TextureHeight,TArray& PixelArray) +{ + + if(!T2D) + { + return false; + } + + if(T2D->CompressionSettings != TC_VectorDisplacementmap) + { + #if WITH_EDITOR + FMessageLog("PIE").Error(FText::Format(LOCTEXT("Victory_GetPixelFromT2D", "UVictoryBPFunctionLibrary::Victory_GetPixelFromT2D >> Texture Compression must be VectorDisplacementmap <3 Rama: {0}'"), FText::FromString(T2D->GetName()))); + #endif // WITH_EDITOR + 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; + } + + uint8* RawByteArray = (uint8*)RawImageData->Lock(LOCK_READ_ONLY); + + + for(int32 y = 0; y < TextureHeight; y++) + { + for(int32 x = 0; x < TextureWidth; x++) + { + FColor ByteColor; + ByteColor.B = RawByteArray[y * TextureWidth * 4 + (x * 4) ]; + ByteColor.G = RawByteArray[y * TextureWidth * 4 + (x * 4) + 1]; + ByteColor.R = RawByteArray[y * TextureWidth * 4 + (x * 4) + 2]; + ByteColor.A = RawByteArray[y * TextureWidth * 4 + (x * 4) + 3]; + + PixelArray.Add(ByteColor.ReinterpretAsLinear()); + } + } + + RawImageData->Unlock(); + return true; +} + +bool UVictoryBPFunctionLibrary::Victory_GetPixelsArrayFromT2DDynamic(UTexture2DDynamic* T2D, int32& TextureWidth, int32& TextureHeight,TArray& 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(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(); + */ +} + + +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::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* 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->SetSampleRate(info.SampleRate); + + return 0; +} + + +int32 UVictoryBPFunctionLibrary::findSource(class USoundWave* sw, class FSoundSource* out_audioSource) +{ + FAudioDevice* device = GEngine ? GEngine->GetMainAudioDeviceRaw() : 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 tmpActualSounds = device->GetActiveSounds(); + if (tmpActualSounds.Num()) + { + for (auto activeSoundIt(tmpActualSounds.CreateIterator()); activeSoundIt; ++activeSoundIt) + { + activeSound = *activeSoundIt; + for (auto WaveInstanceIt(activeSound->GetWaveInstances().CreateConstIterator()); 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& 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 FArrayProperty* 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 GetImageWrapperByExtention(const FString InImagePath) +{ + IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked(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 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 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 CompressedData; + if (!FFileHelper::LoadFileToArray(CompressedData, *ImagePath)) + { + return nullptr; + } + + TSharedPtr ImageWrapper = GetImageWrapperByExtention(ImagePath); + + if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(CompressedData.GetData(), CompressedData.Num())) + { + TArray UncompressedRGBA; + + 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 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 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 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(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(PossibleParent->GetOuter()); + if (WidgetTree) + { + NextPossibleParent = Cast(WidgetTree->GetOuter()); + } + } + + PossibleParent = NextPossibleParent; + } + } + + return ResultParent; +} + +void UVictoryBPFunctionLibrary::WidgetGetChildrenOfClass(UWidget* ParentWidget, TArray& ChildWidgets, TSubclassOf WidgetClass, bool bImmediateOnly) +{ + ChildWidgets.Empty(); + + if (ParentWidget && WidgetClass) + { + // Current set of widgets to check + TInlineComponentArray WidgetsToCheck; + + // Set of all widgets we have checked + TInlineComponentArray 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 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(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(Target); + } + return (TeamAgentInterface != nullptr) ? TeamAgentInterface->GetGenericTeamId() : FGenericTeamId::NoTeam; +} + +void UVictoryBPFunctionLibrary::SetGenericTeamId(AActor* Target, uint8 NewTeamId) +{ + if (Target) + { + IGenericTeamAgentInterface* TeamAgentInterface = Cast(Target); + if (TeamAgentInterface != nullptr) + { + TeamAgentInterface->SetGenericTeamId(NewTeamId); + } + } +} + +FLevelStreamInstanceInfo::FLevelStreamInstanceInfo(ULevelStreamingDynamic* LevelInstance) +{ + PackageName = LevelInstance->GetWorldAssetPackageFName(); + PackageNameToLoad = LevelInstance->PackageNameToLoad; + Location = LevelInstance->LevelTransform.GetLocation(); + Rotation = LevelInstance->LevelTransform.GetRotation().Rotator(); + bShouldBeLoaded = LevelInstance->HasLoadedLevel(); + bShouldBeVisible = LevelInstance->GetShouldBeVisibleFlag(); + bShouldBlockOnLoad = LevelInstance->bShouldBlockOnLoad; + LODIndex = LevelInstance->GetLevelLODIndex(); +}; + +FLevelStreamInstanceInfo UVictoryBPFunctionLibrary::GetLevelInstanceInfo(ULevelStreamingDynamic* 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->GetStreamingLevels()) + { + 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 + ULevelStreamingDynamic* StreamingLevel = NewObject(World, ULevelStreamingDynamic::StaticClass(), NAME_None, RF_Transient, nullptr); + StreamingLevel->SetWorldAssetByPackageName(PackageName); + StreamingLevel->LevelColor = FColor::MakeRandomColor(); + StreamingLevel->SetShouldBeLoaded(LevelInstanceInfo.bShouldBeLoaded); + StreamingLevel->SetShouldBeVisible(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->AddStreamingLevel(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->GetStreamingLevels()) + { + + 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->SetShouldBeLoaded(false); + StreamingLevel->SetShouldBeVisible(false); + // This removes the level from the streaming level list + StreamingLevel->SetIsRequestingUnloadAndRemoval(true); + // Force a refresh of the world + World->FlushLevelStreaming(EFlushLevelStreamingType::Full); + break; + } + } + } +} + +bool UVictoryBPFunctionLibrary::GenericArray_SortCompare(const FProperty* LeftProperty, void* LeftValuePtr, const FProperty* RightProperty, void* RightValuePtr) +{ + bool bResult = false; + + if (const FNumericProperty *LeftNumericProperty = Cast(LeftProperty)) + { + if (LeftNumericProperty->IsFloatingPoint()) + { + bResult = (LeftNumericProperty->GetFloatingPointPropertyValue(LeftValuePtr) < Cast(RightProperty)->GetFloatingPointPropertyValue(RightValuePtr)); + } + else if (LeftNumericProperty->IsInteger()) + { + bResult = (LeftNumericProperty->GetSignedIntPropertyValue(LeftValuePtr) < Cast(RightProperty)->GetSignedIntPropertyValue(RightValuePtr)); + } + } + else if (const FBoolProperty* LeftBoolProperty = Cast(LeftProperty)) + { + bResult = (!LeftBoolProperty->GetPropertyValue(LeftValuePtr) && Cast(RightProperty)->GetPropertyValue(RightValuePtr)); + } + else if (const FNameProperty* LeftNameProperty = Cast(LeftProperty)) + { + bResult = (LeftNameProperty->GetPropertyValue(LeftValuePtr).ToString() < Cast(RightProperty)->GetPropertyValue(RightValuePtr).ToString()); + } + else if (const FStrProperty* LeftStringProperty = Cast(LeftProperty)) + { + bResult = (LeftStringProperty->GetPropertyValue(LeftValuePtr) < Cast(RightProperty)->GetPropertyValue(RightValuePtr)); + } + else if (const FTextProperty* LeftTextProperty = Cast(LeftProperty)) + { + bResult = (LeftTextProperty->GetPropertyValue(LeftValuePtr).ToString() < Cast(RightProperty)->GetPropertyValue(RightValuePtr).ToString()); + } + + return bResult; +} + +void UVictoryBPFunctionLibrary::GenericArray_Sort(void* TargetArray, const FArrayProperty* ArrayProp, bool bAscendingOrder /* = true */, FName VariableName /* = NAME_None */) +{ + if (TargetArray) + { + FScriptArrayHelper ArrayHelper(ArrayProp, TargetArray); + const int32 LastIndex = ArrayHelper.Num(); + + if (const FObjectProperty* ObjectProperty = Cast(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)); + + FProperty* LeftProperty = FindField(LeftObject->GetClass(), VariableName); + FProperty* RightProperty = FindField(RightObject->GetClass(), VariableName); + + if (LeftProperty && RightProperty) + { + void* LeftValuePtr = LeftProperty->ContainerPtrToValuePtr(LeftObject); + void* RightValuePtr = RightProperty->ContainerPtrToValuePtr(RightObject); + + if (GenericArray_SortCompare(LeftProperty, LeftValuePtr, RightProperty, RightValuePtr) != bAscendingOrder) + { + ArrayHelper.SwapValues(j, j + 1); + } + } + } + } + } + else + { + FProperty* Property = nullptr; + + if (const FStructProperty* StructProperty = Cast(ArrayProp->Inner)) + { + Property = FindField(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(ArrayHelper.GetRawPtr(j)); + void* RightValuePtr = Property->ContainerPtrToValuePtr(ArrayHelper.GetRawPtr(j + 1)); + + if (GenericArray_SortCompare(Property, LeftValuePtr, Property, RightValuePtr) != bAscendingOrder) + { + ArrayHelper.SwapValues(j, j + 1); + } + } + } + } + } + } +} + +void UVictoryBPFunctionLibrary::Array_Sort(const TArray& 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(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& 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 diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPFunctionLibrary_WinOS.cpp b/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPFunctionLibrary_WinOS.cpp new file mode 100644 index 00000000..da090361 --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPFunctionLibrary_WinOS.cpp @@ -0,0 +1,65 @@ +/* + By Rama +*/ + +#include "VictoryBPLibraryPrivatePCH.h" +#include "VictoryBPFunctionLibrary.h" + +#if PLATFORM_WINDOWS +#include "Runtime/Core/Public/Windows/AllowWindowsPlatformTypes.h" +//#include "AdditionalWindowsHeaders.h" +#endif + +void UVictoryBPFunctionLibrary::FlashGameOnTaskBar(APlayerController* PC, bool FlashContinuous, int32 MaxFlashCount, int32 FlashFrequencyMilliseconds) +{ + #if PLATFORM_WINDOWS + if(!PC) return; + + //Local Player + ULocalPlayer* VictoryPlayer = Cast(PC->Player); + if(!VictoryPlayer) return; + + //Game Viewport Client + UGameViewportClient* GameViewport = Cast(VictoryPlayer->ViewportClient); + if(!GameViewport) return; + + //Slate Game Window + TSharedPtr< SWindow > GWSlate = GameViewport->GetWindow(); + if(!GWSlate.IsValid()) return; + + //Native OS Window + TSharedPtr GW = GWSlate->GetNativeWindow(); + if(!GW.IsValid()) return; + + //Windows + FLASHWINFO fi; + fi.cbSize = sizeof(FLASHWINFO); + fi.hwnd = (HWND)GW->GetOSWindowHandle(); + fi.dwFlags = FLASHW_ALL; + + //Continuous? <3 Rama + if(FlashContinuous) + { + fi.dwFlags |= FLASHW_TIMERNOFG; + fi.uCount = 0; + fi.dwTimeout = 0; + } + else + { + fi.uCount = MaxFlashCount; + fi.dwTimeout = FlashFrequencyMilliseconds; + } + + FlashWindowEx(&fi); + #endif + + //<3 Rama +} + + + + + +#if PLATFORM_WINDOWS +#include "Runtime/Core/Public/Windows/HideWindowsPlatformTypes.h" +#endif diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPHTML.cpp b/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPHTML.cpp new file mode 100644 index 00000000..675d15ae --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPHTML.cpp @@ -0,0 +1,58 @@ +/* + By Rama +*/ +#include "VictoryBPLibraryPrivatePCH.h" +#include "VictoryBPHTML.h" + + +//! Someone should please integrate the HTML5 plugin with this code + +/* +#if PLATFORM_HTML5 + #include "SDL_opengl.h" + + DEFINE_LOG_CATEGORY_STATIC(VictoryPluginHTML, Log, All); + + #include "emscripten.h" + #include "html5.h" +#endif +*/ + +/* +bool UVictoryBPHTML::IsHTML() +{ + + #if PLATFORM_HTML5 + return true; + #else + return false; + #endif + + return false; +} +*/ + +/* +void UVictoryBPHTML::VictoryHTML5_SetCursorVisible(bool MakeVisible) +{ + if(MakeVisible) + { + #if PLATFORM_HTML5 + { + emscripten_exit_pointerlock(); + UE_LOG(VictoryPluginHTML, Warning, TEXT("Exiting Pointer Lock")); + } + #endif + } + else + { + #if PLATFORM_HTML5 + { + emscripten_request_pointerlock ( "#canvas" , true); + UE_LOG(VictoryPluginHTML, Warning, TEXT("Entering Pointer Lock")); + } + #endif + } + +} +*/ \ No newline at end of file diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPLibrary.cpp b/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPLibrary.cpp new file mode 100644 index 00000000..329484a8 --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPLibrary.cpp @@ -0,0 +1,24 @@ +/* + By Rama +*/ +#include "VictoryBPLibraryPrivatePCH.h" + +#define LOCTEXT_NAMESPACE "FVictoryBPLibraryModule" + + +void FVictoryBPLibraryModule::StartupModule() +{ + // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module + +} + +void FVictoryBPLibraryModule::ShutdownModule() +{ + // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, + // we call this function before unloading the module. + +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FVictoryBPLibraryModule, VictoryBPLibrary) \ No newline at end of file diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPLibraryPrivatePCH.h b/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPLibraryPrivatePCH.h new file mode 100644 index 00000000..baef7e2d --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Private/VictoryBPLibraryPrivatePCH.h @@ -0,0 +1,4 @@ +/* + By Rama +*/ +#include "VictoryBPLibrary.h" \ No newline at end of file diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Public/TKMathFunctionLibrary.h b/Plugins/Victory/Source/VictoryBPLibrary/Public/TKMathFunctionLibrary.h new file mode 100644 index 00000000..76feae4d --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Public/TKMathFunctionLibrary.h @@ -0,0 +1,265 @@ +/* + By TK-Master +*/ +#pragma once + +//For the Anchor Conversion +#include "Runtime/UMG/Public/UMG.h" + +#include "TKMathFunctionLibrary.generated.h" + +/* Speed Units Enum. */ +UENUM() +enum ESpeedUnit +{ + /* Centimeter / second (cm/s). This is default unreal velocity unit. */ + CentimeterPerSecond, + + /* Foot / second (ft/s). */ + FootPerSecond, + + /* Meter / second (m/s). */ + MeterPerSecond, + + /* Meter / minute (m/min). */ + MeterPerMinute, + + /* Kilometer / second (km/s). */ + KilometerPerSecond, + + /* Kilometer / minute (km/min). */ + KilometerPerMinute, + + /*Kilometer / hour (km/h). */ + KilometerPerHour, + + /* Mile / hour (mph). */ + MilePerHour, + + /* Knot (kn). Nautical mile per hour. */ + Knot, + + /* Mach (speed of sound) (M) at standard atm. */ + Mach, + + /* Speed of light. */ + SpeedOfLight, + + /* Yard / second. */ + YardPerSecond +}; + + +UCLASS() +class VICTORYBPLIBRARY_API UTKMathFunctionLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Console") + static float GetConsoleVariableFloat(FString VariableName); + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Console") + static int32 GetConsoleVariableInt(FString VariableName); + + //Reverses the sign (- or +) of a float. + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Float") + static float NegateFloat(float A); + + //Reverses the sign (- or +) of an integer. + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Integer") + static int32 NegateInt(int32 A); + + //Reverses the sign (- or +) of a Vector2D. + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector2D") + static FVector2D NegateVector2D(FVector2D A); + + //Changes the size (length) of a Vector to the given size (normalized vector * size). + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector") + static FVector SetVectorLength(FVector A, float size); + + //Converts radians to degrees. + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector") + static FVector VectorRadiansToDegrees(FVector RadVector); + + //Converts degrees to radians. + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector") + static FVector VectorDegreesToRadians(FVector DegVector); + + /** + * Rounds an integer to the lower multiple of the given number. + * If Skip Self is set to True it will skip to the previous multiple if the integer rounds to itself. + * @param Multiple - The multiple number to round to. + * @param skipSelf - Skip to the previous multiple if the integer rounds to itself. + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Integer") + static int32 RoundToLowerMultiple(int32 A, int32 Multiple = 32, bool skipSelf = false); + + /** + * Rounds an integer to the upper multiple of the given number. + * If Skip Self is set to True it will skip to the next multiple if the integer rounds to itself. + * @param Multiple - The multiple number to round to. + * @param skipSelf - Skip to the next multiple if the integer rounds to itself. + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Integer") + static int32 RoundToUpperMultiple(int32 A, int32 Multiple = 32, bool skipSelf = false); + + /** Rounds an integer to the nearest multiple of the given number. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Integer") + static int32 RoundToNearestMultiple(int32 A, int32 Multiple = 32); + + /** Returns true if the integer is a power of two number. */ + UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "PwrOf2"), Category = "Victory BP Library|TK-Master Math|Integer") + static bool IsPowerOfTwo(int32 x); + + /** Returns true if the integer is a multiple of the given number. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Integer") + static bool IsMultipleOf(int32 A, int32 Multiple); + + /** Returns true if the number is even (false if it's odd). */ + UFUNCTION(BlueprintPure, meta = (CompactNodeTitle = "isEven"), Category = "Victory BP Library|TK-Master Math|Float") + static bool IsEvenNumber(float A); + + /** + * Find closest point on a Sphere to a Line. + * When line intersects Sphere, then closest point to LineOrigin is returned. + * @param SphereOrigin Origin of Sphere + * @param SphereRadius Radius of Sphere + * @param LineOrigin Origin of line + * @param LineDir Direction of line. + * @return Closest point on sphere to given line. + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector") + static FVector ClosestPointOnSphereToLine(FVector SphereOrigin, float SphereRadius, FVector LineOrigin, FVector LineDir); + + /** Find the point on line segment from LineStart to LineEnd which is closest to Point. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector") + static FVector ClosestPointOnLineSeqment(FVector Point, FVector LineStart, FVector LineEnd); + + /** Returns true if the given Point vector is within a box (defined by BoxOrigin and BoxExtent). */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector|Intersection") + static bool IsPointInsideBox(FVector Point, FVector BoxOrigin, FVector BoxExtent); + + /** Determines whether a line intersects a sphere. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector|Intersection") + static bool IsLineInsideSphere(FVector LineStart, FVector LineDir, float LineLength, FVector SphereOrigin, float SphereRadius); + + /** + * Swept-Box vs Box test. + * Sweps a box defined by Extend from Start to End points and returns whether it hit a box or not plus the hit location and hit normal if successful. + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector|Intersection") + static bool LineExtentBoxIntersection(FBox inBox, FVector Start, FVector End, FVector Extent, FVector& HitLocation, FVector& HitNormal, float& HitTime); + + /** + * Get the shortest distance between a point and a plane. + * The output is signed so it holds information as to which side of the plane normal the point is. + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector") + static float SignedDistancePlanePoint(FVector planeNormal, FVector planePoint, FVector point); + + /** + * Returns a vector point which is a projection from a point to a line (defined by the vector couple LineOrigin, LineDirection). + * The line is infinite (in both directions). + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector") + static FVector ProjectPointOnLine(FVector LineOrigin, FVector LineDirection, FVector Point); + + /** + * Performs a sphere vs box intersection test. + * @param SphereOrigin the center of the sphere being tested against the box. + * @param SphereRadius the size of the sphere being tested. + * @param BoxOrigin the box origin being tested against. + * @param BoxExtent the box extend (width, depth, height). + * @return Whether the sphere/box intersect or not. + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector|Intersection") + static bool SphereBoxIntersection(FVector SphereOrigin, float SphereRadius, FVector BoxOrigin, FVector BoxExtent); + + /** + * Find closest points between 2 line segments. + * @param (Line1Start, Line1End) defines the first line segment. + * @param (Line2Start, Line2End) defines the second line segment. + * @param LinePoint1 Closest point on segment 1 to segment 2. + * @param LinePoint2 Closest point on segment 2 to segment 1. + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector|Intersection") + static void ClosestPointsOfLineSegments(FVector Line1Start, FVector Line1End, FVector Line2Start, FVector Line2End, FVector& LinePoint1, FVector& LinePoint2); + + /** + * Calculate the intersection point of two infinitely long lines. Returns true if lines intersect, otherwise false. + * Note that in 3d, two lines do not intersect most of the time. + * So if the two lines are not in the same plane, use Closest Points On Two Lines instead. + * @param IntersectionPoint The intersection point of the lines. Returns zero if the lines do not intersect or the operation fails. + * @param LinePoint1 Line point of the first line. + * @param LineDir1 Line direction (normal) of the first line. Should be a normalized vector. + * @param LinePoint2 Line point of the second line. + * @param LineDir2 Line direction (normal) of the second line. Should be a normalized vector. + * @return true if lines intersect, otherwise false. + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector|Intersection") + static bool LineToLineIntersection(FVector& IntersectionPoint, FVector LinePoint1, FVector LineDir1, FVector LinePoint2, FVector LineDir2); + + /* + * Calculate the closest points between two infinitely long lines. + * If lines are intersecting (not parallel) it will return false! Use Line To Line Intersection instead. + * @param closestPointLine1 The closest point of line1 to line2. Returns zero if the lines intersect. + * @param closestPointLine2 The closest point of line2 to line1. Returns zero if the lines intersect. + * @param linePoint1 Line point of the first line. + * @param lineVec1 Line direction (normal) of the first line. Should be a normalized vector. + * @param linePoint2 Line point of the second line. + * @param lineVec2 Line direction (normal) of the second line. Should be a normalized vector. + * @return true if lines are parallel, false otherwise. + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector") + static bool ClosestPointsOnTwoLines(FVector& closestPointLine1, FVector& closestPointLine2, FVector linePoint1, FVector lineVec1, FVector linePoint2, FVector lineVec2); + + /* + * Returns 0 if point is on the line segment. + * Returns 1 if point is not on the line segment and it is on the side of linePoint1. + * Returns 2 if point is not on the line segment and it is on the side of linePoint2. + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector") + static int32 PointOnWhichSideOfLineSegment(FVector linePoint1, FVector linePoint2, FVector point); + + /* + * Returns true if the two line segments are intersecting and not parallel. + * If you need the intersection point, use Closest Points On Two Lines. + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector|Intersection") + static bool AreLineSegmentsCrossing(FVector pointA1, FVector pointA2, FVector pointB1, FVector pointB2); + + /*Snaps vector to nearest grid multiple.*/ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector") + static FVector GridSnap(FVector A, float Grid); + + /*Converts UMG layout offsets to another anchor.*/ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Anchor", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static void ConvertAnchorToAnchor(UObject* WorldContextObject, FAnchors CurrentAnchor, FMargin Offsets, FAnchors TargetAnchor, FMargin& ConvertedOffsets); + + /*Converts Physics Linear Velocity to a more useful speed unit.*/ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|TK-Master Math|Vector") + static float ConvertPhysicsLinearVelocity(FVector Velocity, TEnumAsByte SpeedUnit); + + //------------------------------------------------------------ + //Physics functions! (why aren't these exposed by Epic yet?!) + + /** + * Get the current world velocity of a point on a physics-enabled component. + * @param Point - Point in world space. + * @param DrawDebugInfo - Draw debug point & string. + * @param BoneName - If a SkeletalMeshComponent, name of body to get velocity of. 'None' indicates root body. + * @return The velocity of the point in world space. + */ + UFUNCTION(BlueprintCallable, Category = "Physics") + static FVector GetVelocityAtPoint(UPrimitiveComponent* Target, FVector Point, FName BoneName = NAME_None, bool DrawDebugInfo = false); + + /* + * Set the physx center of mass offset. + * Note: this offsets the physx-calculated center of mass (it is not an offset from the pivot point). + */ + UFUNCTION(BlueprintCallable, Category = "Physics") + static void SetCenterOfMassOffset(UPrimitiveComponent* Target, FVector Offset, FName BoneName = NAME_None); + +}; diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryBPFunctionLibrary.h b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryBPFunctionLibrary.h new file mode 100644 index 00000000..39035528 --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryBPFunctionLibrary.h @@ -0,0 +1,1987 @@ +/* + + By Rama + +*/ +#pragma once + +//to prevent nodes from getting called in constructors: +//meta=(UnsafeDuringActorConstruction = "true") + +#include "VictoryISM.h" + +//~~~~~~~~~~~~ UMG ~~~~~~~~~~~~~~~ +#include "Runtime/UMG/Public/UMG.h" +#include "Runtime/UMG/Public/UMGStyle.h" +#include "Runtime/UMG/Public/Slate/SObjectWidget.h" +#include "Runtime/UMG/Public/IUMGModule.h" +#include "Runtime/UMG/Public/Blueprint/UserWidget.h" +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +//AI +#include "AIController.h" //MoveToWithFilter + +//Audio +#include "Components/AudioComponent.h" +#include "AudioDecompress.h" +#include "AudioDevice.h" +#include "ActiveSound.h" +#include "Audio.h" +#include "Developer/TargetPlatform/Public/Interfaces/IAudioFormat.h" +#include "VorbisAudioInfo.h" + +#include "Runtime/Engine/Classes/Engine/LevelStreamingDynamic.h" + +//Texture2D +//#include "Engine/Texture2D.h" +#include "DDSLoader.h" + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#include "VictoryBPFunctionLibrary.generated.h" + +// BP Library for You +// +// Written by Rama + +//note about UBlueprintFunctionLibrary +// This class is a base class for any function libraries exposed to blueprints. +// Methods in subclasses are expected to be static, and no methods should be added to the base class. + + +//~~~~~~~~~~~~~~~~~~~~~~ +// Key Modifiers +//~~~~~~~~~~~~~~~~~~~~~~ +UENUM(BlueprintType) +enum class EJoyImageFormats : uint8 +{ + JPG UMETA(DisplayName="JPG "), + PNG UMETA(DisplayName="PNG "), + BMP UMETA(DisplayName="BMP "), + ICO UMETA(DisplayName="ICO "), + EXR UMETA(DisplayName="EXR "), + ICNS UMETA(DisplayName="ICNS ") +}; + +//! REMOVE THIS AFTER A FEW VERSIONS +//! +//! +UENUM(BlueprintType) +enum class EVictoryHMDDevice : uint8 +{ + None UMETA(DisplayName="None"), + OculusRift UMETA(DisplayName="Oculus Rift"), + Morpheus UMETA(DisplayName="Morpheus"), + ES2GenericStereoMesh UMETA(DisplayName="ES2 Generic Stereo Mesh"), + SteamVR UMETA(DisplayName="Vive (Steam VR)"), + GearVR UMETA(DisplayName="Gear VR") +}; + +USTRUCT(BlueprintType) +struct FVictoryInput +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input Song") + FString ActionName; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input Song") + FKey Key; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input Song") + FString KeyAsString; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input Song") + uint32 bShift:1; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input Song") + uint32 bCtrl:1; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input Song") + uint32 bAlt:1; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input Song") + uint32 bCmd:1; + + + FVictoryInput(){} + FVictoryInput(const FString InActionName, const FKey InKey, const bool bInShift, const bool bInCtrl, const bool bInAlt, const bool bInCmd) + : Key(InKey) + , KeyAsString(InKey.GetDisplayName().ToString()) + , bShift(bInShift) + , bCtrl(bInCtrl) + , bAlt(bInAlt) + , bCmd(bInCmd) + { + ActionName = InActionName; + } + + FVictoryInput(const FInputActionKeyMapping& Action) + : Key(Action.Key) + , KeyAsString(Action.Key.GetDisplayName().ToString()) + , bShift(Action.bShift) + , bCtrl(Action.bCtrl) + , bAlt(Action.bAlt) + , bCmd(Action.bCmd) + { + ActionName = Action.ActionName.ToString(); + } +}; + +USTRUCT(BlueprintType) +struct FVictoryInputAxis +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input Song") + FString AxisName = ""; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input Song") + FString KeyAsString = ""; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input Song") + FKey Key; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input Song") + float Scale = 1; + + FVictoryInputAxis(){} + FVictoryInputAxis(const FString InAxisName, FKey InKey, float InScale) + : AxisName(InAxisName) + , KeyAsString(InKey.GetDisplayName().ToString()) + , Key(InKey) + , Scale(InScale) + { } + + FVictoryInputAxis(const FInputAxisKeyMapping& Axis) + : KeyAsString(Axis.Key.GetDisplayName().ToString()) + , Key(Axis.Key) + , Scale(Axis.Scale) + { + AxisName = Axis.AxisName.ToString(); + } +}; + +UENUM(BlueprintType) +namespace EJoyGraphicsFullScreen +{ + //256 entries max + enum Type + { + FullScreen UMETA(DisplayName="Regular Full Screen"), + WindowedFullScreen UMETA(DisplayName="Windowed Full Screen High Quality"), + WindowedFullScreenPerformance UMETA(DisplayName="Windowed Full Screen (Default)"), + //~~~ + + //256th entry + EJoyGraphicsFullScreen_Max UMETA(Hidden), + }; +} + +USTRUCT(BlueprintType) +struct FLevelStreamInstanceInfo +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY(Category = "LevelStreaming", BlueprintReadWrite) + FName PackageName; + + UPROPERTY(Category = "LevelStreaming", BlueprintReadWrite) + FName PackageNameToLoad; + + UPROPERTY(Category = "LevelStreaming", BlueprintReadWrite) + FVector Location; + + UPROPERTY(Category = "LevelStreaming", BlueprintReadWrite) + FRotator Rotation; + + UPROPERTY(Category = "LevelStreaming", BlueprintReadWrite) + uint8 bShouldBeLoaded:1; + + UPROPERTY(Category = "LevelStreaming", BlueprintReadWrite) + uint8 bShouldBeVisible:1; + + UPROPERTY(Category = "LevelStreaming", BlueprintReadWrite) + uint8 bShouldBlockOnLoad:1; + + UPROPERTY(Category = "LevelStreaming", BlueprintReadWrite) + int32 LODIndex; + + FLevelStreamInstanceInfo() {} + + FLevelStreamInstanceInfo(ULevelStreamingDynamic* LevelInstance); + + FString ToString() const + { + return FString::Printf(TEXT("PackageName: %s\nPackageNameToLoad:%s\nLocation:%s\nRotation:%s\nbShouldBeLoaded:%s\nbShouldBeVisible:%s\nbShouldBlockOnLoad:%s\nLODIndex:%i") + , *PackageName.ToString() + , *PackageNameToLoad.ToString() + , *Location.ToString() + , *Rotation.ToString() + , (bShouldBeLoaded) ? TEXT("True") : TEXT("False") + , (bShouldBeVisible) ? TEXT("True") : TEXT("False") + , (bShouldBlockOnLoad) ? TEXT("True") : TEXT("False") + , LODIndex); + } +}; + + +UCLASS() +class VICTORYBPLIBRARY_API UVictoryBPFunctionLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_UCLASS_BODY() + + //~~~~~~~~~~~~~~~~~~ + // Level Generation + //~~~~~~~~~~~~~~~~~~ + /** Load a level to a specific location and rotation, can create multiple of the same level! + * + * Ensure that each InstanceNumber is unique to spawn multiple instances of the same level! + * + * <3 Rama + * + * @param MapFolderOffOfContent - Maps or Maps/TileSets/TileSet1 etc + * @param LevelName - Just the level name itself, such as Tile1 + * @param InstanceNumber - Ensure this is unique by keeping count to spawn as many instances of same level as you want! + * @param Location - Worldspace location where the level should be spawned + * @param Rotation - Worldspace rotation for rotating the entire level + * @return false if the level name was not found + */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Dynamic Level Generation",meta=(DeprecatedFunction, DeprecationMessage="My LoadLevelInstance BP node is in the main UE4 Engine as of 4.13! This version is deprecated and will be removed in the near future. <3 -Rama",WorldContext="WorldContextObject")) + static ULevelStreaming* VictoryLoadLevelInstance(UObject* WorldContextObject, FString MapFolderOffOfContent, FString LevelName, int32 InstanceNumber, FVector Location, FRotator Rotation,bool& Success); + + //~~~~~~~~~~ + // AI + //~~~~~~~~~~ + /** Move to Location with optional Query Filter! + * + * 1. Create Custon Nav Area Classes. + * + * 2. Use Nav Modifier Volumes to apply custom area class data within the level, then + * + * 3. Create Query Filters which alter/exclude those custom nav areas. + * + * 4. Can then choose to use the filters per character or even per Move To using this node. + * + * <3 Rama + * + * @param FilterClass - Allows different types of units to path in different ways all the time, or path differently per Move To using this node! + * @param bProjectDestinationToNavigation - Whether to attempt to find a nearby point on the nav mesh below/above/close to the supplied point. Uses the Agent's Nav Extent for the projection + * @param bStopOnOverlap - Add pawn's radius to AcceptanceRadius + * @param bCanStrafe - Set focus related flag: bAllowStrafe + * @return Whether the Pawn's AI Controller is valid and goal can be pathed to + */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|AI") + static EPathFollowingRequestResult::Type Victory_AI_MoveToWithFilter( + APawn* Pawn, + const FVector& Dest, + TSubclassOf FilterClass = NULL, + float AcceptanceRadius = 0, + bool bProjectDestinationToNavigation = false, + bool bStopOnOverlap = false, + bool bCanStrafe = false + ); + + //~~~~~~~~~~~~~~~~ + // GPU <3 Rama + //~~~~~~~~~~~~~~~~ + + UFUNCTION(BlueprintPure,Category="Victory BP Library|GPU") + static FString Victory_GetGPUBrand() + { + return FPlatformMisc::GetPrimaryGPUBrand(); + } + UFUNCTION(BlueprintPure,Category="Victory BP Library|GPU", meta=(Keywords="GPU")) + static FString Victory_GetGRHIAdapterName() + { + return GRHIAdapterName; + } + + UFUNCTION(BlueprintPure,Category="Victory BP Library|GPU") + static void Victory_GetGPUInfo(FString& DeviceDescription, FString& Provider, FString& DriverVersion, FString& DriverDate); + + //~~~~~~~~~~ + // Core + //~~~~~~~~~~ + + /** + Launch a new process, if it is not set to be detached, UE4 will not fully close until the other process completes. + + The new process id is returned! + + Priority options: -2 idle, -1 low, 0 normal, 1 high, 2 higher + + ♥ Rama + */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|System") + static void VictoryCreateProc(int32& ProcessId, FString FullPathOfProgramToRun,TArray CommandlineArgs,bool Detach,bool Hidden, int32 Priority=0, FString OptionalWorkingDirectory=""); + + /** You can obtain ProcessID from processes you initiate via VictoryCreateProc */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|System") + static FString VictoryGetApplicationName(int32 ProcessId) + { + //Please note it should really be uint32 but that is not supported by BP yet + return FPlatformProcess::GetApplicationName(ProcessId); + } + + /** You can obtain ProcessID from processes you initiate via VictoryCreateProc */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|System") + static bool VictoryIsApplicationRunning( int32 ProcessId ) + { + //Please note it should really be uint32 but that is not supported by BP yet + return FPlatformProcess::IsApplicationRunning(ProcessId); + } + /* Blueprints does not support int64 so at some pt in future int32 will not be enough, probably by then dolphins will rule the world, or UE4 BP will support int64, or both! <3 Rama*/ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|System") + static int32 GetUnixTimeStamp(const FDateTime& UTCTime) + { + //Please note it should really be int64 but that is not supported by BP yet + return UTCTime.ToUnixTimestamp(); + } + /* Blueprints does not support int64 so at some pt in future int32 will not be enough, probably by then dolphins will rule the world, or UE4 BP will support int64, or both! <3 Rama*/ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|System") + static void GetUTCFromUnixTimeStamp(int32 UnixTimeStamp, FDateTime& UTCTime) + { + //Please note it should really be int64 but that is not supported by BP yet + UTCTime = FDateTime::FromUnixTimestamp( UnixTimeStamp ); + } + + UFUNCTION(BlueprintPure, Category = "Rama Save System|File IO") + static void UTCToLocal(const FDateTime& UTCTime, FDateTime& LocalTime) + { + //Turn UTC into local ♥ Rama + FTimespan UTCOffset = FDateTime::Now() - FDateTime::UtcNow(); + LocalTime = UTCTime; + LocalTime += UTCOffset; + //♥ Rama + } + + /** Game thread may pause while hashing is ocurring. Please note that hashing multi-gb size files is very very slow, smaller files will process much faster :) <3 Rama*/ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|MD5") + static bool CreateMD5Hash(FString FileToHash, FString FileToStoreHashTo ); + + /** Game thread may pause while hashing is ocurring. Please note that hashing multi-gb size files is very very slow, smaller files will process much faster :) <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|MD5") + static bool CompareMD5Hash(FString MD5HashFile1, FString MD5HashFile2 ); + + /** Dynamically change how frequently in seconds a component will tick! Can be altered at any point during game-time! ♥ Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|System") + static void SetComponentTickRate(UActorComponent* Component, float Seconds) + { + if(!Component) return; + Component->PrimaryComponentTick.TickInterval = Seconds; + } + + /** Retrieves command line arguments that were passed into unreal */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|System") + static const FString GetCommandLine() + { + return FCommandLine::Get(); + } + + /** + * Create a new Texture Render Target 2D, ideal for use with Scene Capture Components created during runtime that need their own unique Render Targets + * @param Width Texture Width + * @param Height Texture Height + * @param ClearColor The color the texture is cleared to + * @param Gamma Will override FTextureRenderTarget2DResource::GetDisplayGamma if > 0. + * @return A new Texture Render Target 2D! + * + */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Misc") + static UTextureRenderTarget2D* CreateTextureRenderTarget2D(int32 Width=256, int32 Height=256, FLinearColor ClearColor = FLinearColor::White, float Gamma = 1) + { + UTextureRenderTarget2D* NewRenderTarget2D = NewObject(); + if(!NewRenderTarget2D) + { + return nullptr; + } + NewRenderTarget2D->ClearColor = ClearColor; + NewRenderTarget2D->TargetGamma = Gamma; + NewRenderTarget2D->InitAutoFormat(Width, Height); + return NewRenderTarget2D; + } + + //~~~~~~~~~~ + // Physics + //~~~~~~~~~~ + + /** Update the Angular Damping during runtime! Make sure the component is simulating physics before calling this! Returns false if the new value could not be set. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Physics") + static bool VictoryPhysics_UpdateAngularDamping(UPrimitiveComponent* CompToUpdate, float NewAngularDamping); + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Physics", meta=(Keywords="Closest Surface")) + static float GetDistanceToCollision(UPrimitiveComponent* CollisionComponent, const FVector& Point, FVector& ClosestPointOnCollision); + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Physics", meta=(Keywords="Closest Surface")) + static float GetDistanceBetweenComponentSurfaces(UPrimitiveComponent* CollisionComponent1, UPrimitiveComponent* CollisionComponent2, FVector& PointOnSurface1, FVector& PointOnSurface2); + + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Physics", meta=(Keywords="APEX Piece fracture damage PhysX Physics")) + static bool VictoryDestructible_DestroyChunk(UDestructibleComponent* DestructibleComp, int32 HitItem); + + + //~~~~~~~~~~ + // Joy ISM + //~~~~~~~~~~ + + /** Retrieve an array of all of the Victory Instanced Static Mesh Actors that have been created during runtime! */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Instanced Static Mesh",meta=(WorldContext="WorldContextObject")) + static void VictoryISM_GetAllVictoryISMActors(UObject* WorldContextObject, TArray& Out); + + /** Finds all instances of a specified Blueprint or class, and all subclasses of this class, and converts them into a single Instanced Static Mesh Actor! Returns the created Victory ISM actors. Please note all actors of subclasses are found as well, so use a very specific blueprint / class if you only want to generate Victory ISM actors for specific classes! Ignores actor classes that dont have a static mesh component. Please note that instanced static mesh actors can only be created for actors sharing the same static mesh asset. Different Instanced Static Mesh Actors are created for each unique static mesh asset found in the whole group of actors! */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Instanced Static Mesh",meta=(WorldContext="WorldContextObject")) + static void VictoryISM_ConvertToVictoryISMActors(UObject* WorldContextObject, TSubclassOf ActorClass, TArray& CreatedISMActors, bool DestroyOriginalActors=true, int32 MinCountToCreateISM=2); + + //~~~~~~~~~~ + // File I/O + //~~~~~~~~~~ + + /** Obtain all files in a provided directory, with optional extension filter. All files are returned if Ext is left blank. Returns false if operation could not occur. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|File IO") + static bool JoyFileIO_GetFiles(TArray& Files, FString RootFolderFullPath, FString Ext); + + /** Obtain all files in a provided root directory, including all subdirectories, with optional extension filter. All files are returned if Ext is left blank. The full file path is returned because the file could be in any subdirectory. Returns false if operation could not occur. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|File IO") + static bool JoyFileIO_GetFilesInRootAndAllSubFolders(TArray& Files, FString RootFolderFullPath, FString Ext); + + /** Obtain a listing of all SaveGame file names that were saved using the Blueprint Save Game system. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|File IO") + static void SaveGameObject_GetAllSaveSlotFileNames(TArray& FileNames); + + /** Obtain the last SaveGame file that was saved using the Blueprint Save Game system. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|File IO") + static void SaveGameObject_GetMostRecentSaveSlotFileName(FString& FileName, bool& bFound); + + /** Returns false if the new file could not be created. The folder path must be absolute, such as C:\Users\Self\Documents\YourProject\MyPics. You can use my other Paths nodes to easily get absolute paths related to your project! <3 Rama */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Screenshots", meta=(Keywords="High resolution")) + static bool ScreenShots_Rename_Move_Most_Recent(FString& OriginalFileName, FString NewName, FString NewAbsoluteFolderPath, bool HighResolution=true); + + //~~~~ Key Re Binding ! ~~~~ + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Key Rebinding") + static void VictoryGetAllAxisAndActionMappingsForKey(FKey Key, TArray& ActionBindings, TArray& AxisBindings); + + // Axis Mapping + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Key Rebinding") + static FVictoryInputAxis VictoryGetVictoryInputAxis(const FKeyEvent& KeyEvent); + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Key Rebinding") + static void VictoryGetAllAxisKeyBindings(TArray& Bindings); + + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Key Rebinding") + static void VictoryRemoveAxisKeyBind(FVictoryInputAxis ToRemove); + + /** You can leave the AsString field blank :) Returns false if the key could not be found as an existing mapping! Enjoy! <3 Rama */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Key Rebinding") + static bool VictoryReBindAxisKey(FVictoryInputAxis Original, FVictoryInputAxis NewBinding); + + static FORCEINLINE void UpdateAxisMapping(FInputAxisKeyMapping& Destination, const FVictoryInputAxis& VictoryInputBind) + { + Destination.Key = VictoryInputBind.Key; + Destination.Scale = VictoryInputBind.Scale; + } + + + // Action Mapping + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Key Rebinding") + static FVictoryInput VictoryGetVictoryInput(const FKeyEvent& KeyEvent); + + static FORCEINLINE void UpdateActionMapping(FInputActionKeyMapping& Destination, const FVictoryInput& VictoryInputBind) + { + Destination.Key = VictoryInputBind.Key; + Destination.bShift = VictoryInputBind.bShift; + Destination.bCtrl = VictoryInputBind.bCtrl; + Destination.bAlt = VictoryInputBind.bAlt; + Destination.bCmd = VictoryInputBind.bCmd; + } + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Key Rebinding") + static void VictoryGetAllActionKeyBindings(TArray& Bindings); + + /** You can leave the AsString field blank :) Returns false if the key could not be found as an existing mapping! Enjoy! <3 Rama */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Key Rebinding") + static bool VictoryReBindActionKey(FVictoryInput Original, FVictoryInput NewBinding); + + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Key Rebinding") + static void VictoryRemoveActionKeyBind(FVictoryInput ToRemove); + + //~~~~~~~~~~~~~~~~~~~~ + + /** Change volume of Sound class of your choosing, sets the volume instantly! Returns false if the sound class was not found and volume was not set. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Sound") + static bool VictorySoundVolumeChange(USoundClass* SoundClassObject, float NewVolume); + + /** Get Current Sound Volume! Returns -1 if sound class was not found*/ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Sound") + static float VictoryGetSoundVolume(USoundClass* SoundClassObject); + + //~~~~~~~~~~~~~~~~~~~~ + + /** The number of seconds that this actor has been in play, relative to Get Game Time In Seconds. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Actor") + static float GetTimeInPlay(AActor* Actor) + { + if(!Actor) return -1; + + UWorld* World = Actor->GetWorld(); + + //Use FApp Current Time as a back up + float CurrentTime = (World) ? World->GetTimeSeconds() : FApp::GetCurrentTime(); + return CurrentTime - Actor->CreationTime; + } + + /** + * Creates a plane centered on a world space point with a facing direction of Normal. + * + * @param Center The world space point the plane should be centered on (easy to observe with DrawDebugPlane) + * @param Normal The facing direction of the plane (can receive a Rotator) + * @return Plane coordinates + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Math|Plane", meta=(Keywords="make base plane")) + static FPlane CreatePlane(FVector Center, FVector Normal) + { + return FPlane(Center,Normal); + } + + /** >0: point is in front of the plane, <0: behind, =0: on the plane **/ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Math|Plane") + static void PointDistanceToPlane(const FPlane& Plane, FVector Point,float& Distance) + { + Distance = Plane.PlaneDot(Point); + } + + /** Use a larger tolerance to allow inaccuracy of measurement in certain situations */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Math|Plane") + static bool IsPointOnPlane(const FPlane& Plane, FVector Point, float Tolerance= 0.01) + { + return FMath::Abs(Plane.PlaneDot(Point)) < Tolerance; + } + + /** Easily add to an integer! <3 Rama*/ + UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "+=",Keywords = "increment integer"), Category = "Victory BP Library|Math|Integer") + static void VictoryIntPlusEquals(UPARAM(ref) int32& Int, int32 Add, int32& IntOut); + + /** Easily subtract from an integer! <3 Rama*/ + UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "-=",Keywords = "decrement integer"), Category = "Victory BP Library|Math|Integer") + static void VictoryIntMinusEquals(UPARAM(ref) int32& Int, int32 Sub, int32& IntOut); + + /** Easily add to a float! <3 Rama*/ + UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "+=",Keywords = "increment float"), Category = "Victory BP Library|Math|Float") + static void VictoryFloatPlusEquals(UPARAM(ref) float& Float, float Add, float& FloatOut); + + /** Easily subtract from a float! <3 Rama*/ + UFUNCTION(BlueprintCallable, meta = (CompactNodeTitle = "-=",Keywords = "decrement float"), Category = "Victory BP Library|Math|Float") + static void VictoryFloatMinusEquals(UPARAM(ref) float& Float, float Sub, float& FloatOut); + + /** Sort an integer array, smallest value will be at index 0 after sorting. Modifies the input array, no new data created. <3 Rama */ + UFUNCTION(BlueprintCallable, meta = (Keywords = "sort integer array"), Category = "Victory BP Library|Array") + static void VictorySortIntArray(UPARAM(ref) TArray& IntArray, TArray& IntArrayRef); + + /** Sort a float array, smallest value will be at index 0 after sorting. Modifies the input array, no new data created. */ + UFUNCTION(BlueprintCallable, meta = (Keywords = "sort float array"), Category = "Victory BP Library|Array") + static void VictorySortFloatArray(UPARAM(ref) TArray& FloatArray, TArray& FloatArrayRef); + + + /* Returns true if vector2D A is equal to vector2D B (A == B) within a specified error tolerance */ + UFUNCTION(BlueprintPure, meta=(DisplayName = "Equal (vector2D)", CompactNodeTitle = "==", Keywords = "== equal"), Category="Victory BP Library|Math|Vector2D") + static bool EqualEqual_Vector2DVector2D(FVector2D A, FVector2D B, float ErrorTolerance = 1.e-4f) + { + return A.Equals(B,ErrorTolerance); + } + + /* Returns true if vector2D A is not equal to vector2D B (A != B) within a specified error tolerance */ + UFUNCTION(BlueprintPure, meta=(DisplayName = "Not Equal (vector2D)", CompactNodeTitle = "!=", Keywords = "!= not equal"), Category="Victory BP Library|Math|Vector2D") + static bool NotEqual_Vector2DVector2D(FVector2D A, FVector2D B, float ErrorTolerance = 1.e-4f) + { + return !A.Equals(B,ErrorTolerance); + } + + //~~~ + + /** + * Tries to reach Target based on distance from Current position, giving a nice smooth feeling when tracking a position. + * + * @param Current Actual position + * @param Target Target position + * @param DeltaTime Time since last tick + * @param InterpSpeed Interpolation speed + * @return New interpolated position + */ + //UFUNCTION(BlueprintPure, Category="Math|Interpolation", meta=(Keywords="position")) + UFUNCTION(BlueprintPure, Category="Victory BP Library|Math", meta=(Keywords="position")) + static FVector2D Vector2DInterpTo(FVector2D Current, FVector2D Target, float DeltaTime, float InterpSpeed); + + /** + * Tries to reach Target at a constant rate. + * + * @param Current Actual position + * @param Target Target position + * @param DeltaTime Time since last tick + * @param InterpSpeed Interpolation speed + * @return New interpolated position + */ + //UFUNCTION(BlueprintPure, Category="Math|Interpolation", meta=(Keywords="position")) + UFUNCTION(BlueprintPure, Category="Victory BP Library|Math", meta=(Keywords="position")) + static FVector2D Vector2DInterpTo_Constant(FVector2D Current, FVector2D Target, float DeltaTime, float InterpSpeed); + + //~~~ Text To Number ~~~ + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Conversion") + static bool Text_IsNumeric(const FText& Text) + { + return Text.IsNumeric(); + } + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Conversion", meta=(AdvancedDisplay = "1")) + static float Text_ToFloat(const FText& Text, bool UseDotForThousands=false) + { + //because commas lead to string number being truncated, FText 10,000 becomes 10 for FString + FString StrFloat = Text.ToString(); + TextNumFormat(StrFloat,UseDotForThousands); + return FCString::Atof(*StrFloat); + } + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Conversion", meta=(AdvancedDisplay = "1")) + static int32 Text_ToInt(const FText& Text, bool UseDotForThousands=false) + { + //because commas lead to string number being truncated, FText 10,000 becomes 10 for FString + FString StrInt = Text.ToString(); + TextNumFormat(StrInt,UseDotForThousands); + return FCString::Atoi(*StrInt); + } + + static void TextNumFormat(FString& StrNum, bool UseDotForThousands) + { + //10.000.000,997 + if(UseDotForThousands) + { + StrNum.ReplaceInline(TEXT("."),TEXT("")); //no dots as they truncate + StrNum.ReplaceInline(TEXT(","),TEXT(".")); //commas become decimal + } + + //10,000,000.997 + else + { + StrNum.ReplaceInline(TEXT(","),TEXT("")); //decimal can stay, commas would truncate so remove + } + } + + //~~~ End of Text To Number ~~~ + + /** Returns Value mapped from one range into another where the value is clamped to the output range. (e.g. 0.5 normalized from the range 0->1 to 0->50 would result in 25) */ + UFUNCTION(BlueprintPure, Category="Victory BP Library|Math", meta=(Keywords = "get mapped value clamped")) + static float MapRangeClamped(float Value, float InRangeA, float InRangeB, float OutRangeA, float OutRangeB); + + /** Server Travel! This is an async load level process which allows you to put up a UMG widget while the level loading occurs! */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|System",meta=(WorldContext="WorldContextObject")) + static void ServerTravel(UObject* WorldContextObject,FString MapName, bool bSkipNotifyPlayers=false); + + /** Get a Player Start by Name! */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|System",meta=(WorldContext="WorldContextObject")) + static APlayerStart* GetPlayerStart(UObject* WorldContextObject,FString PlayerStartName); + + /** Convert String Back To Vector. IsValid indicates whether or not the string could be successfully converted. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Conversion",meta=(DisplayName = "String to Vector", CompactNodeTitle = "->")) + static void Conversions__StringToVector(const FString& String, FVector& ConvertedVector, bool& IsValid); + + /** Convert String Back To Rotator. IsValid indicates whether or not the string could be successfully converted. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Conversion",meta=(DisplayName = "String to Rotator", CompactNodeTitle = "->")) + static void Conversions__StringToRotator(const FString& String, FRotator& ConvertedRotator, bool& IsValid); + + /** Convert String Back To Color. IsValid indicates whether or not the string could be successfully converted. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Conversion",meta=(DisplayName = "String to Color", CompactNodeTitle = "->")) + static void Conversions__StringToColor(const FString& String, FLinearColor& ConvertedColor, bool& IsValid); + + /** Convert Color to String! */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Conversion",meta=(DisplayName = "Color to String ", CompactNodeTitle = "~>")) + static void Conversions__ColorToString(const FLinearColor& Color, FString& ColorAsString); + + /** Get Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + //UFUNCTION(BlueprintPure, Category = "Victory BP Library|Custom Config Vars!") + //static uint8 Victory_ConvertStringToByte(UEnum* Enum,FString String); + //! not working yet, always getting 255 + + /** Get Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Custom Config Vars") + static bool VictoryGetCustomConfigVar_Bool(FString SectionName, FString VariableName, bool& IsValid); + + /** Get Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Custom Config Vars") + static int32 VictoryGetCustomConfigVar_Int(FString SectionName, FString VariableName, bool& IsValid); + + /** Get Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Custom Config Vars") + static float VictoryGetCustomConfigVar_Float(FString SectionName, FString VariableName, bool& IsValid); + + /** Get Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Custom Config Vars") + static FVector VictoryGetCustomConfigVar_Vector(FString SectionName, FString VariableName, bool& IsValid); + + /** Get Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Custom Config Vars") + static FRotator VictoryGetCustomConfigVar_Rotator(FString SectionName, FString VariableName, bool& IsValid); + + /** Get Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Custom Config Vars") + static FLinearColor VictoryGetCustomConfigVar_Color(FString SectionName, FString VariableName, bool& IsValid); + + /** Get Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Custom Config Vars") + static FString VictoryGetCustomConfigVar_String(FString SectionName, FString VariableName, bool& IsValid); + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Custom Config Vars") + static FVector2D VictoryGetCustomConfigVar_Vector2D(FString SectionName, FString VariableName, bool& IsValid); + + //~~~~~~~~~~~~~~~~~~~~ + + /** Set Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Custom Config Vars") + static void VictorySetCustomConfigVar_Vector2D(FString SectionName, FString VariableName, FVector2D Value); + + /** Set Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Custom Config Vars") + static void VictorySetCustomConfigVar_Bool(FString SectionName, FString VariableName, bool Value); + + /** Set Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Custom Config Vars") + static void VictorySetCustomConfigVar_Int(FString SectionName, FString VariableName, int32 Value); + + /** Set Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Custom Config Vars") + static void VictorySetCustomConfigVar_Float(FString SectionName, FString VariableName, float Value); + + /** Set Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Custom Config Vars") + static void VictorySetCustomConfigVar_Vector(FString SectionName, FString VariableName, FVector Value); + + /** Set Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Custom Config Vars") + static void VictorySetCustomConfigVar_Rotator(FString SectionName, FString VariableName, FRotator Value); + + /** Set Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Custom Config Vars") + static void VictorySetCustomConfigVar_Color(FString SectionName, FString VariableName, FLinearColor Value); + + + /** Set Custom Config Var! These are stored in Saved/Config/Windows/Game.ini */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Custom Config Vars") + static void VictorySetCustomConfigVar_String(FString SectionName, FString VariableName, FString Value); + + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Transform") + FRotator TransformVectorToActorSpaceAngle(AActor* Actor, const FVector& InVector); + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Transform") + FVector TransformVectorToActorSpace(AActor* Actor, const FVector& InVector); + + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|UMG", meta=(keywords="HMD vive oculus rift gearvr morpheus")) + static FName GetHeadMountedDisplayDeviceType(); + + + /** The FName that is expected is the exact same format as when you right click on asset -> Copy Reference! You can directly paste copied references into this node! IsValid lets you know if the path was correct or not and I was able to load the object. MAKE SURE TO SAVE THE RETURNED OBJECT AS A VARIABLE. Otherwise your shiny new asset will get garbage collected. I recommend you cast the return value to the appropriate object and then promote it to a variable :) -Rama */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Misc") + static UObject* LoadObjectFromAssetPath(TSubclassOf ObjectClass, FName Path, bool& IsValid); + + /** Uses the same format as I use for LoadObjectFromAssetPath! Use this node to get the asset path of objects in the world! -Rama */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Misc") + static FName GetObjectPath(UObject* Obj); + + + /** Find all widgets of a certain class! Top level only means only widgets that are directly added to the viewport will be found */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|UMG", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject", DeterminesOutputType = "WidgetClass", DynamicOutputParam = "FoundWidgets")) + static void GetAllWidgetsOfClass(UObject* WorldContextObject, TSubclassOf WidgetClass, TArray& FoundWidgets, bool TopLevelOnly = true); + + /** Remove all widgets of a certain class from viewport! */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|UMG", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static void RemoveAllWidgetsOfClass(UObject* WorldContextObject, TSubclassOf WidgetClass); + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|UMG", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static bool IsWidgetOfClassInViewport(UObject* WorldContextObject, TSubclassOf WidgetClass); + + /** Handy helper to check if a Key Event was for specified Key ♥ Rama*/ + UFUNCTION(BlueprintPure,Category="Victory BP Library|UMG", meta = (Keywords = "== match same equal")) + static void JoyIsKey(const FKeyEvent& KeyEvent, FKey Key, bool& Ctrl, bool& Shift, bool& Alt, bool& Cmd, bool& Match) + { + Ctrl = KeyEvent.IsControlDown(); + Alt = KeyEvent.IsAltDown(); + Shift = KeyEvent.IsShiftDown(); + Cmd = KeyEvent.IsCommandDown(); + Match = KeyEvent.GetKey() == Key; + } + + /** Retrieves the unique net ID for the local player as a number! The number itself will vary based on what Online Subsystem is being used, but you are guaranteed that this number is unique per player! */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Networking") + static int32 GetPlayerUniqueNetID(); + + /** Call this periodically in a huge loop you are intentionally using to reset the BP runaway loop system. Caution, if you have an infinite loop this will permanently hang your system until you turn your computer off. Use very very carefully! When constructing a new loop and you are not sure if it is totally stable, do NOT use this node! Always test new loops normally to ensure you dont truly have a runaway loop that would hang your computer forever. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Misc") + static void Loops_ResetBPRunawayCounter(); + + /** Set the Max Frame Rate. Min value is 10. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Graphics Settings") + static void GraphicsSettings__SetFrameRateCap(float NewValue); + + /** Only hardware dependent, no smoothing */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Graphics Settings") + static void GraphicsSettings__SetFrameRateToBeUnbound(); + + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Misc") + static FVector2D ProjectWorldToScreenPosition(const FVector& WorldLocation); + + /** Make sure to save off the return value as a global variable in one of your BPs or else it will get garbage collected! */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Misc", meta = (DeprecatedFunction, DeprecationMessage="Epic has introduced Construct Object as of 4.9.0, I recommend you use that instead! -Rama", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static UObject* CreateObject(UObject* WorldContextObject, UClass* TheObjectClass); + + /** Make sure to save off the return value as a global variable in one of your BPs or else it will get garbage collected! */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Misc", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static UPrimitiveComponent* CreatePrimitiveComponent(UObject* WorldContextObject, TSubclassOf CompClass, FName Name, FVector Location, FRotator Rotation); + + + + /** Spawn an Actor and choose which level you want them to spawn into! */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Actor", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static AActor* SpawnActorIntoLevel(UObject* WorldContextObject, TSubclassOf ActorClass, FName Level = NAME_None, FVector Location = FVector::ZeroVector, FRotator Rotation = FRotator::ZeroRotator, bool SpawnEvenIfColliding = true); + + /** Get the names of all currently loaded and visible levels! */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|System", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static void GetNamesOfLoadedLevels(UObject* WorldContextObject, TArray& NamesOfLoadedLevels); + + + + + /** Obtain the scaled,rotated, and translated vertex positions for any static mesh! Returns false if operation could not occur because the comp or static mesh asset was invalid. <3 Rama */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Actor") + static bool GetStaticMeshVertexLocations(UStaticMeshComponent* Comp, TArray& VertexPositions); + + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Actor") + static void AddToActorRotation(AActor* TheActor, FRotator AddRot); + + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Misc", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static void DrawCircle( + UObject* WorldContextObject, + FVector Center, + float Radius, + int32 NumPoints = 32, + float Thickness = 7, + FLinearColor LineColor = FLinearColor::Red, + FVector YAxis = FVector(0, 1, 0), + FVector ZAxis = FVector(0, 0, 1), + float Duration = 0, + bool PersistentLines = false + ); + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|AI",meta=(WorldContext="WorldContextObject")) + static AActor* GetClosestActorOfClassInRadiusOfLocation(UObject* WorldContextObject, TSubclassOf ActorClass, FVector Center, float Radius, bool& IsValid); + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|AI",meta=(WorldContext="WorldContextObject")) + static AActor* GetClosestActorOfClassInRadiusOfActor(UObject* WorldContextObject, TSubclassOf ActorClass, AActor* ActorCenter, float Radius, bool& IsValid); + + /** + * Generates a box that is guaranteed to contain all of the supplied points. + * + * @param Points The world space points that the box will encompass. + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Misc") + static void GetBoxContainingWorldPoints(const TArray& Points, FVector& Center, FVector& Extent) + { + FBox Box(ForceInit); + + for(const FVector& Each : Points) + { + Box += Each; + } + Center = Box.GetCenter(); + Extent = Box.GetExtent(); + } + + /** Implementation of a Selection Marquee / Selection Box as a BP Node. AnchorPoint is the first clicked point, which user then drags from to make the box. Class filter is optional way to narrow the scope of actors that can be selected by the selection box! -Rama*/ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Misc", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static void Selection_SelectionBox(UObject* WorldContextObject, TArray& SelectedActors, FVector2D AnchorPoint, FVector2D DraggedPoint, TSubclassOf ClassFilter); + + + /** Get the Controller ID for a supplied Player Controller <3 Rama. Returns false if operation could not occur. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Controller") + static bool PlayerController_GetControllerID(APlayerController* ThePC, int32& ControllerID); + + /** Get the Unique PlayerID from the PlayerState for a supplied Player Controller. Returns false if operation could not occur. Epic accepted my pull request for this a while back so now you can just GetPlayerState and directly access <3 Rama*/ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Networking") + static bool PlayerState_GetPlayerID(APlayerController* ThePC, int32& PlayerID); + + /** Returns whether this game instance is single player. <3 Rama*/ + UFUNCTION(BlueprintPure, Category="Victory BP Library|Networking", meta=(Keywords="SinglePlayer multiplayer", WorldContext="WorldContextObject")) + static bool IsStandAlone(UObject* WorldContextObject) + { + UWorld* World = GEngine->GetWorldFromContextObjectChecked( WorldContextObject ); + return World ? (World->GetNetMode() == NM_Standalone) : false; + } + + + /** Launches the specified URL in the OS default web browser :) <3 Rama */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|System") + static void Open_URL_In_Web_Browser(FString TheURL); + + + + /** Returns which platform the game code is running in.*/ + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Victory BP Library|System") + static void OperatingSystem__GetCurrentPlatform( + bool& Windows_, + bool& Mac, + bool& Linux, + bool& iOS, + bool& Android, + bool& Android_ARM, + bool& Android_Vulkan, + bool& PS4, + bool& XBoxOne, + bool& HTML5, + bool& Apple + ); + + //~~~ + + /** Retrieves the OS system Date and Time as a string at the instant this BP node runs. Use my other RealWorldTime node to get the time passed since the return value of this node! You can use this to record milliseconds/seconds/minutes/hours between events in game logic! */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Victory BP Library|System") + static FString RealWorldTime__GetCurrentOSTime( + int32& MilliSeconds, + int32& Seconds, + int32& Minutes, + int32& Hours12, + int32& Hours24, + int32& Day, + int32& Month, + int32& Year + ); + + /** Get the amount of seconds/minutes/hours since the the supplied DateTime string! You can use this to record milliseconds/seconds/minutes/hours between events in game logic! */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Victory BP Library|System") + static void RealWorldTime__GetTimePassedSincePreviousTime( + const FString& PreviousTime, + float& Milliseconds, + float& Seconds, + float& Minutes, + float& Hours + ); + + /** Get the difference between two recorded times! You can use this to record milliseconds/seconds/minutes/hours between events in game logic! */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Victory BP Library|System") + static void RealWorldTime__GetDifferenceBetweenTimes( + const FString& PreviousTime1, + const FString& PreviousTime2, + float& Milliseconds, + float& Seconds, + float& Minutes, + float& Hours + ); + + //~~~ + + /** Loads a text file from hard disk and parses it into a String array, where each entry in the string array is 1 line from the text file. Option to exclude lines that are only whitespace characters or '\n'. Returns the size of the final String Array that was created. Returns false if the file could be loaded from hard disk. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|File IO") + static bool LoadStringArrayFromFile(TArray& StringArray, int32& ArraySize, FString FullFilePath = "Enter Full File Path", bool ExcludeEmptyLines = false); + + /** Load a text file to a single string that you can use ParseIntoArray on newline characters if you want same format as LoadStringArrayFromFile. This version supports unicode characters! */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|File IO") + static bool LoadStringFromFile(FString& Result, FString FullFilePath = "Enter Full File Path") + { + return FFileHelper::LoadFileToString( Result, *FullFilePath); + } + + //~~~ + + /** Max of all array entries. Returns -1 if the supplied array is empty. Returns the index of the max value as well as the value itself. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Array") + static void MaxOfFloatArray(const TArray& FloatArray, int32& IndexOfMaxValue, float& MaxValue); + + /** Max of all array entries. Returns -1 if the supplied array is empty. Returns the index of the max value as well as the value itself. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Array") + static void MaxOfIntArray(const TArray& IntArray, int32& IndexOfMaxValue, int32& MaxValue); + + /** Min of all array entries. Returns -1 if the supplied array is empty. Returns the index of the min value as well as the value itself. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Array") + static void MinOfFloatArray(const TArray& FloatArray, int32& IndexOfMinValue, float& MinValue); + + /** Min of all array entries. Returns -1 if the supplied array is empty. Returns the index of the min value as well as the value itself. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Array") + static void MinOfIntArray(const TArray& IntArray, int32& IndexOfMinValue, int32& MinValue); + + //~~~ + + /** Set Max Move Speed. Supply the Character whose Character Movement to change! Returns false if operation could not occur due to invalid Character or MovementComponent could not be obtained.*/ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Character", meta = (DefaultToSelf = "TheCharacter")) + static bool CharacterMovement__SetMaxMoveSpeed(ACharacter* TheCharacter, float NewMaxMoveSpeed); + + //~~~ + + /** Converts a float to a rounded Integer, examples: 1.4 becomes 1, 1.6 becomes 2 */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Victory BP Library|Math") + static int32 Conversion__FloatToRoundedInteger(float IN_Float); + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|String") + static int32 CountOccurrancesOfSubString(FString Source, FString SubString, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase) + { + return Source.ReplaceInline(*SubString,TEXT(""),SearchCase); + } + + + + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|String", meta=( Keywords = "concatenate append")) + static void VictoryAppendInline(UPARAM(ref) FString& String, const FString& ToAppend, FString& Result, bool AppendNewline=false) + { + String += ToAppend; + if(AppendNewline) String += LINE_TERMINATOR; + Result = String; + } + + /** Handy option to trim any extra 00: 's while keeping a base set of 00:ss as per user expectation. 00:05:30 will become 05:30. ♥ Rama */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|System") + static FString Victory_SecondsToHoursMinutesSeconds(float Seconds, bool TrimZeroes=true); + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|String") + static bool IsAlphaNumeric(const FString& String); + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|String") + static void Victory_GetStringFromOSClipboard(FString& FromClipboard); + + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|String") + static void Victory_SaveStringToOSClipboard(const FString& ToClipboard); + + /** + * Returns whether or not the SearchIn string contains the supplied Substring. + * Ex: "cat" is a contained within "concatenation" as a substring. + * @param SearchIn The string to search within + * @param Substring The string to look for in the SearchIn string + * @param bUseCase Whether or not to be case-sensitive + * @param bSearchFromEnd Whether or not to start the search from the end of the string instead of the beginning + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|String") + static bool HasSubstring(const FString& SearchIn, const FString& Substring, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase, ESearchDir::Type SearchDir = ESearchDir::FromStart); + + /** Combines two strings together! The Separator and the Labels are optional*/ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|String") + static FString String__CombineStrings(FString StringFirst, FString StringSecond, FString Separator = "", FString StringFirstLabel = "", FString StringSecondLabel = ""); + + /** Separator is always a space */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|String", meta=( Keywords = "concatenate append", CommutativeAssociativeBinaryOperator = "true")) + static FString String__CombineStrings_Multi(FString A, FString B); + + /** Returns three arrays containing all of the resolutions and refresh rates for the current computer's current display adapter. You can loop over just 1 of the arrays and use the current index for the other two arrays, as all 3 arrays will always have the same length. Returns false if operation could not occur. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|System", meta = (Keywords = "screen resolutions display adapter")) + static bool OptionsMenu__GetDisplayAdapterScreenResolutions(TArray& Widths, TArray& Heights, TArray& RefreshRates, bool IncludeRefreshRates = false); + + UFUNCTION(BlueprintPure, Category = "Victory BP Library|GPU", meta=(Keyword="amd nvidia graphics card brand make model")) + static void GetUserDisplayAdapterBrand(bool& IsAMD, bool& IsNvidia, bool& IsIntel, bool& IsUnknown, int32& UnknownId); + + /** Clones an actor by obtaining its class and creating a copy. Returns the created Actor. The cloned actor is set to have the rotation and location of the initial actor. You can optionally specify location / rotation offsets for the new clone from original actor. Use IsValid to know if the actor was able to be cloned. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Actor", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static AStaticMeshActor* Clone__StaticMeshActor(UObject* WorldContextObject, bool&IsValid, AStaticMeshActor* ToClone, FVector LocationOffset = FVector(0, 0, 0), FRotator RotationOffset = FRotator(0, 0, 0)); + + + /** Teleport Actor To Actor. Moves an actor instantly to the position and rotation of another actor. Useful for player starts, notes, triggers, and any other destination actors who dont have collision. Returns false if the operation could not occur. */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Victory BP Library|Actor") + static bool Actor__TeleportToActor(AActor* ActorToTeleport, AActor* DestinationActor); + + /** Is this game logic running in the Editor world? */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Victory BP Library|System", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static bool WorldType__InEditorWorld(UObject* WorldContextObject); + + /** Is this game logic running in the PIE world? */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Victory BP Library|System", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static bool WorldType__InPIEWorld(UObject* WorldContextObject); + + /** Is this game logic running in an actual independent game instance? */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Victory BP Library|System", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static bool WorldType__InGameInstanceWorld(UObject* WorldContextObject); + + /** Cause a supplied Character (casted from Actor internally) to enter Ragdoll physics. A check will be done to see if the character has a physics asset. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Physics") + static bool Physics__EnterRagDoll(AActor* TheCharacter); + + /** Cause a supplied Character (casted from Actor internally) to exit Ragdoll physics. HeightAboveRBMesh is how far above the RB Mesh the Actor Capsule should be moved to upon exiting. Pass in the InitLocation and InitRotation from InitializeVictoryRagdoll */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Physics") + static bool Physics__LeaveRagDoll(AActor* TheCharacter, bool SetToFallingMovementMode=true, float HeightAboveRBMesh = 64, const FVector& InitLocation = FVector(0, 0, 0), const FRotator& InitRotation = FRotator(0, 0, 0)); + + /** Returns whether or not a supplied Character is in Ragdoll Physics. Cast from Actor done internally for your convenience. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Physics") + static bool Physics__IsRagDoll(AActor* TheCharacter); + + /** Get the Ragdoll Position of the supplied actor, casted to Character internally. Returns false if operation could not occur. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Physics") + static bool Physics__GetLocationofRagDoll(AActor* TheCharacter, FVector& RagdollLocation); + + /** Initialize Victory Ragdoll Mode, by Obtaining the Default Relative Rotation and Location for this Character's Mesh. The Output Location and Rotation must be saved for use with LeaveRagdoll. Returns false if operation could not occur */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Physics") + static bool Physics__InitializeVictoryRagDoll(AActor* TheCharacter, FVector&InitLocation, FRotator&InitRotation); + + /** Update the TheCharacter's Capsule Location and Camera to the Current Location of the Ragdoll. InterpSpeed is how fast the camera keeps up with the moving ragdoll! HeightOffset is the height above the ragdoll that the camera should stay. Returns false if operation could not occur or if Mesh was not in ragdoll */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Physics") + static bool Physics__UpdateCharacterCameraToRagdollLocation(AActor* TheCharacter, float HeightOffset = 128, float InterpSpeed = 3); + + + /** This node checks all Scalar, Vector, and Texture parameters of a material to see if the supplied parameter name is an actual parameter in the material! ♥ Rama*/ + UFUNCTION(BlueprintPure,Category="Victory BP Library|Material") + static bool DoesMaterialHaveParameter(UMaterialInterface* Mat, FName Parameter); + + + /** Get Name as String*/ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|String") + static FString Accessor__GetNameAsString(const UObject* TheObject); + + /** Get Socket Local Transform. Returns false if operation could not occur.*/ + //UFUNCTION(BlueprintCallable, Category = "Victory BP Library") + //static bool Accessor__GetSocketLocalTransform(const USkeletalMeshComponent* Mesh, FTransform& LocalTransform, FName SocketName=FName("SocketName")); + + /** Get Player Character's Player Controller. Requires: The Passed in Actor must be a character and it must be a player controlled character. IsValid will tell you if the return value is valid, make sure to do a Branch to confirm this! */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Character") + static APlayerController* Accessor__GetPlayerController(AActor* TheCharacter, bool&IsValid); + + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Input") + static void VictorySimulateMouseWheel(const float& Delta); + + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Input") + static void VictorySimulateKeyPress(APlayerController* ThePC, FKey Key, EInputEvent EventType); + + /** This handy node lets you turn the rendering of the entire world on or off! Does not affect UMG or HUD, which allows you to use loading screens effectively! <3 Rama. Returns false if player controller could not be used to get the viewport. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|System", meta=(keywords="disable show hide loading screen")) + static bool Viewport__EnableWorldRendering(const APlayerController* ThePC, bool RenderTheWorld); + + /** SET the Mouse Position! Returns false if the operation could not occur */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Input") + static bool Viewport__SetMousePosition(const APlayerController* ThePC, const float& PosX, const float& PosY); + + /** Get the Cursor Position within the Player's Viewport. This will return a result consistent with SET Mouse Position Returns false if the operation could not occur */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Game Window") + static bool Viewport__GetMousePosition(const APlayerController* ThePC, float& PosX, float& PosY); + + + /** Get the coordinates of the center of the player's screen / viewport. Returns false if the operation could not occur */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Game Window") + static bool Viewport__GetCenterOfViewport(const APlayerController* ThePC, float& PosX, float& PosY); + + + /** Convert Vector to Rotator*/ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Conversion") + static FRotator Conversions__VectorToRotator(const FVector& TheVector); + + /** Convert Rotator to Vector */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Conversion") + static FVector Conversions__RotatorToVector(const FRotator& TheRotator); + + /** Input Actor is expected to be a ACharacter, conversion done internally for your convenience */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Conversion") + static FRotator Character__GetControllerRotation(AActor * TheCharacter); + + + + /** Draw 3D Line of Chosen Thickness From Socket on Character's Mesh to Destination, conversion of AActor to ACharacter done internally for your convenience. Duration is in Seconds */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|3d Lines") + static void Draw__Thick3DLineFromCharacterSocket(AActor* TheCharacter, const FVector& EndPoint, FName Socket = FName("SocketName"), FLinearColor LineColor = FLinearColor(1, 0, 0, 1), float Thickness = 7, float Duration = -1.f); + /** Draw 3D Line of Chosen Thickness From Mesh Socket to Destination. Duration is in Seconds */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|3d Lines") + static void Draw__Thick3DLineFromSocket(USkeletalMeshComponent* Mesh, const FVector& EndPoint, FName Socket = FName("SocketName"), FLinearColor LineColor = FLinearColor(0, 1, 0, 1), float Thickness = 7, float Duration = -1.f); + /** Draw 3D Line of Chosen Thickness Between Two Actors. Duration is in Seconds */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|3d Lines") + static void Draw__Thick3DLineBetweenActors(AActor* StartActor, AActor* EndActor, FLinearColor LineColor = FLinearColor(0, 0, 1, 1), float Thickness = 7, float Duration = -1.f); + + /** AnimBPOwner - Must be a Character, Conversion Internally For Convenience.\n\nRetrieves the Aim Offsets Pitch & Yaw Based On the Rotation of the Controller of The Character Owning The Anim Instance.\n\nThe Pitch and Yaw are meant to be used with a Blend Space going from -90,-90 to 90,90.\n Returns true if function filled the pitch and yaw vars successfully */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Aim Offset") + static bool Animation__GetAimOffsets(AActor* AnimBPOwner, float& Pitch, float& Yaw); + + /** AnimBPOwner - Must be a Character, Conversion Internally For Convenience.\n\nRetrieves the Aim Offsets Pitch & Yaw for the AnimBPOwner Based On the supplied Rotation.\n\nThe Pitch and Yaw are meant to be used with a Blend Space going from -90,-90 to 90,90.\n Returns true if function filled the pitch and yaw vars successfully */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Aim Offset") + static bool Animation__GetAimOffsetsFromRotation(AActor * AnimBPOwner, const FRotator & TheRotation, float & Pitch, float & Yaw); + + /** Saves text to filename of your choosing, make sure include whichever file extension you want in the filename, ex: SelfNotes.txt . Make sure to include the entire file path in the save directory, ex: C:\MyGameDir\BPSavedTextFiles */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|File IO") + static bool FileIO__SaveStringTextToFile(FString SaveDirectory, FString JoyfulFileName, FString SaveText, bool AllowOverWriting = false, bool AllowAppend = false); + + /** Saves multiple Strings to filename of your choosing, with each string on its own line! Make sure include whichever file extension you want in the filename, ex: SelfNotes.txt . Make sure to include the entire file path in the save directory, ex: C:\MyGameDir\BPSavedTextFiles */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|File IO") + static bool FileIO__SaveStringArrayToFile(FString SaveDirectory, FString JoyfulFileName, TArray SaveText, bool AllowOverWriting = false, bool AllowAppend = false); + + + /** Obtain an Array of Actors Rendered Recently. You can specifiy what qualifies as "Recent" in seconds. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Actor", meta=(WorldContext="WorldContextObject")) + static void Visibility__GetRenderedActors(UObject* WorldContextObject, TArray& CurrentlyRenderedActors, float MinRecentTime = 0.01); + + /** Obtain an Array of Actors NOT Rendered Recently! You can specifiy what qualifies as "Recent" in seconds. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Actor", meta=(WorldContext="WorldContextObject")) + static void Visibility__GetNotRenderedActors(UObject* WorldContextObject, TArray& CurrentlyNotRenderedActors, float MinRecentTime = 0.01); + + /** Is the Current Game Window the Foreground window in the OS, or in the Editor? This will be accurate in standalone running of the game as well as in the editor PIE */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Game Window") + static bool ClientWindow__GameWindowIsForeGroundInOS(); + + /** Flashes the game on the windows OS task bar! Please note this won't look the best in PIE, flashing is smoother in Standalone or packaged game. You can use GameWindowIsForeGroundInOS to see if there is a need to get the user's attention! <3 Rama */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Game Window") + static void FlashGameOnTaskBar(APlayerController* PC, bool FlashContinuous=false, int32 MaxFlashCount = 3, int32 FlashFrequencyMilliseconds=500); + + /** Freeze Game Render, Does Not Stop Game Logic, Just Rendering. This is not like Pausing. Mainly useful for freezing render when window is not in the foreground */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Game Window") + static void Rendering__FreezeGameRendering(); + + /** Unfreeze Game Render. This is not an unpause function, it's just for actual screen rendering */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Game Window") + static void Rendering__UnFreezeGameRendering(); + + /** Compare Source Vector against Array of Vectors. Returns: Returns the Closest Vector to Source and what that closest Distance is, or -1 if there was an error such as array being empty. Ignores: Ignores Source if source is in the array */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Misc") + static float Calcs__ClosestPointToSourcePoint(const FVector & Source, const TArray& OtherPoints, FVector& ClosestPoint); + + /** Takes in an actor (for convenience) and tries to cast it to Character and return an array of Vectors of all of the current bone locations of the character's Mesh. Locations are in World Space. Returns: false if the operation could not occur. Requires: Character Mesh Component must be valid */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Actor") + static bool Data__GetCharacterBoneLocations(AActor * TheCharacter, TArray& BoneLocations); + + /** Retrieves the "Mesh" component of a Character. IsValid lets you know if the data is valid, make sure to check if it is! Requires: the passed in Actor must be a Character */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Character") + static USkeletalMeshComponent* Accessor__GetCharacterSkeletalMesh(AActor* TheCharacter, bool& IsValid); + + + /** + * Get All Bone Names Below Bone, requires a physics asset, by Rama + * + * @param StartingBoneName The name of the bone to find all bones below. + * + * @param BoneNames , all of the bone names below the starting bone. + * + * @return total number of bones found + */ + UFUNCTION(BlueprintCallable, Category="Victory BP Library|Components|SkinnedMesh") + static int32 GetAllBoneNamesBelowBone(USkeletalMeshComponent* SkeletalMeshComp, FName StartingBoneName, TArray& BoneNames ); + + /** Does Not Do A Trace, But Obtains the Start and End for doing a Trace:\n\nTakes in an actor (for convenience) and tries to cast it to Character. Takes in a socket name to find on the Character's Mesh component, the socket location will be the start of the trace.\n\nAlso takes in the Angle / Rotator and the length of the trace you want to do. Option to draw the trace with variable thickness as it occurs.\n\nReturns what the Trace Start and End should be so you can plug these into any existing trace node you want.\n\nRequires: Character Mesh Component must be valid. Returns False if trace could not be done */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Traces") + static bool TraceData__GetTraceDataFromCharacterSocket(FVector& TraceStart, FVector& TraceEnd, AActor * TheCharacter, const FRotator& TraceRotation, float TraceLength = 10240, FName Socket = "SocketName", bool DrawTraceData = true, FLinearColor TraceDataColor = FLinearColor(1, 0, 0, 1), float TraceDataThickness = 7); + + /** Does Not Do A Trace, But Obtains the Start and End for doing a Trace:\n\nTakes in a Skeletal Mesh Component and a socket name to trace from. Also takes in the Angle / Rotator and the length of the trace you want to do.\n\nOption to draw the trace as a variable thickness line\n\nReturns what the Trace Start and End should be so you can plug these into any existing trace node you want.\n\n Requires: Mesh must be valid. Returns False if trace could not be done */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Traces") + static bool TraceData__GetTraceDataFromSkeletalMeshSocket(FVector& TraceStart, FVector& TraceEnd, USkeletalMeshComponent* Mesh, const FRotator& TraceRotation, float TraceLength = 10240, FName Socket = "SocketName", bool DrawTraceData = true, FLinearColor TraceDataColor = FLinearColor(1, 0, 0, 1), float TraceDataThickness = 7); + + /** Does a simple line trace given Trace Start and End, and if a Character is hit by the trace, then a component trace is performed on that character's mesh. Trace Owner is ignored when doing the trace.\n\nReturns the Character that was hit, as an Actor, as well as the name of the bone that was closest to the impact point of the trace. Also returns the impact point itself as well as the impact normal.\n\nUsing component trace ensures accuracy for testing against bones and sockets.\n\nIsValid: Will be true only if the component trace also hit someting. But the Returned Actor will contain an actor if any actor at all was hit by the simple trace. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Traces") + static AActor* Traces__CharacterMeshTrace___ClosestBone(AActor* TraceOwner, const FVector& TraceStart, const FVector& TraceEnd, FVector& OutImpactPoint, FVector& OutImpactNormal, FName& ClosestBoneName, FVector & ClosestBoneLocation, bool&IsValid); + + /** Does a simple line trace given Trace Start and End, and if a Character is hit by the trace, then a component trace is performed on that character's mesh. Returns the name of the socket that was closest to the impact point of the trace. Also returns the impact point itself as well as the impact normal. Also returns the Socket Location. Using component trace ensures accuracy for testing against bones and sockets.*/ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Traces",meta=(WorldContext="WorldContextObject")) + static AActor* Traces__CharacterMeshTrace___ClosestSocket(UObject* WorldContextObject, const AActor * TraceOwner, const FVector& TraceStart, const FVector& TraceEnd, FVector& OutImpactPoint, FVector& OutImpactNormal, FName& ClosestSocketName, FVector & SocketLocation, bool&IsValid); + + /** Returns the float as a String with Precision, Precision 0 = no decimal value. Precison 1 = 1 decimal place. The re-precisioned result is rounded appropriately. */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Conversion") + static void StringConversion__GetFloatAsStringWithPrecision(float TheFloat, FString & TheString, int32 Precision = 2, bool IncludeLeadingZero=true); + + /** Rotator out value is the degrees of difference between the player camera and the direction of player to light source. Returns false if the operation could not occur. */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Misc") + static bool LensFlare__GetLensFlareOffsets(APlayerController* PlayerController, AActor* LightSource, float& PitchOffset, float& YawOffset, float& RollOffset); + + /** Retrieve Distance of given point to any Surface point on a Static Mesh Actor. Returns the distance as well as the exact closest point on the mesh surface to the given point. Returns -1 if an error occurred*/ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Misc") + static float DistanceToSurface__DistaceOfPointToMeshSurface(AStaticMeshActor* TheSMA, const FVector& TestPoint, FVector& ClosestSurfacePoint); + + /** Change the Mobility of a Static Mesh Component, can be used in Constructor Script or in Event Graph! Returns false if operation could not occur.*/ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Misc") + static bool Mobility__SetSceneCompMobility(USceneComponent* SceneComp, EComponentMobility::Type NewMobility); + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Paths + + /** InstallDir/GameName/Binaries/Win64 */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Paths") + static FString VictoryPaths__Win64Dir_BinaryLocation(); + + /** InstallDir/WindowsNoEditor/ */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Paths") + static FString VictoryPaths__WindowsNoEditorDir(); + + /** InstallDir/GameName */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Paths") + static FString VictoryPaths__GameRootDirectory(); + + /** InstallDir/GameName/Saved */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Paths") + static FString VictoryPaths__SavedDir(); + + /** InstallDir/GameName/Saved/Config/ */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Paths") + static FString VictoryPaths__ConfigDir(); + + /** InstallDir/GameName/Saved/Screenshots/Windows */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Paths") + static FString VictoryPaths__ScreenShotsDir(); + + /** InstallDir/GameName/Saved/Logs */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Paths") + static FString VictoryPaths__LogsDir(); + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Graphics Settings Sample + + //~~~~~~~~~~~~~~~~~~ + // FullScreen + //~~~~~~~~~~~~~~~~~~ + + /** Get Full Screen Type */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Graphics Settings") + static TEnumAsByte JoyGraphicsSettings__FullScreen_Get(); + + /** Set Full Screen Type */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Graphics Settings") + static void JoyGraphicsSettings__FullScreen_Set(TEnumAsByte NewSetting); + + + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CPP FUNCTION LIBRARY + + static FORCEINLINE void JoyCC(const FString& Str, const int32 Value) + { + TObjectIterator PC; + if (!PC) return; + //~~~~~~ + + PC->ConsoleCommand(Str + " " + FString::FromInt(Value)); + } + static FORCEINLINE void JoyGraphics_FullScreen_SetFullScreenType(int32 Value) + { + JoyCC("r.FullScreenMode", Value); + } + static FORCEINLINE int32 JoyGraphics_FullScreen_GetFullScreenType() + { + static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.FullScreenMode")); + return CVar->GetValueOnGameThread(); + } + static FORCEINLINE void JoyGraphics_SetFullScreen_NonWindowed() + { + /*"r.FullScreenMode"), + 2, + TEXT("Defines how we do full screen when requested (e.g. command line option -fullscreen or in ini [SystemSettings] fullscreen=true)\n") + */ + JoyCC("r.FullScreenMode", 0); + } + static FORCEINLINE void JoyGraphics_SetFullScreen_Windowed() + { + //TEXT(" 2: windowed full screen, specified resolution (like 1 but no unintuitive performance cliff, can be blurry, default)\n") + JoyCC("r.FullScreenMode", 2); + } + static FORCEINLINE void JoyGraphics_SetFullScreen_WindowedHighestQuality() + { + //TEXT(" 1: windowed full screen, desktop resolution (quick switch between applications and window mode, full quality)\n") + JoyCC("r.FullScreenMode", 1); + } + + + + //Min and Max of Array + static FORCEINLINE float Min(const TArray& Values, int32* MinIndex = NULL) + { + if (MinIndex) + { + *MinIndex = 0; + } + + if (Values.Num() <= 0) + { + return -1; + } + + float CurMin = Values[0]; + for (const float EachValue : Values) + { + CurMin = FMath::Min(CurMin, EachValue); + } + + if (MinIndex) + { + *MinIndex = Values.Find(CurMin); + } + return CurMin; + } + static FORCEINLINE float Max(const TArray& Values, int32* MaxIndex = NULL) + { + if (MaxIndex) + { + *MaxIndex = 0; + } + + if (Values.Num() <= 0) + { + return -1; + } + + float CurMax = Values[0]; + for (const float EachValue : Values) + { + CurMax = FMath::Max(CurMax, EachValue); + } + + if (MaxIndex) + { + *MaxIndex = Values.Find(CurMax); + } + return CurMax; + } + + static FORCEINLINE int32 Min(const TArray& Values, int32* MinIndex = NULL) + { + if (MinIndex) + { + *MinIndex = 0; + } + + if (Values.Num() <= 0) + { + return -1; + } + + int32 CurMin = Values[0]; + for (const int32 EachValue : Values) + { + CurMin = FMath::Min(CurMin, EachValue); + } + + if (MinIndex) + { + *MinIndex = Values.Find(CurMin); + } + return CurMin; + } + static FORCEINLINE int32 Max(const TArray& Values, int32* MaxIndex = NULL) + { + if (MaxIndex) + { + *MaxIndex = 0; + } + + if (Values.Num() <= 0) + { + return -1; + } + + int32 CurMax = Values[0]; + for (const int32 EachValue : Values) + { + CurMax = FMath::Max(CurMax, EachValue); + } + + if (MaxIndex) + { + *MaxIndex = Values.Find(CurMax); + } + return CurMax; + } + + + + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Contributed by Others + + /** + * + * Contributed by: Mindfane + * + * Split a string into an array of substrings based on the given delimitter. + * Unlike ParseIntoArray() function which expects single character delimitters, this function can accept a delimitter that is also a string. + * + * @param InputString - The string that is to be exploded. + * @param Separator - The delimitter that is used for splitting (multi character strings are allowed) + * @param limit - If greater than zero, returns only the first x strings. Otherwsie returns all the substrings + * @param bTrimElelements - If True, then each subsctring is processed and any leading or trailing whitespcaes are trimmed. + */ + UFUNCTION(BlueprintPure, meta = (DisplayName = "Victory BP Library|String", Keywords = "split explode string"), Category = String) + static void String__ExplodeString(TArray& OutputStrings, FString InputString, FString Separator = ",", int32 limit = 0, bool bTrimElements = false); + + + //NOT QUITE WORKING, REQUIRES INVESTIGATION + /** Load a Texture 2D from a DDS file! Contributed by UE4 forum member n00854180t! */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Load Texture From File",meta=(Keywords="image DDS")) + static UTexture2D* LoadTexture2D_FromDDSFile(const FString& FullFilePath); + + /** Load a Texture2D from a JPG,PNG,BMP,ICO,EXR,ICNS file! IsValid tells you if file path was valid or not. Enjoy! -Rama */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Load Texture From File",meta=(Keywords="image png jpg jpeg bmp bitmap ico icon exr icns")) + static UTexture2D* Victory_LoadTexture2D_FromFile(const FString& FullFilePath,EJoyImageFormats ImageFormat,bool& IsValid, int32& Width, int32& Height); + + /** Load a Texture2D from a JPG,PNG,BMP,ICO,EXR,ICNS file! IsValid tells you if file path was valid or not. Enjoy! -Rama */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Load Texture From File",meta=(Keywords="image png jpg jpeg bmp bitmap ico icon exr icns")) + static UTexture2D* Victory_LoadTexture2D_FromFile_Pixels(const FString& FullFilePath,EJoyImageFormats ImageFormat,bool& IsValid, int32& Width, int32& Height, TArray& OutPixels); + + /** Retrieve a pixel color value given the pixel array, the image height, and the coordinates. Returns false if the coordinates were not valid. Pixel coordinates start from upper left corner as 0,0. X= horizontal, Y = vertical */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Load Texture From File",meta=(Keywords="image coordinate index map value")) + static bool Victory_Get_Pixel(const TArray& Pixels, int32 ImageHeight, int32 x, int32 y, FLinearColor& FoundColor); + + /** Save an array of pixels to disk as a PNG! It is very important that you supply the curret width and height of the image! Returns false if Width * Height != Array length or file could not be saved to the location specified. I return an ErrorString to clarify what the exact issue was. -Rama */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Load Texture From File",meta=(Keywords="create image png jpg jpeg bmp bitmap ico icon exr icns")) + static bool Victory_SavePixels(const FString& FullFilePath,int32 Width, int32 Height, const TArray& ImagePixels, bool SaveAsBMP, bool sRGB, FString& ErrorString); + + /** This will modify the original T2D to remove sRGB and change compression to VectorDisplacementMap to ensure accurate pixel reading. -Rama*/ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Load Texture From File",meta=(Keywords="create image png jpg jpeg bmp bitmap ico icon exr icns"))//, DeprecatedFunction, DeprecationMessage="This function will not work until I figure out how to update it to 4.25, if you need it urgently, please post in my ue4 forum thread for this plugin")) + static bool Victory_GetPixelFromT2D(UTexture2D* T2D, int32 X, int32 Y, FLinearColor& PixelColor); + + /** This will modify the original T2D to remove sRGB and change compression to VectorDisplacementMap to ensure accurate pixel reading. -Rama*/ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Load Texture From File",meta=(Keywords="create image png jpg jpeg bmp bitmap ico icon exr icns"))//, DeprecatedFunction, DeprecationMessage="This function will not work until I figure out how to update it to 4.25, if you need it urgently, please post in my ue4 forum thread for this plugin")) + static bool Victory_GetPixelsArrayFromT2D(UTexture2D* T2D, int32& TextureWidth, int32& TextureHeight,TArray& PixelArray); + + /** This will modify the original T2D to remove sRGB and change compression to VectorDisplacementMap to ensure accurate pixel reading. -Rama*/ + //UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Load Texture From File",meta=(Keywords="create image png jpg jpeg bmp bitmap ico icon exr icns")) + static bool Victory_GetPixelsArrayFromT2DDynamic(UTexture2DDynamic* T2D, int32& TextureWidth, int32& TextureHeight,TArray& PixelArray); + + /** Contributed by UE4 forum member n00854180t! Plays a .ogg sound from file, attached to and following the specified component. This is a fire and forget sound. Replication is also not handled at this point. + * @param FilePath - Path to sound file to play + * @param AttachComponent - Component to attach to. + * @param AttachPointName - Optional named point within the AttachComponent to play the sound at + * @param Location - Depending on the value of Location Type this is either a relative offset from the attach component/point or an absolute world position that will be translated to a relative offset + * @param LocationType - Specifies whether Location is a relative offset or an absolute world position + * @param bStopWhenAttachedToDestroyed - Specifies whether the sound should stop playing when the owner of the attach to component is destroyed. + * @param VolumeMultiplier - Volume multiplier + * @param PitchMultiplier - PitchMultiplier + * @param AttenuationSettings - Override attenuation settings package to play sound with + */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Sound", meta = (VolumeMultiplier = "1.0", PitchMultiplier = "1.0", AdvancedDisplay = "2", UnsafeDuringActorConstruction = "true")) + static class UAudioComponent* PlaySoundAttachedFromFile(const FString& FilePath, class USceneComponent* AttachToComponent, FName AttachPointName = NAME_None, FVector Location = FVector(ForceInit), EAttachLocation::Type LocationType = EAttachLocation::SnapToTarget, bool bStopWhenAttachedToDestroyed = false, float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f, class USoundAttenuation* AttenuationSettings = NULL); + + /** Contributed by UE4 forum member n00854180t! Plays a .ogg sound at the given location. This is a fire and forget sound and does not travel with any actor. Replication is also not handled at this point. + * + * NOT SUPPORTED ON PS4. + * + * @param FilePath - Path to sound file to play + * @param Location - World position to play sound at + * @param World - The World in which the sound is to be played + * @param VolumeMultiplier - Volume multiplier + * @param PitchMultiplier - PitchMultiplier + * @param AttenuationSettings - Override attenuation settings package to play sound with + */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Sound", meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject", VolumeMultiplier = "1.0", PitchMultiplier = "1.0", AdvancedDisplay = "3", UnsafeDuringActorConstruction = "true")) + static void PlaySoundAtLocationFromFile(UObject* WorldContextObject, const FString& FilePath, FVector Location, float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f, class USoundAttenuation* AttenuationSettings = NULL); + + /** Contributed by UE4 forum member n00854180t! Creates a USoundWave* from file path. + * Read .ogg header file and refresh USoundWave metadata. + * + * NOT SUPPORTED ON PS4. + * + * @param FilePath path to file to create sound wave from + */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Sound") + static class USoundWave* GetSoundWaveFromFile(const FString& FilePath); + +#if !PLATFORM_PS4 +private: + // Thanks to @keru for the base code for loading an Ogg into a USoundWave: + // https://forums.unrealengine.com/showthread.php?7936-Custom-Music-Player&p=97659&viewfull=1#post97659 + + /** + * Read .ogg header file and refresh USoundWave metadata. NOT SUPPORTED BY PS4 + * @param sw wave to put metadata + * @param rawFile pointer to src file in memory + * @return 0 if everything is ok + * 1 if couldn't read metadata. + */ + static int32 fillSoundWaveInfo(USoundWave* sw, TArray* rawFile); + + + + /** + * Tries to find out FSoundSource object associated to the USoundWave. NOT SUPPORTED BY PS4 + * @param sw wave, search key + * @return 0 if wave found and correctly set + * -1 if error: sound device not set + * -2 if error: sound wave not found + */ + static int32 findSource(class USoundWave* sw, class FSoundSource* out_audioSource); +#endif //PLATFORM_PS4 + + + + /** + * 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 +public: + /** Construct a random device, returns either a random device or the default random engine; system dependant; + */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Random") + static void constructRand(); + + /** Seed Rand with value passed + * @param seed - value to pass to the prng as the seed + */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Random") + static void seedRand(int32 seed); + + /** Seed Rand with current time + */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Random") + static void seedRandWithTime(); + + /** Seed Rand with entropy + * @param seed - value to pass to the prng as the seed + */ + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Random") + static void seedRandWithEntropy(); + + /** Random Bool - Bernoulli distribution + * @param fBias - Bias of Bernoulli distribution + * @return uniformly distributed bool based on bias parameter + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Random") + static bool RandBool_Bernoulli(float fBias); + + /** Random Integer - Zero to One Uniform distribution + * @return int32 - uniform distribution from 0 to 1 + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Random") + static int32 RandInt_uniDis(); + + /** Random Integer - MIN to MAX Uniform distribution + * @param iMin - Minimum value of uniform distribution + * @param iMax - Maximum value of uniform distribution + * @return int32 - uniform distribution from iMin to iMax parameters + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Random") + static int32 RandInt_MINMAX_uniDis(int32 iMin, int32 iMax); + + /** Random Double - Zero to One Uniform distribution + * @return double - uniform distribution from 0 to 1 + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Random") + static float RandFloat_uniDis(); + + /** Random Double - Uniform distribution based on MIN to MAX parameters + * @param iMin - Minimum value of uniform distribution + * @param iMax - Maximum value of uniform distribution + * @return double - uniform distribution from iMin to iMax parameters + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Random") + static float RandFloat_MINMAX_uniDis(float iMin, float iMax); + + /** Random Bool - Bernoulli distribution - Mersenne Twister + * @param fBias - Bias of Bernoulli distribution + * @return uniformly distributed bool based on bias parameter + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Random") + static bool RandBool_Bernoulli_MT(float fBias); + + /** Random Integer - Zero to One Uniform distribution - Mersenne Twister + * @return int32 - uniform distribution from 0 to 1 + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Random") + static int32 RandInt_uniDis_MT(); + + /** Random Integer - MIN to MAX Uniform distribution - Mersenne Twister + * @param iMin - Minimum value of uniform distribution + * @param iMax - Maximum value of uniform distribution + * @return int32 - uniform distribution from iMin to iMax parameters + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Random") + static int32 RandInt_MINMAX_uniDis_MT(int32 iMin, int32 iMax); + + /** Random Float - Zero to One Uniform distribution - Mersenne Twister + * @return float - uniform distribution from 0 to 1 + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Random") + static float RandFloat_uniDis_MT(); + + /** Random Float - Uniform distribution based on MIN to MAX parameters - Mersenne Twister + * @param iMin - Minimum value of uniform distribution + * @param iMax - Maximum value of uniform distribution + * @return float - uniform distribution from iMin to iMax parameters + */ + UFUNCTION(BlueprintPure, Category = "Victory BP Library|Random") + static float RandFloat_MINMAX_uniDis_MT(float iMin, float iMax); +//----------------------------------------------------------------------------------------------ENDRANDOM + +/** Inspired by Sahkan! */ +UFUNCTION(BlueprintPure, Category = "Victory BP Library|Actor|Get Immediate Attached Actors") +static void Actor__GetAttachedActors(AActor* ParentActor,TArray& ActorsArray); + +/** Modify the bloom intensity of a post process volume, by Community Member Sahkan */ +UFUNCTION(BlueprintCallable, Category = "Victory BP Library|Post Process") +static void SetBloomIntensity(APostProcessVolume* PostProcessVolume,float Intensity); + + + + +//~~~ Kris ~~~ + + /* + *See if index is a valid index for this array + * + *@param TargetArray The array to perform the operation on + *@param Index The index to check. + *@return Bool if integer is valid index for this array + */ + UFUNCTION(Category="Victory BP Library|Utilities|Array", BlueprintPure, CustomThunk, meta=(DisplayName = "Valid Index", CompactNodeTitle = "VALID INDEX", ArrayParm = "TargetArray")) + static bool Array_IsValidIndex(const TArray& TargetArray, int32 Index); + + static bool GenericArray_IsValidIndex(void* TargetArray, const FArrayProperty* ArrayProp, int32 Index); + + DECLARE_FUNCTION(execArray_IsValidIndex) + { + Stack.MostRecentProperty = nullptr; + Stack.StepCompiledIn(NULL); + void* ArrayAddr = Stack.MostRecentPropertyAddress; + FArrayProperty* ArrayProperty = Cast(Stack.MostRecentProperty); + if (!ArrayProperty) + { + Stack.bArrayContextFailed = true; + return; + } + P_GET_PROPERTY(FIntProperty, Index); + P_FINISH; + + bool WasValid = GenericArray_IsValidIndex(ArrayAddr, ArrayProperty, Index); + *(bool*)RESULT_PARAM = WasValid; + } + + /** Get the time target actor was created. */ + UFUNCTION(Category = "Victory BP Library|Actor", BlueprintPure, Meta = (DefaultToSelf = "Target")) + static float GetCreationTime(const AActor* Target); + + /** Get the time target actor has been alive. */ + UFUNCTION(Category = "Victory BP Library|Actor", BlueprintPure, Meta = (DefaultToSelf = "Target")) + static float GetTimeAlive(const AActor* Target); + + /** Contributed by Community Member Kris! */ + UFUNCTION(Category = "Victory BP Library|SceneCapture", BlueprintPure) + static bool CaptureComponent2D_Project(class USceneCaptureComponent2D* Target, FVector Location, FVector2D& OutPixelLocation); + + /** Contributed by Community Member Kris! */ + UFUNCTION(Category = "Victory BP Library|SceneCapture", BlueprintPure, Meta = (DefaultToSelf = "Target")) + static bool Capture2D_Project(class ASceneCapture2D* Target, FVector Location, FVector2D& OutPixelLocation); + + /** Currently the only supported format for this function is B8G8R8A8. Make sure to include the appropriate image extension in your file path! Recommended: .bmp, .jpg, .png. Contributed by Community Member Kris! */ + UFUNCTION(Category = "Victory BP Library|SceneCapture", BlueprintCallable) + static bool CaptureComponent2D_SaveImage(class USceneCaptureComponent2D* Target, const FString ImagePath, const FLinearColor ClearColour); + + /** Currently the only supported format for this function is B8G8R8A8. Make sure to include the appropriate image extension in your file path! Recommended: .bmp, .jpg, .png. Contributed by Community Member Kris! */ + UFUNCTION(Category = "Victory BP Library|SceneCapture", BlueprintCallable, Meta = (DefaultToSelf = "Target")) + static bool Capture2D_SaveImage(class ASceneCapture2D* Target, const FString ImagePath, const FLinearColor ClearColour); + + /** Make sure your image path has a valid extension! Supported types can be seen in the BP node Victory_LoadTexture2D_FromFile. Contributed by Community Member Kris! */ + UFUNCTION(Category = "Victory BP Library|Load Texture From File", BlueprintCallable) + static UTexture2D* LoadTexture2D_FromFileByExtension(const FString& ImagePath, bool& IsValid, int32& OutWidth, int32& OutHeight); + + /** + * Find first widget of a certain class and return it. + * @param WidgetClass The widget class to filter by. + * @param TopLevelOnly Only a widget that is a direct child of the viewport will be returned. + */ + UFUNCTION(Category = "Victory BP Library|UMG", BlueprintCallable, BlueprintCosmetic, Meta = (WorldContext = "WorldContextObject", DeterminesOutputType = "WidgetClass")) + static UUserWidget* GetFirstWidgetOfClass(UObject* WorldContextObject, TSubclassOf WidgetClass, bool TopLevelOnly); + + /** + * Recurses up the list of parents and returns true if this widget is a descendant of the PossibleParent + * @return true if this widget is a child of the PossibleParent + */ + UFUNCTION(Category = "Victory BP Library|UMG", BlueprintCallable, BlueprintCosmetic, Meta = (DefaultToSelf = "ChildWidget")) + static bool WidgetIsChildOf(UWidget* ChildWidget, UWidget* PossibleParent); + + /** + * Recurses up the list of parents until it finds a widget of WidgetClass. + * @return widget that is Parent of ChildWidget that matches WidgetClass. + */ + UFUNCTION(Category = "Victory BP Library|UMG", BlueprintCallable, BlueprintCosmetic, Meta = (DefaultToSelf = "ChildWidget", DeterminesOutputType = "WidgetClass")) + static UUserWidget* WidgetGetParentOfClass(UWidget* ChildWidget, TSubclassOf WidgetClass); + + UFUNCTION(Category = "Victory BP Library|UMG", BlueprintCallable, BlueprintCosmetic, Meta = (DefaultToSelf = "ParentWidget", DeterminesOutputType = "WidgetClass", DynamicOutputParam = "ChildWidgets")) + static void WidgetGetChildrenOfClass(UWidget* ParentWidget, TArray& ChildWidgets, TSubclassOf WidgetClass, bool bImmediateOnly); + + UFUNCTION(Category = "Victory BP Library|UMG", BlueprintCallable, BlueprintCosmetic, Meta = (DefaultToSelf = "ParentUserWidget")) + static UWidget* GetWidgetFromName(UUserWidget* ParentUserWidget, const FName& Name); + + UFUNCTION(Category = "Victory BP Library|Team", BlueprintPure) + static uint8 GetGenericTeamId(AActor* Target); + + UFUNCTION(Category = "Victory BP Library|Team", BlueprintCallable) + static void SetGenericTeamId(AActor* Target, uint8 NewTeamId); + + UFUNCTION(Category = "Victory BP Library|LevelStreaming", BlueprintCallable) + static FLevelStreamInstanceInfo GetLevelInstanceInfo(ULevelStreamingDynamic* LevelInstance); + + UFUNCTION(Category = "Victory BP Library|LevelStreaming", BlueprintCallable, Meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static void AddToStreamingLevels(UObject* WorldContextObject, const FLevelStreamInstanceInfo& LevelInstanceInfo); + + UFUNCTION(Category = "Victory BP Library|LevelStreaming", BlueprintCallable, Meta = (HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) + static void RemoveFromStreamingLevels(UObject* WorldContextObject, const FLevelStreamInstanceInfo& LevelInstanceInfo); + + UFUNCTION(Category = "Victory BP Library|LevelStreaming", BlueprintCallable, Meta = (keywords="remove")) + static void HideStreamingLevel(ULevelStreamingDynamic* LevelInstance) + { + if(LevelInstance) LevelInstance->SetShouldBeVisible(false); + } + + UFUNCTION(Category = "Victory BP Library|LevelStreaming", BlueprintCallable, Meta = (keywords="remove")) + static void UnloadStreamingLevel(ULevelStreamingDynamic* LevelInstance) + { + if(LevelInstance) LevelInstance->SetShouldBeLoaded(false); + } + + static bool GenericArray_SortCompare(const FProperty* LeftProperty, void* LeftValuePtr, const FProperty* RightProperty, void* RightValuePtr); + + /** + * Sort the elements of an array by FString, FName, FText, float, int or boolean. + * Supports struct and object based arrays. + * + * @param TargetArray The array to sort. + * @param bAscendingOrder If true, sort by ascending order. + * @param VariableName If a struct or object based array, the name of the variable to sort by. + */ + UFUNCTION(Category = "Victory BP Library|Utilities|Array", BlueprintCallable, CustomThunk, Meta = (DisplayName = "Sort", ArrayParm = "TargetArray", AdvancedDisplay = "bAscendingOrder,VariableName")) + static void Array_Sort(const TArray& TargetArray, bool bAscendingOrder = true, FName VariableName = NAME_None); + + static void GenericArray_Sort(void* TargetArray, const FArrayProperty* ArrayProp, bool bAscendingOrder = true, FName VariableName = NAME_None); + + DECLARE_FUNCTION(execArray_Sort) + { + Stack.MostRecentProperty = nullptr; + Stack.StepCompiledIn(NULL); + void* ArrayAddr = Stack.MostRecentPropertyAddress; + FArrayProperty* ArrayProperty = Cast(Stack.MostRecentProperty); + if (!ArrayProperty) + { + Stack.bArrayContextFailed = true; + return; + } + + P_GET_UBOOL(bAscendingOrder); + + P_GET_PROPERTY(FNameProperty, VariableName); + + P_FINISH; + P_NATIVE_BEGIN; + GenericArray_Sort(ArrayAddr, ArrayProperty, bAscendingOrder, VariableName); + P_NATIVE_END; + } + + /** + * Calls PrestreamTextures() for all the actor's meshcomponents. + * PrestreamTextures() tells the streaming system to start loading all textures with all mip-levels. + * @param Seconds - Number of seconds to force all mip-levels to be resident + * @param bEnableStreaming - Whether to start (true) or stop (false) streaming + * @param CinematicTextureGroups - Bitfield indicating which texture groups that use extra high-resolution mips + */ + UFUNCTION(Category = "Victory BP Library|Actor", BlueprintCallable, Meta = (DisplayName = "PrestreamTextures (Actor)")) + static void Actor_PrestreamTextures(AActor* Target, float Seconds = 1.0f, bool bEnableStreaming = true, int32 CinematicTextureGroups = 0); + + /** + * Tells the streaming system to start loading all textures with all mip-levels. + * @param Seconds - Number of seconds to force all mip-levels to be resident + * @param bEnableStreaming - Whether to start (true) or stop (false) streaming + * @param CinematicTextureGroups - Bitfield indicating which texture groups that use extra high-resolution mips + */ + UFUNCTION(Category = "Victory BP Library|Components", BlueprintCallable, Meta = (DisplayName = "PrestreamTextures (Component)")) + static void Component_PrestreamTextures(UMeshComponent* Target, float Seconds = 1.0f, bool bEnableStreaming = true, int32 CinematicTextureGroups = 0); + + /** + * Converts the screen position (primary screen's top left corner) supplied by pointer events or similar + * to the local space of viewport related to WorldContextObject. + * + * @param WorldContextObject World context. + * @param ScreenPosition Coordinates from FPointerEvent GetScreenSpacePosition() or similar. + * @param OutViewportPosition Coordinates based on the local viewport (fullscreen or otherwise). + * + * @return True if OutViewportPosition is not 0,0. + */ + UFUNCTION(Category = "Victory BP Library|Game|Viewport", BlueprintCallable, meta=(WorldContext="WorldContextObject")) + static bool GetViewportPosition(UObject* WorldContextObject, const FVector2D& ScreenPosition, FVector2D& OutViewportPosition); + + /** + * Does a line collision trace based the viewport position and returns the first blocking hit encountered. + * This trace finds the objects that RESPOND to the given TraceChannel + * + * @param WorldContextObject World context. + * @param ViewportPosition Local space of viewport from GetViewportPosition() or similar. + * @param TraceChannel + * @param bTraceComplex True to test against complex collision, false to test against simplified collision. + * @param OutHitResult Properties of the trace hit. + * + * @return True if there was a hit, false otherwise. + */ + UFUNCTION(Category = "Victory BP Library|Game|Viewport", BlueprintCallable, Meta = (WorldContext="WorldContextObject", bTraceComplex = true, TraceChannel = ECC_Visibility)) + static bool GetViewportPositionHitResultByChannel(UObject* WorldContextObject, const FVector2D& ViewportPosition, ECollisionChannel TraceChannel, bool bTraceComplex, FHitResult& OutHitResult); + + /** + * Transforms the viewport position into a world space origin and direction. + * + * @param WorldContextObject World context. + * @param ViewportPosition Local space of viewport from GetViewportPosition() or similar. + * @param OutWorldOrigin Corresponding 3D location in world space. + * @param OutWorldDirection World space direction vector away from the camera at the given 2d point. + * + * @return false if something went wrong during the deproject process. + */ + UFUNCTION(Category = "Victory BP Library|Game|Viewport", BlueprintCallable, Meta = (WorldContext="WorldContextObject")) + static bool ViewportPositionDeproject(UObject* WorldContextObject, const FVector2D& ViewportPosition, FVector& OutWorldOrigin, FVector& OutWorldDirection); + + /** + * Inserts child widget into panel widget at given location. + * NOTE: The child widgets "Construct" event will be fired again! + * + * @param Parent - The panel to insert the child into. + * @param Index - Where to insert the new widget. + * @param Content - The child widget to insert. + * @return slot assigned to content. + */ + UFUNCTION(Category = "Victory BP Library|Widget|Panel", BlueprintCallable) + static class UPanelSlot* InsertChildAt(class UWidget* Parent, int32 Index, UWidget* Content); + + /** Flushes the current key state for target player controller. */ + UFUNCTION(Category = "Victory BP Library|Input", BlueprintCallable) + static void FlushPressedKeys(class APlayerController* PlayerController); + + UFUNCTION(Category = "Victory BP Library|Vector", BlueprintPure) + static FVector GetVectorRelativeLocation(FVector ParentLocation, FRotator ParentRotation, FVector ChildLocation); + + UFUNCTION(Category = "Victory BP Library|Components", BlueprintPure, Meta = (DefaultToSelf = "ChildComponent")) + static FVector GetComponentRelativeLocation(class USceneComponent* ParentComponent, class USceneComponent* ChildComponent); + + UFUNCTION(Category = "Victory BP Library|Actor", BlueprintPure, Meta = (DefaultToSelf = "ChildActor")) + static FVector GetActorRelativeLocation(class AActor* ParentActor, class AActor* ChildActor); + + UFUNCTION(Category = "Victory BP Library|Rotator", BlueprintPure) + static FRotator GetRotatorRelativeRotation(FRotator ParentRotation, FRotator ChildRotation); + + UFUNCTION(Category = "Victory BP Library|Components", BlueprintPure, Meta = (DefaultToSelf = "ChildComponent")) + static FRotator GetComponentRelativeRotation(class USceneComponent* ParentComponent, class USceneComponent* ChildComponent); + + UFUNCTION(Category = "Victory BP Library|Actor", BlueprintPure, Meta = (DefaultToSelf = "ChildActor")) + static FRotator GetActorRelativeRotation(class AActor* ParentActor, class AActor* ChildActor); + + /** + * Helper function to calculate vertical FOV from horizontal FOV and aspect ratio. + * Useful to for determining distance from camera fit in-game objects to the width of the screen. + */ + UFUNCTION(Category = "Victory BP Library|Game|Viewport", BlueprintPure) + static float HorizontalFOV(float VerticalFOV, float AspectRatio); + + /** + * Helper function to calculate vertical FOV from horizontal FOV and aspect ratio. + * Useful to for determining distance from camera fit in-game objects to the height of the screen. + */ + UFUNCTION(Category = "Victory BP Library|Game|Viewport", BlueprintPure) + static float VerticalFOV(float HorizontalFOV, float AspectRatio); + + UFUNCTION(Category = "Victory BP Library|Utilities|String", BlueprintPure, Meta = (DisplayName = "IsEmpty")) + static bool StringIsEmpty(const FString& Target); + +//~~~~~~~~~ + +//~~~ KeyToTruth ~~~ + +//.h +/* Addition of strings (A + B) with pins. Contributed by KeyToTruth */ +UFUNCTION(BlueprintPure, meta = (DisplayName = "Append Multiple", Keywords = "concatenate combine append strings", CommutativeAssociativeBinaryOperator = "true"), Category = "Victory BP Library|String") +static FString AppendMultiple(FString A, FString B); + +//~~~ Mhousse ~~~ + +}; + diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryBPHTML.h b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryBPHTML.h new file mode 100644 index 00000000..a28167c6 --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryBPHTML.h @@ -0,0 +1,31 @@ +/* + + By Rama + +*/ +#pragma once + +#include "Runtime/Engine/Classes/Kismet/BlueprintFunctionLibrary.h" +#include "VictoryBPHTML.generated.h" + + +//!! Can someone submit HTML5 update to Victory Git? + +UCLASS() +class VICTORYBPLIBRARY_API UVictoryBPHTML : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() +public: + + /** Is the current OS HTML5? This code will only run in games packaged for HTML5, it will not run in Editor builds :) Use this to customize particle FX for HTML5 vs PC builds! Or for any custom HTML5-specific game logic! <3 Rama*/ + /* + UFUNCTION(BlueprintPure, Category = "Victory BP Library|HTML5") + static bool IsHTML(); + */ + + /* + UFUNCTION(BlueprintCallable, Category = "Victory BP Library|HTML5") + static void VictoryHTML5_SetCursorVisible(bool MakeVisible); + */ +}; + diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryBPLibrary.h b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryBPLibrary.h new file mode 100644 index 00000000..ef198955 --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryBPLibrary.h @@ -0,0 +1,17 @@ +/* + By Rama +*/ +#pragma once + +#include "CoreMinimal.h" +#include "Modules/ModuleInterface.h" +#include "Modules/ModuleManager.h" + +class FVictoryBPLibraryModule : public IModuleInterface +{ +public: + + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; \ No newline at end of file diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryISM.cpp b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryISM.cpp new file mode 100644 index 00000000..92a0fdca --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryISM.cpp @@ -0,0 +1,24 @@ +/* + + By Rama + +*/ +#include "VictoryBPLibraryPrivatePCH.h" +#include "VictoryISM.h" + +////////////////////////////////////////////////////////////////////////// +// VictoryISM + +AVictoryISM::AVictoryISM(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + RootComponent = Mesh = ObjectInitializer.CreateDefaultSubobject(this, "VictoryInstancedMesh"); +} + +void AVictoryISM::BeginPlay() +{ + Super::BeginPlay(); + //~~~~~~~~~ + + +} \ No newline at end of file diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryISM.h b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryISM.h new file mode 100644 index 00000000..a60f437e --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryISM.h @@ -0,0 +1,30 @@ +/* + + By Rama + +*/ + +#pragma once + +#include "Runtime/Engine/Classes/Components/InstancedStaticMeshComponent.h" +#include "VictoryISM.generated.h" + +UCLASS() +class AVictoryISM : public AActor +{ + GENERATED_BODY() +public: + + AVictoryISM(const FObjectInitializer& ObjectInitializer); + + UPROPERTY(Category = "Joy ISM", VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) + UInstancedStaticMeshComponent* Mesh; + +//~~~~~~~~~~~~~ +// ISM +//~~~~~~~~~~~~~ +public: + virtual void BeginPlay() override; + +}; + diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryPC.cpp b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryPC.cpp new file mode 100644 index 00000000..c629cb8f --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryPC.cpp @@ -0,0 +1,104 @@ +/* + + By Rama + +*/ + +#include "VictoryBPLibraryPrivatePCH.h" +#include "VictoryPC.h" + +#include "Runtime/Engine/Classes/Kismet/GameplayStatics.h" + +DEFINE_LOG_CATEGORY(VictoryPCLog) + +////////////////////////////////////////////////////////////////////////// +// AVictoryPC + +AVictoryPC::AVictoryPC(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + +} + + +UAudioComponent* AVictoryPC::VictoryPlaySpeechSound( + USoundBase* Sound + ,float VolumeMultiplier + ,float PitchMultiplier + , float StartTime) +{ + + UAudioComponent* Audio = UGameplayStatics::SpawnSound2D(this,Sound,VolumeMultiplier,PitchMultiplier,StartTime); + if(Audio) + { + //Subtitle Delegate for You! + // <3 Rama + Audio->OnQueueSubtitles.BindDynamic(this, &AVictoryPC::Subtitles_CPPDelegate); + } + + /* + Note that the OnAudioFinished is BP assignable off of return of this node! + + //called when we finish playing audio, either because it played to completion or because a Stop() call turned it off early + UPROPERTY(BlueprintAssignable) + FOnAudioFinished OnAudioFinished; + */ + + return Audio; +} + +void AVictoryPC::Subtitles_CPPDelegate(const TArray& Subtitles, float CueDuration) +{ + TArray VictorySubtitles; + for(const FSubtitleCue& Each : Subtitles) + { + VictorySubtitles.Add(FVictorySubtitleCue(Each.Text,Each.Time)); + } + + OnVictorySubtitlesQueued(VictorySubtitles,CueDuration); +} + +//~~~ + +bool AVictoryPC::VictoryPC_GetMyIP_SendRequest() +{ + FHttpModule* Http = &FHttpModule::Get(); + + if(!Http) + { + return false; + } + + if(!Http->IsHttpEnabled()) + { + return false; + } + //~~~~~~~~~~~~~~~~~~~ + + FString TargetHost = "http://api.ipify.org"; + TSharedRef < IHttpRequest > Request = Http->CreateRequest(); + Request->SetVerb("GET"); + Request->SetURL(TargetHost); + Request->SetHeader("User-Agent", "VictoryBPLibrary/1.0"); + Request->SetHeader("Content-Type" ,"text/html"); + + Request->OnProcessRequestComplete().BindUObject(this, &AVictoryPC::HTTPOnResponseReceived); + if (!Request->ProcessRequest()) + { + return false; + } + + return true; +} + +void AVictoryPC::HTTPOnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful) +{ + FString ResponseStr = "AVictoryPC::HTTPOnResponseReceived>>> Connection Error"; + if(bWasSuccessful) + { + ResponseStr = Response->GetContentAsString(); + } + + this->VictoryPC_GetMyIP_DataReceived(ResponseStr); +} + \ No newline at end of file diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryPC.h b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryPC.h new file mode 100644 index 00000000..2eca2f20 --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryPC.h @@ -0,0 +1,72 @@ +/* + + By Rama + +*/ +#pragma once + +//HTTP +#include "Http.h" + +#include "Runtime/Engine/Classes/GameFramework/PlayerController.h" +#include "VictoryPC.generated.h" + +DECLARE_LOG_CATEGORY_EXTERN(VictoryPCLog, Log, All); + + +//Exposing the UE4 Subtitle system for Solus +// <3 Rama +USTRUCT(BlueprintType) +struct FVictorySubtitleCue +{ + GENERATED_USTRUCT_BODY() + + /** The text to appear in the subtitle. */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=SubtitleCue) + FText SubtitleText; + + /** The time at which the subtitle is to be displayed, in seconds relative to the beginning of the line. */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=SubtitleCue) + float Time; + + FVictorySubtitleCue() + : Time(0) + { } + FVictorySubtitleCue(const FText& InText, float InTime) + : SubtitleText(InText) + , Time(InTime) + {} +}; + +UCLASS() +class VICTORYBPLIBRARY_API AVictoryPC : public APlayerController +{ + GENERATED_BODY() + +public: + AVictoryPC(const FObjectInitializer& ObjectInitializer); + + /** + * When the sound is played OnVictorySubtitlesQueued will be called with the subtitles! + * You can bind an event off of the audio component for OnAudioFinished to know hwen the sound is done! + */ + UFUNCTION(Category="Victory Subtitles", BlueprintCallable, BlueprintCosmetic, meta=( UnsafeDuringActorConstruction = "true", Keywords = "play" )) + UAudioComponent* VictoryPlaySpeechSound(class USoundBase* Sound, float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f); + + UFUNCTION(Category="Victory Subtitles", BlueprintImplementableEvent) + void OnVictorySubtitlesQueued(const TArray& VictorySubtitles, float CueDuration); + + UFUNCTION() + void Subtitles_CPPDelegate(const TArray& VictorySubtitles, float CueDuration); + +public: + /** This node relies on http://api.ipify.org, so if this node ever stops working, check out http://api.ipify.org. Returns false if the operation could not occur because HTTP module was not loaded or unable to process request. */ + UFUNCTION(BlueprintCallable, Category="Victory PC") + bool VictoryPC_GetMyIP_SendRequest(); + + /** Implement this event to receive your IP once the request is processed! This requires that your computer has a live internet connection */ + UFUNCTION(BlueprintImplementableEvent, Category = "Victory PC", meta = (DisplayName = "Victory PC ~ GetMyIP ~ Data Received!")) + void VictoryPC_GetMyIP_DataReceived(const FString& YourIP); + + void HTTPOnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful); +}; diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryTMapComp.cpp b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryTMapComp.cpp new file mode 100644 index 00000000..ebf008fc --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryTMapComp.cpp @@ -0,0 +1,201 @@ +/* + + By Rama + +*/ + +#include "VictoryBPLibraryPrivatePCH.h" +#include "VictoryTMapComp.h" + +DEFINE_LOG_CATEGORY(VictoryTMapLog) + +////////////////////////////////////////////////////////////////////////// +// UVictoryTMapComp + +UVictoryTMapComp::UVictoryTMapComp(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + +} + +//~~~ Add ~~~ +void UVictoryTMapComp::String_Actor__AddPair(FString Key, AActor* Value) +{ + StringActor.Add(Key,Value); +} + +void UVictoryTMapComp::String_String__AddPair(FString Key, FString Value) +{ + StringString.Add(Key,Value); +} + +void UVictoryTMapComp::String_Int__AddPair(FString Key, int32 Value) +{ + StringInt.Add(Key,Value); +} + +void UVictoryTMapComp::String_Vector__AddPair(FString Key, FVector Value) +{ + StringVector.Add(Key,Value); +} +void UVictoryTMapComp::String_Rotator__AddPair(FString Key, FRotator Value) +{ + StringRotator.Add(Key,Value); +} + +void UVictoryTMapComp::Int_Vector__AddPair(int32 Key, FVector Value) +{ + IntVector.Add(Key,Value); +} + +void UVictoryTMapComp::Int_Float__AddPair(int32 Key, float Value) +{ + IntFloat.Add(Key,Value); +} + +//~~~ Get ~~~ +AActor* UVictoryTMapComp::String_Actor__Get(FString Key, bool& IsValid) +{ + IsValid = false; + if(!StringActor.Contains(Key)) + { + return nullptr; + } + IsValid = true; + return StringActor[Key]; +} + +FString UVictoryTMapComp::String_String__Get(FString Key, bool& IsValid) +{ + IsValid = false; + if(!StringString.Contains(Key)) + { + return ""; + } + IsValid = true; + return StringString[Key]; +} + +int32 UVictoryTMapComp::String_Int__Get(FString Key, bool& IsValid) +{ + IsValid = false; + if(!StringInt.Contains(Key)) + { + return 0; + } + IsValid = true; + return StringInt[Key]; +} + +FVector UVictoryTMapComp::String_Vector__Get(FString Key, bool& IsValid) +{ + IsValid = false; + if(!StringVector.Contains(Key)) + { + return FVector::ZeroVector; + } + IsValid = true; + return StringVector[Key]; +} +FRotator UVictoryTMapComp::String_Rotator__Get(FString Key, bool& IsValid) +{ + IsValid = false; + if(!StringRotator.Contains(Key)) + { + return FRotator::ZeroRotator; + } + IsValid = true; + return StringRotator[Key]; +} + +FVector UVictoryTMapComp::Int_Vector__Get(int32 Key, bool& IsValid) +{ + IsValid = false; + if(!IntVector.Contains(Key)) + { + return FVector::ZeroVector; + } + IsValid = true; + return IntVector[Key]; +} + +float UVictoryTMapComp::Int_Float__Get(int32 Key, bool& IsValid) +{ + IsValid = false; + if(!IntFloat.Contains(Key)) + { + return -1; + } + IsValid = true; + return IntFloat[Key]; +} + +//~~~ Remove ~~~ +void UVictoryTMapComp::String_Actor__Remove(FString Key) +{ + StringActor.Remove(Key); +} + +void UVictoryTMapComp::String_String__Remove(FString Key) +{ + StringString.Remove(Key); +} + +void UVictoryTMapComp::String_Int__Remove(FString Key) +{ + StringInt.Remove(Key); +} + +void UVictoryTMapComp::String_Vector__Remove(FString Key) +{ + StringVector.Remove(Key); +} +void UVictoryTMapComp::String_Rotator__Remove(FString Key) +{ + StringRotator.Remove(Key); +} + +void UVictoryTMapComp::Int_Vector__Remove(int32 Key) +{ + IntVector.Remove(Key); +} + +void UVictoryTMapComp::Int_Float__Remove(int32 Key, float Value) +{ + IntFloat.Remove(Key); +} + +//~~~ Clear ~~~ +void UVictoryTMapComp::String_Actor__Clear() +{ + StringActor.Empty(); +} + +void UVictoryTMapComp::String_String__Clear() +{ + StringString.Empty(); +} + +void UVictoryTMapComp::String_Int__Clear() +{ + StringInt.Empty(); +} + +void UVictoryTMapComp::String_Vector__Clear() +{ + StringVector.Empty(); +} +void UVictoryTMapComp::String_Rotator__Clear() +{ + StringRotator.Empty(); +} + +void UVictoryTMapComp::Int_Vector__Clear() +{ + IntVector.Empty(); +} + +void UVictoryTMapComp::Int_Float__Clear() +{ + IntFloat.Empty(); +} diff --git a/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryTMapComp.h b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryTMapComp.h new file mode 100644 index 00000000..a805a15a --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/Public/VictoryTMapComp.h @@ -0,0 +1,148 @@ +/* + + By Rama + +*/ +#pragma once + +#include "VictoryTMapComp.generated.h" + +DECLARE_LOG_CATEGORY_EXTERN(VictoryTMapLog, Log, All); + +UCLASS(ClassGroup=VictoryBPLibrary, meta=(BlueprintSpawnableComponent)) +class UVictoryTMapComp : public UActorComponent +{ + GENERATED_BODY() +public: + UVictoryTMapComp(const FObjectInitializer& ObjectInitializer); + +//Add +public: + /** If a key already exists in the TMap, its current value is replaced with your new value! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Add") + void String_Actor__AddPair(FString Key, AActor* Value); + + /** If a key already exists in the TMap, its current value is replaced with your new value! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Add") + void String_String__AddPair(FString Key, FString Value); + + /** If a key already exists in the TMap, its current value is replaced with your new value! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Add") + void String_Int__AddPair(FString Key, int32 Value); + + /** If a key already exists in the TMap, its current value is replaced with your new value! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Add") + void String_Vector__AddPair(FString Key, FVector Value); + + /** If a key already exists in the TMap, its current value is replaced with your new value! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Add") + void String_Rotator__AddPair(FString Key, FRotator Value); + + /** If a key already exists in the TMap, its current value is replaced with your new value! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Add") + void Int_Vector__AddPair(int32 Key, FVector Value); + + /** If a key already exists in the TMap, its current value is replaced with your new value! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Add") + void Int_Float__AddPair(int32 Key, float Value); + +//Get +public: + /** Get the value associated with they key at fastest possible speed! <3 Rama */ + UFUNCTION(BlueprintPure,Category="Victory BP Library|TMap Component|Get") + AActor* String_Actor__Get(FString Key, bool& IsValid); + + /** Get the value associated with they key at fastest possible speed! <3 Rama */ + UFUNCTION(BlueprintPure,Category="Victory BP Library|TMap Component|Get") + FString String_String__Get(FString Key, bool& IsValid); + + /** Get the value associated with they key at fastest possible speed! <3 Rama */ + UFUNCTION(BlueprintPure,Category="Victory BP Library|TMap Component|Get") + int32 String_Int__Get(FString Key, bool& IsValid); + + /** Get the value associated with they key at fastest possible speed! <3 Rama */ + UFUNCTION(BlueprintPure,Category="Victory BP Library|TMap Component|Get") + FVector String_Vector__Get(FString Key, bool& IsValid); + + /** Get the value associated with they key at fastest possible speed! <3 Rama */ + UFUNCTION(BlueprintPure,Category="Victory BP Library|TMap Component|Get") + FRotator String_Rotator__Get(FString Key, bool& IsValid); + + /** Get the value associated with they key at fastest possible speed! <3 Rama */ + UFUNCTION(BlueprintPure,Category="Victory BP Library|TMap Component|Get") + FVector Int_Vector__Get(int32 Key, bool& IsValid); + + /** Get the value associated with they key at fastest possible speed! <3 Rama */ + UFUNCTION(BlueprintPure,Category="Victory BP Library|TMap Component|Get") + float Int_Float__Get(int32 Key, bool& IsValid); + +//Remove +public: + /** Removes the key and any associated value from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Remove") + void String_Actor__Remove(FString Key); + + /** Removes the key and any associated value from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Remove") + void String_String__Remove(FString Key); + + /** Removes the key and any associated value from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Remove") + void String_Int__Remove(FString Key); + + /** Removes the key and any associated value from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Remove") + void String_Vector__Remove(FString Key); + + /** Removes the key and any associated value from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Remove") + void String_Rotator__Remove(FString Key); + + /** Removes the key and any associated value from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Remove") + void Int_Vector__Remove(int32 Key); + + /** Removes the key and any associated value from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Remove") + void Int_Float__Remove(int32 Key, float Value); + +//Clear +public: + /** Removes every entry from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Clear", meta = (Keywords = "Clear Empty Reset")) + void String_Actor__Clear(); + + /** Removes every entry from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Clear", meta = (Keywords = "Clear Empty Reset")) + void String_String__Clear(); + + /** Removes every entry from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Clear", meta = (Keywords = "Clear Empty Reset")) + void String_Int__Clear(); + + /** Removes every entry from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Clear", meta = (Keywords = "Clear Empty Reset")) + void String_Vector__Clear(); + + /** Removes every entry from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Clear", meta = (Keywords = "Clear Empty Reset")) + void String_Rotator__Clear(); + + /** Removes every entry from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Clear", meta = (Keywords = "Clear Empty Reset")) + void Int_Vector__Clear(); + + /** Removes every entry from the TMap! <3 Rama */ + UFUNCTION(BlueprintCallable,Category="Victory BP Library|TMap Component|Clear", meta = (Keywords = "Clear Empty Reset")) + void Int_Float__Clear(); + +public: + TMap StringActor; + TMap StringString; + TMap StringInt; + TMap StringVector; + TMap StringRotator; + TMap IntVector; + TMap IntFloat; + +}; \ No newline at end of file diff --git a/Plugins/Victory/Source/VictoryBPLibrary/VictoryBPLibrary.Build.cs b/Plugins/Victory/Source/VictoryBPLibrary/VictoryBPLibrary.Build.cs new file mode 100644 index 00000000..4ce49d10 --- /dev/null +++ b/Plugins/Victory/Source/VictoryBPLibrary/VictoryBPLibrary.Build.cs @@ -0,0 +1,104 @@ +// Some copyright should be here... + +using UnrealBuildTool; + +public class VictoryBPLibrary : ModuleRules +{ + public VictoryBPLibrary(ReadOnlyTargetRules Target) : base(Target) + { + //Get rid of debug commandline length compile error + //https://developercommunity.visualstudio.com/content/problem/668411/command-line-error-d8049-still-happening.html + bLegacyPublicIncludePaths = false; + + PrivatePCHHeaderFile = "Private/VictoryBPLibraryPrivatePCH.h"; + + //4.15 Include What You Use + bEnforceIWYU = false; + + PublicIncludePaths.AddRange( + new string[] { + "VictoryBPLibrary/Public" + + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + "VictoryBPLibrary/Private", + + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core" + + // ... add other public dependencies that you statically link with here ... + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "InputCore", + + "RHI", + "RenderCore", + + "HTTP", + "UMG", "Slate", "SlateCore", + + "ImageWrapper", + + "PhysicsCore", + "PhysX", + + "HeadMountedDisplay", + + "AIModule", + + "NavigationSystem", + + "Vorbis", + + //FPlatformApplicationMisc + "ApplicationCore" + } + ); + + //APEX EXCLUSIONS + if (Target.Platform != UnrealTargetPlatform.Android && Target.Platform != UnrealTargetPlatform.IOS) + { + PrivateDependencyModuleNames.AddRange( + new string[] + { + "APEX" + } + ); + + PublicDependencyModuleNames.AddRange( + new string[] + { + "ApexDestruction" + } + ); + + } + + + DynamicallyLoadedModuleNames.AddRange( + new string[] + { + // ... add any modules that your module loads dynamically here ... + } + ); + } +} diff --git a/Plugins/Victory/VictoryBPLibrary.uplugin b/Plugins/Victory/VictoryBPLibrary.uplugin new file mode 100644 index 00000000..d56cbed1 --- /dev/null +++ b/Plugins/Victory/VictoryBPLibrary.uplugin @@ -0,0 +1,33 @@ +{ + "FileVersion": 3, + "Version": 1, + "VersionName": "1.0", + "FriendlyName": "Victory Plugin", + "Description": "120+ Custom Blueprint Nodes For You! <3 Rama", + "Category": "Rama", + "CreatedBy": "Rama", + "CreatedByURL": "http://www.ue4code.com", + "DocsURL": "http://www.ue4code.com", + "MarketplaceURL": "http://www.ue4code.com", + "SupportURL": "http://www.ue4code.com", + "EngineVersion": "4.25.0", + "CanContainContent": false, + "Installed": true, + "Modules": [ + { + "Name": "VictoryBPLibrary", + "Type": "Runtime", + "LoadingPhase": "PreDefault", + "WhitelistPlatforms": [ + "Win64", + "Win32" + ] + } + ], + "Plugins": [ + { + "Name": "ApexDestruction", + "Enabled": true + } + ] +} \ No newline at end of file