DataAssets - DataAssets can now have their base class changed (single or in bulk) as a right click asset action. So if you refactor your data assets and make new subclasses it's a lot easier to upgrade existing content now.

#jira none

#ROBOMERGE-SOURCE: CL 17155423 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v855-17104924)

[CL 17155428 by nick darnell in ue5-release-engine-test branch]
This commit is contained in:
nick darnell
2021-08-12 13:49:50 -04:00
parent 71eea9b856
commit 0c8d9e2d51
2 changed files with 112 additions and 0 deletions
@@ -1,11 +1,43 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "AssetTypeActions/AssetTypeActions_DataAsset.h"
#include "Engine/Engine.h"
#include "ToolMenuSection.h"
#include "ClassViewerModule.h"
#include "Kismet2/SClassPickerDialog.h"
#include "ClassViewerFilter.h"
#include "ObjectTools.h"
#define LOCTEXT_NAMESPACE "AssetTypeActions"
static const FName NAME_NativeClass(TEXT("NativeClass"));
class FNewNodeClassFilter : public IClassViewerFilter
{
public:
FNewNodeClassFilter(UClass* InBaseClass)
: BaseClass(InBaseClass)
{
}
virtual bool IsClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const UClass* InClass, TSharedRef< FClassViewerFilterFuncs > InFilterFuncs) override
{
if (InClass != nullptr)
{
return InClass->IsChildOf(BaseClass);
}
return false;
}
virtual bool IsUnloadedClassAllowed(const FClassViewerInitializationOptions& InInitOptions, const TSharedRef< const IUnloadedBlueprintData > InUnloadedClassData, TSharedRef< FClassViewerFilterFuncs > InFilterFuncs) override
{
return InUnloadedClassData->IsChildOf(BaseClass);
}
private:
UClass* BaseClass;
};
FText FAssetTypeActions_DataAsset::GetDisplayNameFromAssetData(const FAssetData& AssetData) const
{
if (AssetData.IsValid())
@@ -23,4 +55,60 @@ FText FAssetTypeActions_DataAsset::GetDisplayNameFromAssetData(const FAssetData&
return FText::GetEmpty();
}
void FAssetTypeActions_DataAsset::GetActions(const TArray<UObject*>& InObjects, FToolMenuSection& Section)
{
TArray<TWeakObjectPtr<UDataAsset>> DataAssets = GetTypedWeakObjectPtrs<UDataAsset>(InObjects);
Section.AddMenuEntry(
"DataAsset_ChangeClass",
LOCTEXT("DataAsset_ChangeClass", "Change DataAsset Class"),
LOCTEXT("DataAsset_ChangeClassTip", "Change the class these Data Assets are subclassed from."),
FSlateIcon(),
FUIAction(
FExecuteAction::CreateSP(this, &FAssetTypeActions_DataAsset::ExecuteChangeDataAssetClass, DataAssets)
)
);
}
void FAssetTypeActions_DataAsset::ExecuteChangeDataAssetClass(TArray<TWeakObjectPtr<UDataAsset>> InDataAssets)
{
const FText TitleText = LOCTEXT("DataAsset_PickNewDataAssetClass", "Pick New DataAsset Class");
FClassViewerInitializationOptions Options;
Options.ClassFilters.Add(MakeShared<FNewNodeClassFilter>(UDataAsset::StaticClass()));
UClass* OutNewDataAssetClass = nullptr;
const bool bPressedOk = SClassPickerDialog::PickClass(TitleText, Options, OutNewDataAssetClass, UDataAsset::StaticClass());
if (bPressedOk && OutNewDataAssetClass != nullptr)
{
for (TWeakObjectPtr<UDataAsset> DataAssetPtr : InDataAssets)
{
if (UDataAsset* OldDataAsset = DataAssetPtr.Get())
{
if (OldDataAsset && OldDataAsset->IsValidLowLevel())
{
FName ObjectName = OldDataAsset->GetFName();
UObject* Outer = OldDataAsset->GetOuter();
OldDataAsset->Rename(nullptr, GetTransientPackage(), REN_DoNotDirty | REN_DontCreateRedirectors);
UObject* NewDataAsset = NewObject<UObject>(Outer, OutNewDataAssetClass, ObjectName, OldDataAsset->GetFlags());
// Migrate Data
{
UEngine::FCopyPropertiesForUnrelatedObjectsParams CopyOptions;
CopyOptions.bNotifyObjectReplacement = true;
UEngine::CopyPropertiesForUnrelatedObjects(OldDataAsset, NewDataAsset, CopyOptions);
}
NewDataAsset->MarkPackageDirty();
// Consolidate or "Replace" the old object with the new object for any living references.
bool bShowDeleteConfirmation = false;
TArray<UObject*> OldDataAssetArray({ (UObject*)OldDataAsset });
ObjectTools::ConsolidateObjects(NewDataAsset, OldDataAssetArray, bShowDeleteConfirmation);
}
}
}
}
}
#undef LOCTEXT_NAMESPACE