// Copyright Epic Games, Inc. All Rights Reserved. #include "LocalizedAssetUtil.h" #include "AssetRegistry/ARFilter.h" #include "AssetRegistry/AssetData.h" #include "AssetRegistry/IAssetRegistry.h" #include "HAL/Platform.h" #include "Internationalization/Text.h" #include "LocalizationSourceControlUtil.h" #include "Logging/LogCategory.h" #include "Logging/LogMacros.h" #include "Misc/PackageName.h" #include "Misc/Paths.h" #include "ObjectTools.h" #include "PackageHelperFunctions.h" #include "Trace/Detail/Channel.h" #include "UObject/Class.h" #include "UObject/Object.h" #include "UObject/Package.h" #include "UObject/TopLevelAssetPath.h" DEFINE_LOG_CATEGORY_STATIC(LogLocalizedAssetUtil, Log, All); bool FLocalizedAssetSCCUtil::SaveAssetWithSCC(const TSharedPtr& InSourceControlInfo, UObject* InAsset) { UPackage* const AssetPackage = InAsset->GetOutermost(); if (!AssetPackage) { UE_LOG(LogLocalizedAssetUtil, Error, TEXT("Unable to find package for %s '%s'."), *InAsset->GetClass()->GetName(), *InAsset->GetPathName()); return false; } return SavePackageWithSCC(InSourceControlInfo, AssetPackage); } bool FLocalizedAssetSCCUtil::SaveAssetWithSCC(const TSharedPtr& InSourceControlInfo, UObject* InAsset, const FString& InFilename) { UPackage* const AssetPackage = InAsset->GetOutermost(); if (!AssetPackage) { UE_LOG(LogLocalizedAssetUtil, Error, TEXT("Unable to find package for %s '%s'."), *InAsset->GetClass()->GetName(), *InAsset->GetPathName()); return false; } return SavePackageWithSCC(InSourceControlInfo, AssetPackage, InFilename); } bool FLocalizedAssetSCCUtil::SavePackageWithSCC(const TSharedPtr& InSourceControlInfo, UPackage* InPackage) { const FString PackageFileName = FPackageName::LongPackageNameToFilename(InPackage->GetPathName(), FPackageName::GetAssetPackageExtension()); return SavePackageWithSCC(InSourceControlInfo, InPackage, PackageFileName); } bool FLocalizedAssetSCCUtil::SavePackageWithSCC(const TSharedPtr& InSourceControlInfo, UPackage* InPackage, const FString& InFilename) { const bool bPackageExistedOnDisk = FPaths::FileExists(InFilename); // If the package already exists on disk, then we need to check it out before writing to it if (bPackageExistedOnDisk && InSourceControlInfo.IsValid()) { FText SCCErrorStr; if (!InSourceControlInfo->CheckOutFile(InFilename, SCCErrorStr)) { UE_LOG(LogLocalizedAssetUtil, Error, TEXT("Failed to check-out package '%s' at '%s'. %s"), *InPackage->GetPathName(), *InFilename, *SCCErrorStr.ToString()); } } if (!SavePackageHelper(InPackage, InFilename)) { UE_LOG(LogLocalizedAssetUtil, Error, TEXT("Unable to save updated package '%s' to '%s'"), *InPackage->GetPathName(), *InFilename); return false; } // If the package didn't exist on disk, then we need to check it out after writing to it (which will perform an add) if (!bPackageExistedOnDisk && InSourceControlInfo.IsValid()) { FText SCCErrorStr; if (!InSourceControlInfo->CheckOutFile(InFilename, SCCErrorStr)) { UE_LOG(LogLocalizedAssetUtil, Error, TEXT("Failed to check-out package '%s' at '%s'. %s"), *InPackage->GetPathName(), *InFilename, *SCCErrorStr.ToString()); } } return true; } bool FLocalizedAssetSCCUtil::DeleteAssetWithSCC(const TSharedPtr& InSourceControlInfo, UObject* InAsset) { UPackage* const AssetPackage = InAsset->GetOutermost(); if (!AssetPackage) { UE_LOG(LogLocalizedAssetUtil, Error, TEXT("Unable to find package for %s '%s'."), *InAsset->GetClass()->GetName(), *InAsset->GetPathName()); return false; } return DeletePackageWithSCC(InSourceControlInfo, AssetPackage); } bool FLocalizedAssetSCCUtil::DeletePackageWithSCC(const TSharedPtr& InSourceControlInfo, UPackage* InPackage) { if (!ObjectTools::DeleteSingleObject(InPackage, /*bPerformReferenceCheck*/false)) { return false; } TArray DeletedPackages; DeletedPackages.Add(InPackage); ObjectTools::CleanupAfterSuccessfulDelete(DeletedPackages, /*bPerformReferenceCheck*/false); return true; } bool FLocalizedAssetSCCUtil::SaveFileWithSCC(const TSharedPtr& InSourceControlInfo, const FString& InFilename, const FSaveFileCallback& InSaveFileCallback) { const bool bFileExistedOnDisk = FPaths::FileExists(InFilename); // If the file already exists on disk, then we need to check it out before writing to it if (bFileExistedOnDisk && InSourceControlInfo.IsValid()) { FText SCCErrorStr; if (!InSourceControlInfo->CheckOutFile(InFilename, SCCErrorStr)) { UE_LOG(LogLocalizedAssetUtil, Error, TEXT("Failed to check-out file at '%s'. %s"), *InFilename, *SCCErrorStr.ToString()); } } if (!InSaveFileCallback(InFilename)) { UE_LOG(LogLocalizedAssetUtil, Error, TEXT("Unable to save updated file to '%s'"), *InFilename); return false; } // If the file didn't exist on disk, then we need to check it out after writing to it (which will perform an add) if (!bFileExistedOnDisk && InSourceControlInfo.IsValid()) { FText SCCErrorStr; if (!InSourceControlInfo->CheckOutFile(InFilename, SCCErrorStr)) { UE_LOG(LogLocalizedAssetUtil, Error, TEXT("Failed to check-out file at '%s'. %s"), *InFilename, *SCCErrorStr.ToString()); } } return true; } bool FLocalizedAssetUtil::GetAssetsByPathAndClass(IAssetRegistry& InAssetRegistry, const FName InPackagePath, const FTopLevelAssetPath& InClassName, const bool bIncludeLocalizedAssets, TArray& OutAssets) { TArray PackagePaths; PackagePaths.Add(InPackagePath); return GetAssetsByPathAndClass(InAssetRegistry, PackagePaths, InClassName, bIncludeLocalizedAssets, OutAssets); } bool FLocalizedAssetUtil::GetAssetsByPathAndClass(IAssetRegistry& InAssetRegistry, const TArray& InPackagePaths, const FTopLevelAssetPath& InClassName, const bool bIncludeLocalizedAssets, TArray& OutAssets) { FARFilter AssetFilter; AssetFilter.PackagePaths = InPackagePaths; AssetFilter.bRecursivePaths = true; AssetFilter.ClassPaths.Add(InClassName); AssetFilter.bRecursiveClasses = true; if (!InAssetRegistry.GetAssets(AssetFilter, OutAssets)) { return false; } if (!bIncludeLocalizedAssets) { // We need to manually exclude any localized assets OutAssets.RemoveAll([&](const FAssetData& InAssetData) -> bool { return FPackageName::IsLocalizedPackage(InAssetData.PackageName.ToString()); }); } return true; }