/* By Rama */ #include "VictoryBPLibraryPrivatePCH.h" #include "VictoryBPFunctionLibrary.h" //Foreground Window check, clipboard copy/paste #include "Runtime/ApplicationCore/Public/HAL/PlatformApplicationMisc.h" //FGPUDriverInfo GPU #include "Runtime/Core/Public/GenericPlatform/GenericPlatformDriver.h" //MD5 Hash #include "Runtime/Core/Public/Misc/SecureHash.h" #include "StaticMeshResources.h" #include "HeadMountedDisplay.h" #include "GenericTeamAgentInterface.h" //For PIE error messages #include "MessageLog.h" #define LOCTEXT_NAMESPACE "Fun BP Lib" //Use MessasgeLog like this: (see GameplayStatics.cpp /* #if WITH_EDITOR FMessageLog("PIE").Error(FText::Format(LOCTEXT("SpawnObjectWrongClass", "SpawnObject wrong class: {0}'"), FText::FromString(GetNameSafe(*ObjectClass)))); #endif // WITH_EDITOR */ // To be able to perform regex operatins on level stream info package name #if WITH_EDITOR #include "Runtime/Core/Public/Internationalization/Regex.h" #endif //~~~ Image Wrapper ~~~ #include "ImageUtils.h" #include "IImageWrapper.h" #include "IImageWrapperModule.h" //~~~ Image Wrapper ~~~ //Body Setup #include "PhysicsEngine/BodySetup.h" #include "DestructibleComponent.h" //Apex issues, can add iOS here <3 Rama #if PLATFORM_ANDROID || PLATFORM_HTML5 || PLATFORM_IOS #ifdef WITH_APEX #undef WITH_APEX #endif #define WITH_APEX 0 #endif //APEX EXCLUSIONS //~~~ PhysX ~~~ #include "PhysXIncludes.h" #include "PhysXPublic.h" //For the ptou conversions //For Scene Locking using Epic's awesome helper macros like SCOPED_SCENE_READ_LOCK #include "Runtime/Engine/Private/PhysicsEngine/PhysXSupport.h" //~~~~~~~~~~~ #include "IXRTrackingSystem.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Saxon Rah Random Nodes // Chrono and Random //Order Matters, // has to be after PhysX includes to avoid isfinite name definition issues #include #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 ){ Success = false; if(!WorldContextObject) return nullptr; UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull); if(!World) return nullptr; //~~~~~~~~~~~ //Full Name FString FullName = "/Game/" + MapFolderOffOfContent + "/" + LevelName; FName LevelFName = FName(*FullName); FString PackageFileName = FullName; ULevelStreamingKismet* StreamingLevel = NewObject(World, ULevelStreamingKismet::StaticClass(), NAME_None, RF_Transient, NULL); if(!StreamingLevel) { return nullptr; } //Long Package Name FString LongLevelPackageName = FPackageName::FilenameToLongPackageName(PackageFileName); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Here is where a unique name is chosen for the new level asset // Ensure unique names to gain ability to have multiple instances of same level! // <3 Rama //Create Unique Name based on BP-supplied instance value FString UniqueLevelPackageName = LongLevelPackageName; UniqueLevelPackageName += "_VictoryInstance_" + FString::FromInt(InstanceNumber); //Set! StreamingLevel->SetWorldAssetByPackageName(FName(*UniqueLevelPackageName)); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (World->IsPlayInEditor()) { FWorldContext WorldContext = GEngine->GetWorldContextFromWorldChecked(World); StreamingLevel->RenameForPIE(WorldContext.PIEInstance); } StreamingLevel->LevelColor = FColor::MakeRandomColor(); StreamingLevel->bShouldBeLoaded = true; StreamingLevel->bShouldBeVisible = true; StreamingLevel->bShouldBlockOnLoad = false; StreamingLevel->bInitiallyLoaded = true; StreamingLevel->bInitiallyVisible = true; //Transform StreamingLevel->LevelTransform = FTransform(Rotation,Location); StreamingLevel->PackageNameToLoad = LevelFName; if (!FPackageName::DoesPackageExist(StreamingLevel->PackageNameToLoad.ToString(), NULL, &PackageFileName)) { return nullptr; } //~~~ //Actual map package to load StreamingLevel->PackageNameToLoad = FName(*LongLevelPackageName); //~~~ // Add the new level to world. World->StreamingLevels.Add(StreamingLevel); Success = true; return StreamingLevel; } //~~~~~~~ // AI //~~~~~~~ EPathFollowingRequestResult::Type UVictoryBPFunctionLibrary::Victory_AI_MoveToWithFilter( APawn* Pawn, const FVector& Dest, TSubclassOf 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 } //~~~ 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->AxisMappings; for(const FInputAxisKeyMapping& Each : Axi) { Bindings.Add(FVictoryInputAxis(Each)); } } void UVictoryBPFunctionLibrary::VictoryRemoveAxisKeyBind(FVictoryInputAxis ToRemove) { //GetMutableDefault UInputSettings* Settings = GetMutableDefault(); if(!Settings) return; TArray& Axi = Settings->AxisMappings; bool Found = false; for(int32 v = 0; v < Axi.Num(); v++) { if(Axi[v].Key == ToRemove.Key) { Found = true; Axi.RemoveAt(v); v = 0; continue; } } if(Found) { //SAVES TO DISK Settings->SaveKeyMappings(); //REBUILDS INPUT, creates modified config in Saved/Config/Windows/Input.ini for (TObjectIterator It; It; ++It) { It->ForceRebuildingKeyMaps(true); } } } void UVictoryBPFunctionLibrary::VictoryGetAllActionKeyBindings(TArray& Bindings) { Bindings.Empty(); const UInputSettings* Settings = GetDefault(); if(!Settings) return; const TArray& Actions = Settings->ActionMappings; for(const FInputActionKeyMapping& Each : Actions) { Bindings.Add(FVictoryInput(Each)); } } void UVictoryBPFunctionLibrary::VictoryRemoveActionKeyBind(FVictoryInput ToRemove) { //GetMutableDefault UInputSettings* Settings = GetMutableDefault(); if(!Settings) return; TArray& Actions = Settings->ActionMappings; bool Found = false; for(int32 v = 0; v < Actions.Num(); v++) { if(Actions[v].Key == ToRemove.Key) { Found = true; Actions.RemoveAt(v); v = 0; continue; } } if(Found) { //SAVES TO DISK Settings->SaveKeyMappings(); //REBUILDS INPUT, creates modified config in Saved/Config/Windows/Input.ini for (TObjectIterator 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->ActionMappings; for(const FInputActionKeyMapping& Each : Actions) { if(Each.Key == Key) { ActionBindings.Add(FVictoryInput(Each)); } } const TArray& Axi = Settings->AxisMappings; for(const FInputAxisKeyMapping& Each : Axi) { if(Each.Key == Key) { AxisBindings.Add(FVictoryInputAxis(Each)); } } } bool UVictoryBPFunctionLibrary::VictoryReBindAxisKey(FVictoryInputAxis Original, FVictoryInputAxis NewBinding) { UInputSettings* Settings = const_cast(GetDefault()); if(!Settings) return false; TArray& Axi = Settings->AxisMappings; //~~~ bool Found = false; for(FInputAxisKeyMapping& Each : Axi) { //Search by original if(Each.AxisName.ToString() == Original.AxisName && Each.Key == Original.Key ){ //Update to new! UVictoryBPFunctionLibrary::UpdateAxisMapping(Each,NewBinding); Found = true; break; } } if(Found) { //SAVES TO DISK const_cast(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 = Settings->ActionMappings; //~~~ bool Found = false; for(FInputActionKeyMapping& Each : Actions) { //Search by original if(Each.ActionName.ToString() == Original.ActionName && Each.Key == Original.Key ){ //Update to new! UVictoryBPFunctionLibrary::UpdateActionMapping(Each,NewBinding); Found = true; break; } } if(Found) { //SAVES TO DISK const_cast(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 bNotifyPlayers) { if(!WorldContextObject) return; UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull); if(!World) return; //~~~~~~~~~~~ World->ServerTravel(MapName,false,bNotifyPlayers); //abs //notify players } APlayerStart* UVictoryBPFunctionLibrary::GetPlayerStart(UObject* WorldContextObject,FString PlayerStartName) { if(!WorldContextObject) return nullptr; UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull); if(!World) return nullptr; //~~~~~~~~~~~ for(TActorIterator 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->PlayerId; } UObject* UVictoryBPFunctionLibrary::CreateObject(UObject* WorldContextObject,UClass* TheObjectClass) { //See deprecation warning // Deprecation warning makes it no longer appear in context menu as a new node to add return nullptr; /* if(!TheObjectClass) return NULL; //~~~~~~~~~~~~~~~~~ //using a context object to get the world! UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull); if(!World) return NULL; //~~~~~~~~~~~ //Need to submit pull request for custom name and custom class both return NewObject(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->StreamingLevels) { if( ! EachLevel) continue; //~~~~~~~~~~~~~~~~ ULevel* LevelPtr = EachLevel->GetLoadedLevel(); //Valid? if(!LevelPtr) continue; if(EachLevel->GetWorldAssetPackageFName() == Level) { FoundLevel = LevelPtr; break; } } //~~~~~~~~~~~~~~~~~~~~~ if(FoundLevel) { SpawnParameters.OverrideLevel = FoundLevel; } //~~~~~~~~~~~~~~~~~~~~~ return World->SpawnActor( ActorClass, &Location, &Rotation, SpawnParameters); } void UVictoryBPFunctionLibrary::GetNamesOfLoadedLevels(UObject* WorldContextObject, TArray& NamesOfLoadedLevels) { //using a context object to get the world! UWorld* const World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull); if(!World) return; //~~~~~~~~~~~ NamesOfLoadedLevels.Empty(); //Get Level from Name! ULevel* FoundLevel = NULL; for(const ULevelStreaming* EachLevel : World->StreamingLevels) { if( ! EachLevel) continue; //~~~~~~~~~~~~~~~~ ULevel* LevelPtr = EachLevel->GetLoadedLevel(); //Valid? if(!LevelPtr) continue; //Is This Level Visible? if(!LevelPtr->bIsVisible) continue; //~~~~~~~~~~~~~~~~~~~ NamesOfLoadedLevels.Add(EachLevel->GetWorldAssetPackageFName().ToString()); } } void UVictoryBPFunctionLibrary::Loops_ResetBPRunawayCounter() { //Reset Runaway loop counter (use carefully) GInitRunaway(); } void UVictoryBPFunctionLibrary::GraphicsSettings__SetFrameRateToBeUnbound() { if(!GEngine) return; //~~~~~~~~~ GEngine->bSmoothFrameRate = 0; } void UVictoryBPFunctionLibrary::GraphicsSettings__SetFrameRateCap(float NewValue) { if(!GEngine) return; //~~~~~~~~~ GEngine->bSmoothFrameRate = 1; GEngine->SmoothedFrameRateRange = FFloatRange(10,NewValue); } FVector2D UVictoryBPFunctionLibrary::ProjectWorldToScreenPosition(const FVector& WorldLocation) { TObjectIterator 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->PlayerId; return true; } void UVictoryBPFunctionLibrary::Open_URL_In_Web_Browser(FString TheURL) { FPlatformProcess::LaunchURL( *TheURL, nullptr, nullptr ); } void UVictoryBPFunctionLibrary::OperatingSystem__GetCurrentPlatform( bool& Windows_, //some weird bug of making it all caps engine-side bool& Mac, bool& Linux, bool& iOS, bool& Android, bool& Android_ARM, bool& Android_Vulkan, bool& PS4, bool& XBoxOne, bool& HTML5, bool& Apple ){ //#define's in UE4 source code Windows_ = PLATFORM_WINDOWS; Mac = PLATFORM_MAC; Linux = PLATFORM_LINUX; PS4 = PLATFORM_PS4; XBoxOne = PLATFORM_XBOXONE; iOS = PLATFORM_IOS; Android = PLATFORM_ANDROID; Android_ARM = PLATFORM_ANDROID_ARM; Android_Vulkan = PLATFORM_ANDROID_VULKAN; HTML5 = PLATFORM_HTML5; Apple = PLATFORM_APPLE; } FString UVictoryBPFunctionLibrary::RealWorldTime__GetCurrentOSTime( int32& MilliSeconds, int32& Seconds, int32& Minutes, int32& Hours12, int32& Hours24, int32& Day, int32& Month, int32& Year ){ const FDateTime Now = FDateTime::Now(); MilliSeconds = Now.GetMillisecond( ); Seconds = Now.GetSecond( ); Minutes = Now.GetMinute( ); Hours12 = Now.GetHour12( ); Hours24 = Now.GetHour( ); //24 Day = Now.GetDay( ); Month = Now.GetMonth( ); Year = Now.GetYear( ); //MS are not included in FDateTime::ToString(), so adding it //The Parse function accepts if MS are present. FString NowWithMS = Now.ToString(); NowWithMS += "." + FString::FromInt(MilliSeconds); return NowWithMS; } void UVictoryBPFunctionLibrary::RealWorldTime__GetTimePassedSincePreviousTime( const FString& PreviousTime, float& Milliseconds, float& Seconds, float& Minutes, float& Hours ){ FDateTime ParsedDateTime; FDateTime::Parse(PreviousTime,ParsedDateTime); const FTimespan TimeDiff = FDateTime::Now() - ParsedDateTime; Milliseconds = TimeDiff.GetTotalMilliseconds( ); Seconds = TimeDiff.GetTotalSeconds( ); Minutes = TimeDiff.GetTotalMinutes( ); Hours = TimeDiff.GetTotalHours( ); } void UVictoryBPFunctionLibrary::RealWorldTime__GetDifferenceBetweenTimes( const FString& PreviousTime1, const FString& PreviousTime2, float& Milliseconds, float& Seconds, float& Minutes, float& Hours ){ FDateTime ParsedDateTime1; FDateTime::Parse(PreviousTime1,ParsedDateTime1); FDateTime ParsedDateTime2; FDateTime::Parse(PreviousTime2,ParsedDateTime2); FTimespan TimeDiff; if(PreviousTime1 < PreviousTime2) { TimeDiff = ParsedDateTime2 - ParsedDateTime1; } else { TimeDiff = ParsedDateTime1 - ParsedDateTime2; } Milliseconds = TimeDiff.GetTotalMilliseconds( ); Seconds = TimeDiff.GetTotalSeconds( ); Minutes = TimeDiff.GetTotalMinutes( ); Hours = TimeDiff.GetTotalHours( ); } void UVictoryBPFunctionLibrary::MaxOfFloatArray(const TArray& 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 ){ if(!FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*SaveDirectory)) { //Could not make the specified directory return false; //~~~~~~~~~~~~~~~~~~~~~~ } //get complete file path SaveDirectory += "\\"; SaveDirectory += JoyfulFileName; //No over-writing? if (!AllowOverWriting) { //Check if file exists already if (FPlatformFileManager::Get().GetPlatformFile().FileExists( * SaveDirectory)) { //no overwriting return false; } } return FFileHelper::SaveStringToFile(SaveText, * SaveDirectory); } bool UVictoryBPFunctionLibrary::FileIO__SaveStringArrayToFile(FString SaveDirectory, FString JoyfulFileName, TArray SaveText, bool AllowOverWriting) { //Dir Exists? if ( !VCreateDirectory(SaveDirectory)) { //Could not make the specified directory return false; //~~~~~~~~~~~~~~~~~~~~~~ } //get complete file path SaveDirectory += "\\"; SaveDirectory += JoyfulFileName; //No over-writing? if (!AllowOverWriting) { //Check if file exists already if (FPlatformFileManager::Get().GetPlatformFile().FileExists( * SaveDirectory)) { //no overwriting return false; } } FString FinalStr = ""; for(FString& Each : SaveText) { FinalStr += Each; FinalStr += LINE_TERMINATOR; } return FFileHelper::SaveStringToFile(FinalStr, * SaveDirectory); } float UVictoryBPFunctionLibrary::Calcs__ClosestPointToSourcePoint(const FVector & Source, const TArray& 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.bTraceAsyncScene = true; TraceParams.bReturnPhysicalMaterial = false; TraceParams.AddIgnoredActor(TraceOwner); //initialize hit info FHitResult RV_Hit(ForceInit); TheWorld->LineTraceSingleByChannel( RV_Hit, //result TraceStart, TraceEnd, ECC_Pawn, //collision channel TraceParams ); //Hit Something! if (!RV_Hit.bBlockingHit) return HitActor; //Character? HitActor = RV_Hit.GetActor(); ACharacter * AsCharacter = Cast(HitActor); if (!AsCharacter) return HitActor; //Mesh if (!AsCharacter->GetMesh()) return HitActor; //Component Trace FHitResult Hit; IsValid = AsCharacter->GetMesh()->K2_LineTraceComponent( TraceStart, TraceEnd, true, false, OutImpactPoint, OutImpactNormal, ClosestBoneName, Hit ); //Location ClosestBoneLocation = AsCharacter->GetMesh()->GetBoneLocation(ClosestBoneName); return HitActor; } AActor* UVictoryBPFunctionLibrary::Traces__CharacterMeshTrace___ClosestSocket( UObject* WorldContextObject, const AActor * TraceOwner, const FVector & TraceStart, const FVector & TraceEnd, FVector & OutImpactPoint, FVector & OutImpactNormal, FName & ClosestSocketName, FVector & SocketLocation, bool & IsValid ) { IsValid = false; AActor * HitActor = NULL; //~~~~~~~~~~~~~~~~~~~~~~ if(!WorldContextObject) return nullptr; UWorld* const TheWorld = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull); if(!TheWorld) return nullptr; //~~~~~~~~~~~ //Simple Trace First FCollisionQueryParams TraceParams(FName(TEXT("VictoryBPTrace::CharacterMeshSocketTrace")), true, HitActor); TraceParams.bTraceComplex = true; TraceParams.bTraceAsyncScene = true; TraceParams.bReturnPhysicalMaterial = false; TraceParams.AddIgnoredActor(TraceOwner); //initialize hit info FHitResult RV_Hit(ForceInit); TheWorld->LineTraceSingleByChannel( RV_Hit, //result TraceStart, TraceEnd, ECC_Pawn, //collision channel TraceParams ); //Hit Something! if (!RV_Hit.bBlockingHit) return HitActor; //Character? HitActor = RV_Hit.GetActor(); ACharacter * AsCharacter = Cast(HitActor); if (!AsCharacter) return HitActor; //Mesh if (!AsCharacter->GetMesh()) return HitActor; //Component Trace FHitResult Hit; FName BoneName; if (! AsCharacter->GetMesh()->K2_LineTraceComponent( TraceStart, TraceEnd, true, false, OutImpactPoint, OutImpactNormal, BoneName, Hit )) return HitActor; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Socket Names TArray 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())) { const TArray* UncompressedBGRA = NULL; if (ImageWrapper->GetRaw(ERGBFormat::BGRA, 8, UncompressedBGRA)) { LoadedT2D = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_B8G8R8A8); //Valid? if(!LoadedT2D) return NULL; //~~~~~~~~~~~~~~ //Out! Width = ImageWrapper->GetWidth(); Height = ImageWrapper->GetHeight(); //Copy! void* TextureData = LoadedT2D->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE); FMemory::Memcpy(TextureData, UncompressedBGRA->GetData(), UncompressedBGRA->Num()); LoadedT2D->PlatformData->Mips[0].BulkData.Unlock(); //Update! LoadedT2D->UpdateResource(); } } // Success! IsValid = true; return LoadedT2D; } UTexture2D* UVictoryBPFunctionLibrary::Victory_LoadTexture2D_FromFile_Pixels(const FString& FullFilePath,EJoyImageFormats ImageFormat,bool& IsValid, int32& Width, int32& Height, TArray& 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())) { const TArray* UncompressedRGBA = NULL; if (ImageWrapper->GetRaw(ERGBFormat::RGBA, 8, UncompressedRGBA)) { LoadedT2D = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_R8G8B8A8); //Valid? if(!LoadedT2D) return NULL; //~~~~~~~~~~~~~~ //Out! Width = ImageWrapper->GetWidth(); Height = ImageWrapper->GetHeight(); const TArray& 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; } T2D->SRGB = false; T2D->CompressionSettings = TC_VectorDisplacementmap; //Update settings T2D->UpdateResource(); FTexture2DMipMap& MipsMap = T2D->PlatformData->Mips[0]; int32 TextureWidth = MipsMap.SizeX; int32 TextureHeight = MipsMap.SizeY; FByteBulkData* RawImageData = &MipsMap.BulkData; if(!RawImageData) { return false; } FColor* RawColorArray = static_cast(RawImageData->Lock(LOCK_READ_ONLY)); //Safety check! if (X >= TextureWidth || Y >= TextureHeight) { return false; } //Get!, converting FColor to FLinearColor PixelColor = RawColorArray[Y * TextureWidth + X]; RawImageData->Unlock(); return true; } bool UVictoryBPFunctionLibrary::Victory_GetPixelsArrayFromT2DDynamic(UTexture2DDynamic* T2D, int32& TextureWidth, int32& TextureHeight,TArray& 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(); */ return true; } bool UVictoryBPFunctionLibrary::Victory_GetPixelsArrayFromT2D(UTexture2D* T2D, int32& TextureWidth, int32& TextureHeight,TArray& PixelArray) { if(!T2D) { return false; } //To prevent overflow in BP if used in a loop PixelArray.Empty(); T2D->SRGB = false; T2D->CompressionSettings = TC_VectorDisplacementmap; //Update settings T2D->UpdateResource(); FTexture2DMipMap& MyMipMap = T2D->PlatformData->Mips[0]; TextureWidth = MyMipMap.SizeX; TextureHeight = MyMipMap.SizeY; FByteBulkData* RawImageData = &MyMipMap.BulkData; if(!RawImageData) { return false; } FColor* RawColorArray = static_cast(RawImageData->Lock(LOCK_READ_ONLY)); for(int32 x = 0; x < TextureWidth; x++) { for(int32 y = 0; y < TextureHeight; y++) { PixelArray.Add(RawColorArray[x * TextureWidth + y]); } } RawImageData->Unlock(); return true; } class UAudioComponent* UVictoryBPFunctionLibrary::PlaySoundAttachedFromFile(const FString& FilePath, class USceneComponent* AttachToComponent, FName AttachPointName, FVector Location, EAttachLocation::Type LocationType, bool bStopWhenAttachedToDestroyed, float VolumeMultiplier, float PitchMultiplier, float StartTime, class USoundAttenuation* AttenuationSettings) { USoundWave* sw = GetSoundWaveFromFile(FilePath); if (!sw) return NULL; return UGameplayStatics::SpawnSoundAttached(sw, AttachToComponent, AttachPointName, Location, LocationType, bStopWhenAttachedToDestroyed, VolumeMultiplier, PitchMultiplier, StartTime, AttenuationSettings); } void UVictoryBPFunctionLibrary::PlaySoundAtLocationFromFile(UObject* WorldContextObject, const FString& FilePath, FVector Location, float VolumeMultiplier, float PitchMultiplier, float StartTime, class USoundAttenuation* AttenuationSettings) { USoundWave* sw = GetSoundWaveFromFile(FilePath); if (!sw) return; UGameplayStatics::PlaySoundAtLocation(WorldContextObject, sw, Location, VolumeMultiplier, PitchMultiplier, StartTime, AttenuationSettings); } class USoundWave* UVictoryBPFunctionLibrary::GetSoundWaveFromFile(const FString& FilePath) { #if PLATFORM_PS4 UE_LOG(LogTemp, Error, TEXT("UVictoryBPFunctionLibrary::GetSoundWaveFromFile ~ vorbis-method not supported on PS4. See UVictoryBPFunctionLibrary::fillSoundWaveInfo")); return nullptr; #else USoundWave* sw = NewObject(USoundWave::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->SampleRate = info.SampleRate; return 0; } int32 UVictoryBPFunctionLibrary::findSource(class USoundWave* sw, class FSoundSource* out_audioSource) { FAudioDevice* device = GEngine ? GEngine->GetMainAudioDevice() : NULL; //gently ask for the audio device FActiveSound* activeSound; FSoundSource* audioSource; FWaveInstance* sw_instance; if (!device) { activeSound = NULL; audioSource = NULL; out_audioSource = audioSource; return -1; } TArray tmpActualSounds = device->GetActiveSounds(); if (tmpActualSounds.Num()) { for (auto activeSoundIt(tmpActualSounds.CreateIterator()); activeSoundIt; ++activeSoundIt) { activeSound = *activeSoundIt; for (auto WaveInstanceIt(activeSound->WaveInstances.CreateIterator()); WaveInstanceIt; ++WaveInstanceIt) { sw_instance = WaveInstanceIt.Value(); if (sw_instance->WaveData->CompressedDataGuid == sw->CompressedDataGuid) { audioSource = device->GetSoundSource(sw_instance); //4.13 onwards, <3 Rama out_audioSource = audioSource; return 0; } } } } audioSource = NULL; activeSound = NULL; out_audioSource = audioSource; return -2; } #endif //PLATFORM_PS4 //~~~ Kris ~~~ bool UVictoryBPFunctionLibrary::Array_IsValidIndex(const TArray& TargetArray, int32 Index) { // We should never hit these! They're stubs to avoid NoExport on the class. Call the Generic* equivalent instead check(0); return false; } bool UVictoryBPFunctionLibrary::GenericArray_IsValidIndex(void* TargetArray, const UArrayProperty* ArrayProp, int32 Index) { bool bResult = false; if (TargetArray) { FScriptArrayHelper ArrayHelper(ArrayProp, TargetArray); bResult = ArrayHelper.IsValidIndex(Index); } return bResult; } float UVictoryBPFunctionLibrary::GetCreationTime(const AActor* Target) { return (Target) ? Target->CreationTime : 0.0f; } float UVictoryBPFunctionLibrary::GetTimeAlive(const AActor* Target) { return (Target) ? (Target->GetWorld()->GetTimeSeconds() - Target->CreationTime) : 0.0f; } bool UVictoryBPFunctionLibrary::CaptureComponent2D_Project(class USceneCaptureComponent2D* Target, FVector Location, FVector2D& OutPixelLocation) { if ((Target == nullptr) || (Target->TextureTarget == nullptr)) { return false; } const FTransform& Transform = Target->GetComponentToWorld(); FMatrix ViewMatrix = Transform.ToInverseMatrixWithScale(); FVector ViewLocation = Transform.GetTranslation(); // swap axis st. x=z,y=x,z=y (unreal coord space) so that z is up ViewMatrix = ViewMatrix * FMatrix( FPlane(0, 0, 1, 0), FPlane(1, 0, 0, 0), FPlane(0, 1, 0, 0), FPlane(0, 0, 0, 1)); const float FOV = Target->FOVAngle * (float)PI / 360.0f; FIntPoint CaptureSize(Target->TextureTarget->GetSurfaceWidth(), Target->TextureTarget->GetSurfaceHeight()); float XAxisMultiplier; float YAxisMultiplier; if (CaptureSize.X > CaptureSize.Y) { // if the viewport is wider than it is tall XAxisMultiplier = 1.0f; YAxisMultiplier = CaptureSize.X / (float)CaptureSize.Y; } else { // if the viewport is taller than it is wide XAxisMultiplier = CaptureSize.Y / (float)CaptureSize.X; YAxisMultiplier = 1.0f; } FMatrix ProjectionMatrix = FReversedZPerspectiveMatrix ( FOV, FOV, XAxisMultiplier, YAxisMultiplier, GNearClippingPlane, GNearClippingPlane ); FMatrix ViewProjectionMatrix = ViewMatrix * ProjectionMatrix; FVector4 ScreenPoint = ViewProjectionMatrix.TransformFVector4(FVector4(Location,1)); if (ScreenPoint.W > 0.0f) { float InvW = 1.0f / ScreenPoint.W; float Y = (GProjectionSignY > 0.0f) ? ScreenPoint.Y : 1.0f - ScreenPoint.Y; FIntRect ViewRect = FIntRect(0, 0, CaptureSize.X, CaptureSize.Y); OutPixelLocation = FVector2D( ViewRect.Min.X + (0.5f + ScreenPoint.X * 0.5f * InvW) * ViewRect.Width(), ViewRect.Min.Y + (0.5f - Y * 0.5f * InvW) * ViewRect.Height() ); return true; } return false; } bool UVictoryBPFunctionLibrary::Capture2D_Project(class ASceneCapture2D* Target, FVector Location, FVector2D& OutPixelLocation) { return (Target) ? CaptureComponent2D_Project(Target->GetCaptureComponent2D(), Location, OutPixelLocation) : false; } static TSharedPtr 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())) { const TArray* UncompressedRGBA = nullptr; if (ImageWrapper->GetRaw(ERGBFormat::RGBA, 8, UncompressedRGBA)) { Texture = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_R8G8B8A8); if (Texture != nullptr) { IsValid = true; OutWidth = ImageWrapper->GetWidth(); OutHeight = ImageWrapper->GetHeight(); void* TextureData = Texture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE); FMemory::Memcpy(TextureData, UncompressedRGBA->GetData(), UncompressedRGBA->Num()); Texture->PlatformData->Mips[0].BulkData.Unlock(); Texture->UpdateResource(); } } } return Texture; } UUserWidget* UVictoryBPFunctionLibrary::GetFirstWidgetOfClass(UObject* WorldContextObject, TSubclassOf 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(ULevelStreamingKismet* LevelInstance) { PackageName = LevelInstance->GetWorldAssetPackageFName(); PackageNameToLoad = LevelInstance->PackageNameToLoad; Location = LevelInstance->LevelTransform.GetLocation(); Rotation = LevelInstance->LevelTransform.GetRotation().Rotator(); bShouldBeLoaded = LevelInstance->bShouldBeLoaded; bShouldBeVisible = LevelInstance->bShouldBeVisible; bShouldBlockOnLoad = LevelInstance->bShouldBlockOnLoad; LODIndex = LevelInstance->LevelLODIndex; }; FLevelStreamInstanceInfo UVictoryBPFunctionLibrary::GetLevelInstanceInfo(ULevelStreamingKismet* LevelInstance) { return FLevelStreamInstanceInfo(LevelInstance); } void UVictoryBPFunctionLibrary::AddToStreamingLevels(UObject* WorldContextObject, const FLevelStreamInstanceInfo& LevelInstanceInfo) { bool bResult = true; UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull); if (World != nullptr) { bool bAlreadyExists = false; for (auto StreamingLevel : World->StreamingLevels) { if (StreamingLevel->GetWorldAssetPackageFName() == LevelInstanceInfo.PackageName) { bAlreadyExists = true; // KRIS : Would normally log a warning here! Is there a LogVictory? break; } } if (!bAlreadyExists) { FName PackageName = LevelInstanceInfo.PackageName; // For PIE Networking: remap the packagename to our local PIE packagename FString PackageNameStr = PackageName.ToString(); if (GEngine->NetworkRemapPath(World->GetNetDriver(), PackageNameStr, true)) { PackageName = FName(*PackageNameStr); } GEngine->DelayGarbageCollection(); // Setup streaming level object that will load specified map ULevelStreamingKismet* StreamingLevel = NewObject(World, ULevelStreamingKismet::StaticClass(), NAME_None, RF_Transient, nullptr); StreamingLevel->SetWorldAssetByPackageName(PackageName); StreamingLevel->LevelColor = FColor::MakeRandomColor(); StreamingLevel->bShouldBeLoaded = LevelInstanceInfo.bShouldBeLoaded; StreamingLevel->bShouldBeVisible = LevelInstanceInfo.bShouldBeVisible; StreamingLevel->bShouldBlockOnLoad = LevelInstanceInfo.bShouldBlockOnLoad; StreamingLevel->bInitiallyLoaded = true; StreamingLevel->bInitiallyVisible = true; // Transform StreamingLevel->LevelTransform = FTransform(LevelInstanceInfo.Rotation, LevelInstanceInfo.Location); // Map to Load StreamingLevel->PackageNameToLoad = LevelInstanceInfo.PackageNameToLoad; // Add the new level to world. World->StreamingLevels.Add(StreamingLevel); World->FlushLevelStreaming(EFlushLevelStreamingType::Full); } } } void UVictoryBPFunctionLibrary::RemoveFromStreamingLevels(UObject* WorldContextObject, const FLevelStreamInstanceInfo& LevelInstanceInfo) { UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull); // Check if the world exists and we have a level to unload if (World != nullptr && !LevelInstanceInfo.PackageName.IsNone()) { #if WITH_EDITOR // If we are using the editor we will use this lambda to remove the play in editor string auto GetCorrectPackageName = [&]( FName PackageName) { FString PackageNameStr = PackageName.ToString(); if (GEngine->NetworkRemapPath(World->GetNetDriver(), PackageNameStr, true)) { PackageName = FName(*PackageNameStr); } return PackageName; }; #endif // Get the package name that we want to check FName PackageNameToCheck = LevelInstanceInfo.PackageName; #if WITH_EDITOR // Remove the play in editor string and client id to be able to use it with replication PackageNameToCheck = GetCorrectPackageName(PackageNameToCheck); #endif // Find the level to unload for (auto StreamingLevel : World->StreamingLevels) { FName LoadedPackageName = StreamingLevel->GetWorldAssetPackageFName(); #if WITH_EDITOR // Remove the play in editor string and client id to be able to use it with replication LoadedPackageName = GetCorrectPackageName(LoadedPackageName); #endif // If we find the level unload it and break if(PackageNameToCheck == LoadedPackageName) { // This unload the level StreamingLevel->bShouldBeLoaded = false; StreamingLevel->bShouldBeVisible = false; // This removes the level from the streaming level list StreamingLevel->bIsRequestingUnloadAndRemoval = true; // Force a refresh of the world World->FlushLevelStreaming(EFlushLevelStreamingType::Full); break; } } } } bool UVictoryBPFunctionLibrary::GenericArray_SortCompare(const UProperty* LeftProperty, void* LeftValuePtr, const UProperty* RightProperty, void* RightValuePtr) { bool bResult = false; if (const UNumericProperty *LeftNumericProperty = Cast(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 UBoolProperty* LeftBoolProperty = Cast(LeftProperty)) { bResult = (!LeftBoolProperty->GetPropertyValue(LeftValuePtr) && Cast(RightProperty)->GetPropertyValue(RightValuePtr)); } else if (const UNameProperty* LeftNameProperty = Cast(LeftProperty)) { bResult = (LeftNameProperty->GetPropertyValue(LeftValuePtr).ToString() < Cast(RightProperty)->GetPropertyValue(RightValuePtr).ToString()); } else if (const UStrProperty* LeftStringProperty = Cast(LeftProperty)) { bResult = (LeftStringProperty->GetPropertyValue(LeftValuePtr) < Cast(RightProperty)->GetPropertyValue(RightValuePtr)); } else if (const UTextProperty* LeftTextProperty = Cast(LeftProperty)) { bResult = (LeftTextProperty->GetPropertyValue(LeftValuePtr).ToString() < Cast(RightProperty)->GetPropertyValue(RightValuePtr).ToString()); } return bResult; } void UVictoryBPFunctionLibrary::GenericArray_Sort(void* TargetArray, const UArrayProperty* ArrayProp, bool bAscendingOrder /* = true */, FName VariableName /* = NAME_None */) { if (TargetArray) { FScriptArrayHelper ArrayHelper(ArrayProp, TargetArray); const int32 LastIndex = ArrayHelper.Num(); if (const UObjectProperty* ObjectProperty = Cast(ArrayProp->Inner)) { for (int32 i = 0; i < LastIndex; ++i) { for (int32 j = 0; j < LastIndex - 1 - i; ++j) { UObject* LeftObject = ObjectProperty->GetObjectPropertyValue(ArrayHelper.GetRawPtr(j)); UObject* RightObject = ObjectProperty->GetObjectPropertyValue(ArrayHelper.GetRawPtr(j + 1)); UProperty* LeftProperty = FindField(LeftObject->GetClass(), VariableName); UProperty* 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 { UProperty* Property = nullptr; if (const UStructProperty* 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