Files
UnrealEngine/Engine/Source/Editor/UnrealEd/Public/PackageHelperFunctions.h
2025-05-18 13:04:45 +08:00

270 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/**
* File to hold common package helper functions.
*
*/
#pragma once
#include "CoreMinimal.h"
#include "Misc/Paths.h"
#include "HAL/FileManager.h"
#include "Misc/PackageName.h"
#include "Commandlets/Commandlet.h"
#include "Misc/FeedbackContext.h"
#include "FileHelpers.h"
#include "CollectionManagerTypes.h"
class Error;
class ICollectionContainer;
UNREALED_API DECLARE_LOG_CATEGORY_EXTERN(LogPackageHelperFunctions, Log, All);
/**
* Flags which modify the way that NormalizePackageNames works.
*/
enum EPackageNormalizationFlags
{
/** reset the linker for any packages currently in memory that are part of the output list */
NORMALIZE_ResetExistingLoaders = 0x01,
/** do not include map packages in the result array; only relevant if the input array is empty */
NORMALIZE_ExcludeMapPackages = 0x02,
/** do not include content packages in the result array; only relevant if the input array is empty */
NORMALIZE_ExcludeContentPackages = 0x04,
/** do not include packages inside developer folders in the result array; only relevant if the input array is empty */
NORMALIZE_ExcludeDeveloperPackages = 0x08,
/** do not include packages outside developer folders in the result array; only relevant if the input array is empty */
NORMALIZE_ExcludeNonDeveloperPackages = 0x10,
/** do not include packages inside the Engine/Content folders in the result array; only relevant if the input array is empty */
NORMALIZE_ExcludeEnginePackages = 0x20,
/** do not include packages inside NoRedist, NotForLicensees, or LimitedAccess folders */
NORMALIZE_ExcludeNoRedistPackages = 0x40,
/** do not include localized packages */
NORMALIZE_ExcludeLocalizedPackages = 0x80,
/** Combo flags */
NORMALIZE_DefaultFlags = NORMALIZE_ResetExistingLoaders,
};
void SearchDirectoryRecursive( const FString& SearchPathMask, TArray<FString>& out_PackageNames, TArray<FString>& out_PackageFilenames );
/**
* Takes an array of package names (in any format) and converts them into relative pathnames for each package.
*
* @param PackageNames the array of package names to normalize. If this array is empty, the complete package list will be used.
* @param PackagePathNames will be filled with the complete relative path name for each package name in the input array
* @param PackageWildcard if specified, allows the caller to specify a wildcard to use for finding package files
* @param PackageFilter allows the caller to limit the types of packages returned.
*
* @return true if packages were found successfully, false otherwise.
*/
bool UNREALED_API NormalizePackageNames( TArray<FString> PackageNames, TArray<FString>& PackagePathNames, const FString& PackageWildcard=FString(TEXT("*.*")), uint8 PackageFilter=NORMALIZE_DefaultFlags );
/**
* Helper function to save a package that may or may not be a map package
*
* @param Package The package to save
* @param Filename The location to save the package to
* @param KeepObjectFlags Objects with any these flags will be kept when saving even if unreferenced.
* @param ErrorDevice the output device to use for warning and error messages
*
* @return true if successful
*/
bool UNREALED_API SavePackageHelper(UPackage* Package, FString Filename, EObjectFlags KeepObjectFlags = RF_Standalone,
FOutputDevice* ErrorDevice=GWarn, ESaveFlags SaveFlags = SAVE_None);
UE_DEPRECATED(5.0, "LinkerToConformAgainst is no longer implemented; call function overload that does not take LinkerToConformAgainst.")
bool UNREALED_API SavePackageHelper(UPackage* Package, FString Filename, EObjectFlags KeepObjectFlags,
FOutputDevice* ErrorDevice, FLinkerNull* LinkerToConformAgainst, ESaveFlags SaveFlags = SAVE_None);
/**
* Collection helper
* Used to create and update ContentBrowser collections
*
*/
class FContentHelper
{
public:
UE_DEPRECATED(5.6, "Use the ICollectionContainer overload instead.")
FContentHelper();
explicit FContentHelper(const TSharedRef<ICollectionContainer>& InCollectionContainer);
~FContentHelper()
{
if (bInitialized == true)
{
Shutdown();
}
}
/**
* Initialize the Collection helper
*
* @return bool true if successful, false if failed
*/
UNREALED_API bool Initialize();
/**
* Shutdown the collection helper
*/
UNREALED_API void Shutdown();
/**
* Create a new tag
*
* @param CollectionName The name of the tag to create
*
* @return bool true if successful, false if failed
*/
bool CreateCollection( FName CollectionName, ECollectionShareType::Type InType );
/**
* Clear the given collection
*
* @param InCollectionName The name of the collection to clear
* @param InType Type of collection
*
* @return bool true if successful, false if failed
*/
bool ClearCollection(FName InCollectionName, ECollectionShareType::Type InType);
/**
* Fill the given collection with the given list of assets
*
* @param InCollectionName The name of the collection to fill
* @param InType Type of collection
* @param InAssetList The list of items to fill the collection with (can be empty)
*
* @return bool true if successful, false if not.
*/
bool SetCollection(FName InCollectionName, ECollectionShareType::Type InType, const TArray<FSoftObjectPath>& InAssetList);
/**
* Update the given collection with the lists of adds/removes
*
* @param InCollectionName The name of the collection to update
* @param InType Type of collection
* @param InAddList The list of items to ADD to the collection (can be empty)
* @param InRemoveList The list of items to REMOVE from the collection (can be empty)
*
* @return bool true if successful, false if not.
*/
bool UpdateCollection(FName InCollectionName, ECollectionShareType::Type InType, const TArray<FSoftObjectPath>& InAddList, const TArray<FSoftObjectPath>& InRemoveList);
/**
* Retrieve the assets contained in the given collection.
*
* @param InCollectionName Name of collection to query
* @param InType Type of collection
* @param OutAssetPaths The assets contained in the collection
*
* @return True if collection was created successfully
*/
UNREALED_API bool QueryAssetsInCollection(FName InCollectionName, ECollectionShareType::Type InType, TArray<FSoftObjectPath>& OutAssetPaths);
protected:
/** Creates a new collection */
template <class AssetSetPolicy> bool CreateAssetSet ( FName InSetName, ECollectionShareType::Type InSetType );
/** Clears the content of a Tag or Collection */
template <class AssetSetPolicy> bool ClearAssetSet ( FName InSetName, ECollectionShareType::Type InSetType );
/** Sets the contents of a Tag or Collection to be the InAssetList. Assets not mentioned in the list will be untagged. */
template <class AssetSetPolicy> bool AssignSetContent( FName InSetName, ECollectionShareType::Type InType, const TArray<FSoftObjectPath>& InAssetList );
/** Add and remove assets for the specified Tag or Connection. Assets from InAddList are added; assets from InRemoveList are removed. */
template <class AssetSetPolicy> bool UpdateSetContent( FName InSetName, ECollectionShareType::Type InType, const TArray<FSoftObjectPath>& InAddList, const TArray<FSoftObjectPath>& InRemoveList );
/** Get the list of all assets in the specified Collection or Tag */
template <class AssetSetPolicy> bool QuerySetContent( FName InCollectionName, ECollectionShareType::Type InType, TArray<FSoftObjectPath>& OutAssetPaths );
bool bInitialized;
TSharedPtr<ICollectionContainer> CollectionContainer;
};
/**
* This is our Functional "Do an Action to all Packages" Template. Basically it handles all
* of the boilerplate code which normally gets copy pasted around. So now we just pass in
* the OBJECTYPE (e.g. Texture2D ) and then the Functor which will do the actual work.
*
* @see UFindMissingPhysicalMaterialsCommandlet
* @see UFindTexturesWhichLackLODBiasOfTwoCommandlet
**/
template< typename OBJECTYPE, typename FUNCTOR >
void DoActionToAllPackages( UCommandlet* Commandlet, const FString& Params )
{
// Parse command line.
TArray<FString> Tokens;
TArray<FString> Switches;
UE_LOG(LogPackageHelperFunctions, Warning, TEXT("%s"), *Params);
const TCHAR* Parms = *Params;
UCommandlet::ParseCommandLine(Parms, Tokens, Switches);
const bool bVerbose = Switches.Contains(TEXT("VERBOSE"));
const bool bLoadMaps = Switches.Contains(TEXT("LOADMAPS"));
const bool bOverrideLoadMaps = Switches.Contains(TEXT("OVERRIDELOADMAPS"));
const bool bOnlyLoadMaps = Switches.Contains(TEXT("ONLYLOADMAPS"));
const bool bSkipReadOnly = Switches.Contains(TEXT("SKIPREADONLY"));
const bool bOverrideSkipOnly = Switches.Contains(TEXT("OVERRIDEREADONLY"));
const bool bGCEveryPackage = Switches.Contains(TEXT("GCEVERYPACKAGE"));
TArray<FString> FilesInPath;
FEditorFileUtils::FindAllPackageFiles(FilesInPath);
int32 GCIndex = 0;
for( int32 FileIndex = 0; FileIndex < FilesInPath.Num(); FileIndex++ )
{
const FString& Filename = FilesInPath[FileIndex];
const bool bIsAutoSave = Filename.Contains( TEXT("AUTOSAVES") );
// See if we should skip read only packages
if( bSkipReadOnly && !bOverrideSkipOnly )
{
const bool bIsReadOnly = IFileManager::Get().IsReadOnly( *Filename );
if( bIsReadOnly )
{
UE_LOG(LogPackageHelperFunctions, Warning, TEXT("Skipping %s (read-only)"), *Filename);
continue;
}
}
// if we don't want to load maps for this
if( ((!bLoadMaps && !bOnlyLoadMaps) || bOverrideLoadMaps) && ( FPaths::GetExtension(Filename, true) == FPackageName::GetMapPackageExtension() ) )
{
continue;
}
// if we only want to load maps for this
if( ( bOnlyLoadMaps == true ) && ( FPaths::GetExtension(Filename, true) != FPackageName::GetMapPackageExtension() ) )
{
continue;
}
if( bVerbose == true )
{
UE_LOG(LogPackageHelperFunctions, Warning, TEXT("Loading %s"), *Filename );
}
UPackage* Package = LoadPackage( NULL, *Filename, LOAD_None );
if( Package != NULL )
{
FUNCTOR TheFunctor;
TheFunctor.template DoIt<OBJECTYPE>( Commandlet, Package, Tokens, Switches );
}
else
{
UE_LOG(LogPackageHelperFunctions, Error, TEXT("Error loading %s!"), *Filename );
}
if( ( (++GCIndex % 10) == 0 ) || ( bGCEveryPackage == true ) )
{
CollectGarbage(RF_NoFlags);
}
}
}