目录
前言:
本文内容:
WHY WHAT HOW
详细步骤
代码解析
1. Build.cs file中
2. QuickAssetAction.cpp中
IMPORTANT NOTES
中文解释:
使用 AssetToolsModule 来修复重定向器
使用 AssetRegistryModule 来过滤所有重定向器
使用 FModuleManager 来加载不同的模块
F 前缀的含义
FModuleManager的作用
FARFilter
前言:
移动asset时需要手动地fix up redirectors,我们不指望引擎用户能每次都记得操作,而忘记操作会导致不确定的data lost。
本文内容:
在代码中实现,移动文件时自动fix up redirectors
WHY WHAT HOW
why:Avoid data lost
what:Fix up redirectors from code
how:找到Fix up redirectors in folder这个按钮,并确定在点击这个按钮时何种function被调用。
the key function to achieve this is in, AssetToolsModule and AssetRegistryModule
- AssetToolsModule: FixUpReferences(TArray<UObjectRedirectors*>)
- AssetRegistryModule: GetAssets(FARFilter) (to get all the redirectors)
- (to use the functions inside of these two different modules) FModuleManager::LoadModuleChecked<>()
详细步骤
在QuickAssetAction.h的private部分里调用
void FixUpRedirectors();
在QuickAssetAction.cpp里创建声明
// Fill out your copyright notice in the Description page of Project Settings.#include "AssetAction/QuickAssetAction.h"
#include "DebugHeader.h"
#include "EditorUtilityLibrary.h"
#include "EditorAssetLibrary.h"
#include "ObjectTools.h"
#include "AssetRegistryModule.h"//fix up
#include "AssetToolsModule.h"//use it when we want to create assets from code//void UQuickAssetAction::TestFuckingFunc()
//{
// Print(TEXT("I hate the plugin 2"), FColor::Cyan);
// PrintLog(TEXT("杀杀杀"));
//
// //if (GEngine)
// //{
// // GEngine->AddOnScreenDebugMessage(-1, 8.f, FColor::Yellow, TEXT("I hate this plugin"));
// //}
//}void UQuickAssetAction::BatchDuplication(int32 NumOfDuplicates)
{if (NumOfDuplicates<=0) {DebugHeader::ShowMsgDialog(EAppMsgType::Ok, TEXT("Please enter a VALID number"));return;}TArray<FAssetData>SelectedAssetsData = UEditorUtilityLibrary::GetSelectedAssetData();uint32 Counter = 0;for (const FAssetData& SelectedAssetData : SelectedAssetsData){for (int32 i = 0; i < NumOfDuplicates; i++) {const FString SourceAssetPath = SelectedAssetData.ObjectPath.ToString();const FString NewDuplicatedAssetName = SelectedAssetData.AssetName.ToString() + TEXT("_") + FString::FromInt(i + 1);const FString NewPathName = FPaths::Combine(SelectedAssetData.PackagePath.ToString(), NewDuplicatedAssetName);if(UEditorAssetLibrary::DuplicateAsset(SourceAssetPath, NewPathName)){UEditorAssetLibrary::SaveAsset(NewPathName, false);++Counter;}}}if (Counter > 0){DebugHeader::ShowNotifyInfo(TEXT("Successfully duplicated " + FString::FromInt(Counter) + " files"));//Print(TEXT("Successfully duplicated " + FString::FromInt(Counter) + " files"), FColor::Green);}}void UQuickAssetAction::AddPrefixes()
{TArray<UObject*>SelectedObjects = UEditorUtilityLibrary::GetSelectedAssets();uint32 Counter = 0;for (UObject* SelectedObject : SelectedObjects){if (!SelectedObject) continue;//空指针检查 SelectedObject 是 nullptrFString* PrefixFound = PrefixMap.Find(SelectedObject->GetClass());//这一行查找 SelectedObject 对象对应的类(SelectedObject->GetClass())在 PrefixMap 中的值。// PrefixMap 是一个自己命名的TMap<UClass*, FString>键值对的映射,// 其中键是 UClass*(对象的类)如material,值是 FString(M_)。if (!PrefixFound || PrefixFound->IsEmpty()){DebugHeader::Print(TEXT("Failed to find prefix for class ") + SelectedObject->GetClass()->GetName(), FColor::Red);continue;}FString OldName = SelectedObject->GetName();if (OldName.StartsWith(*PrefixFound)){DebugHeader::Print(OldName + TEXT(" already has prefix added"), FColor::Red);continue;}//如果类型是MI_old name里有M_和_Inst,移除他们。if (SelectedObject->IsA<UMaterialInstanceConstant>()){OldName.RemoveFromStart(TEXT("M_"));OldName.RemoveFromEnd(TEXT("_Inst"));}const FString NewNameWithPrefix = *PrefixFound + OldName;UEditorUtilityLibrary::RenameAsset(SelectedObject, NewNameWithPrefix);++Counter;//将计数器 Counter 的值增加 1。它用于记录处理了多少个对象。//在脚本完成后,下面那串代码输出一条信息,例如 "成功处理了 X 个对象"。}if(Counter>0){DebugHeader::ShowNotifyInfo(TEXT("Successfully renamed " + FString::FromInt(Counter) + " assets"));}
}void UQuickAssetAction::RemoveUnusedAssets()
{TArray<FAssetData> SelectedAssetsData = UEditorUtilityLibrary::GetSelectedAssetData();TArray<FAssetData> UnusedAssetsData;FixUpRedirectors();for (const FAssetData& SelectedAssetData : SelectedAssetsData) {TArray<FString> AssetReferencers =UEditorAssetLibrary::FindPackageReferencersForAsset(SelectedAssetData.ObjectPath.ToString());if (AssetReferencers.Num() == 0) {UnusedAssetsData.Add(SelectedAssetData);}//把它加入废物列表}if (UnusedAssetsData.Num() == 0) {DebugHeader::ShowMsgDialog(EAppMsgType::Ok, TEXT("No unused asset found among selected assets"), false);return;}//查找未使用资产//有未使用资产else {const int32 NumOfAssetsDeleted = ObjectTools::DeleteAssets(UnusedAssetsData);//执行删除if (NumOfAssetsDeleted > 0) {DebugHeader::ShowNotifyInfo(TEXT("Successfully deleted " + FString::FromInt(NumOfAssetsDeleted) + TEXT(" unused assets.")));}else {DebugHeader::ShowNotifyInfo(TEXT("No assets were deleted.")); // 只有在取消删除资产时显示这条消息}}//const int32 NumOfAssetDeleted = ObjectTools::DeleteAssets(UnusedAssetsData);//执行删除//if (NumOfAssetDeleted == 0)return;//ShowNotifyInfo(TEXT("Successfully deleted " + FString::FromInt(NumOfAssetsDeleted) + TEXT(" unused assets.")));
}void UQuickAssetAction::FixUpRedirectors()
{TArray<UObjectRedirector*> RedirectorsToFixArray;//fixupFAssetRegistryModule& AssetRegistryModule =FModuleManager::Get().LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));FARFilter Filter;Filter.bRecursivePaths = true;Filter.PackagePaths.Emplace("/Game");Filter.ClassNames.Emplace("ObjectRedirector");TArray<FAssetData> OutRedirectors;AssetRegistryModule.Get().GetAssets(Filter,OutRedirectors);for (const FAssetData& RedirectorData : OutRedirectors){if (UObjectRedirector* RedirectorToFix = Cast<UObjectRedirector>(RedirectorData.GetAsset()))//cast from UObject* to UObjectRedirector*{RedirectorsToFixArray.Add(RedirectorToFix);}}FAssetToolsModule& AssetToolsModule =FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));AssetToolsModule.Get().FixupReferencers(RedirectorsToFixArray);
}
代码解析
1. Build.cs file中
插件的build.cs file里加入“AssetTools"的PublicDependency
PublicDependencyModuleNames.AddRange(new string[]{"Core","Blutility","EditorScriptingUtilities","UMG","Niagara","UnrealEd","AssetTools"//,"ContentBrowser"// ... add other public dependencies that you statically link with here ...});
2. QuickAssetAction.cpp中
#include "AssetRegistryModule.h"//fix up
#include "AssetToolsModule.h"//use it when we want to create assets from code
在void UQuickAssetAction::RemoveUnusedAssets()里调用一下修复重定向器功能
FixUpRedirectors();
QuickAssetAction.cpp的修复重定向功能定义
void UQuickAssetAction::FixUpRedirectors()
//定义一个名为 FixUpRedirectors 的函数,属于 UQuickAssetAction 类。这个函数的目的是修复重定向器。
{TArray<UObjectRedirector*> RedirectorsToFixArray;//fixup//创建一个数组 RedirectorsToFixArray,用来存储需要修复的重定向器对象的指针。FAssetRegistryModule& AssetRegistryModule =FModuleManager::Get().LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));//使用 FModuleManager 加载 AssetRegistryModule 模块,并将其引用存储在 AssetRegistryModule 中。// 如果模块加载失败,将引发一个错误。*注意拼写FARFilter Filter;//创建一个 FARFilter 对象,用于定义资产过滤条件。Filter.bRecursivePaths = true;//设置过滤器的 bRecursivePaths 属性为 true,表示在指定路径下递归搜索资产。Filter.PackagePaths.Emplace("/Game");//将 /Game 路径添加到过滤器中,这意味着在该路径下寻找资产。Filter.ClassNames.Emplace("ObjectRedirector");//将 ObjectRedirector 类添加到过滤器中,表示只查找这种类型的资产。TArray<FAssetData> OutRedirectors;//创建一个数组 OutRedirectors,用来存储从资产注册表中检索到的资产数据。AssetRegistryModule.Get().GetAssets(Filter,OutRedirectors);//调用 AssetRegistryModule 中的 GetAssets 函数,// 传入定义的过滤器 Filter 和输出数组 OutRedirectors,以获取符合条件的重定向器资产数据。for (const FAssetData& RedirectorData : OutRedirectors)//遍历 OutRedirectors 中的每个 FAssetData 对象,命名为 RedirectorData。{if (UObjectRedirector* RedirectorToFix = Cast<UObjectRedirector>(RedirectorData.GetAsset()))//cast from UObject* to UObjectRedirector*// 中文解释//尝试将 RedirectorData.GetAsset() 返回的资产转换为 UObjectRedirector* 类型。// 如果转换成功,RedirectorToFix 将是一个有效的指针。{RedirectorsToFixArray.Add(RedirectorToFix);//如果转换成功,将指向重定向器的指针 RedirectorToFix 添加到 RedirectorsToFixArray 中。}}FAssetToolsModule& AssetToolsModule =FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));//加载 AssetToolsModule 模块,并将其引用存储在 AssetToolsModule 中。AssetToolsModule.Get().FixupReferencers(RedirectorsToFixArray);//调用 FixupReferencers 方法,传入 RedirectorsToFixArray,以修复所有收集到的重定向器。
}
IMPORTANT NOTES
- Use AssetToolsModule to fix up redirectors
- Use AssetRegistryModule to filter out all the redirectors
- Use FModuleManager to load different modules
中文解释:
使用 AssetToolsModule 来修复重定向器
AssetToolsModule
提供了一些工具和功能,帮助开发者管理和处理资产,特别是关于重定向器(Redirector)的操作。重定向器通常在资产被移动或重命名时自动生成,使用 AssetToolsModule
可以帮助修复这些重定向器,以确保资产能够正确引用。
使用 AssetRegistryModule 来过滤所有重定向器
AssetRegistryModule
负责管理引擎中的资产注册表,允许你查询和过滤资产信息。通过这个模块,可以轻松获取项目中的所有资产,包括重定向器,并根据特定条件进行过滤。这有助于确保你只处理所需的资产类型,避免无用的重定向器干扰你的逻辑。
使用 FModuleManager 来加载不同的模块
FModuleManager
是 Unreal Engine 的模块管理器,负责加载和卸载模块。由于模块可以按需加载,使用 FModuleManager
可以确保在运行时动态加载所需的模块。例如,当你需要使用 AssetToolsModule
或 AssetRegistryModule
的功能时,首先要确保这些模块已经被加载。
F
前缀的含义
在 Unreal Engine 中,F
前缀通常用于表示 结构体(struct)或 类(class),是 Unreal Engine 的编码约定之一。这种约定旨在帮助开发者区分不同类型的对象。
-
F表示 "Fundamental" 或 "Type":
F
主要用来标识基本类型、数据结构或类的定义。它与其他前缀(如U
或A
)结合使用,有助于理解对象的角色。 -
类型区分:
F
开头:表示一个普通的 C++ 结构体或类,通常不具有与 Unreal 引擎的对象系统相关的特性(如反射、序列化等)。例如,FVector
、FString
、FAssetData
。U
开头:表示一个 Unreal Engine 的 UObject 派生类,具有引擎的对象特性,如反射和序列化。比如UActor
、UObject
。A
开头:表示一个 Unreal Engine 的 Actor 类,通常用来表示游戏世界中的对象,例如ACharacter
、APlayerController
。
示例
FVector
:表示一个三维向量,常用于位置、方向等。FString
:表示一个字符串,通常用于文本处理。FAssetData
:表示资产的元数据,通常用于查询资产信息。
FModuleManager的作用
UE中,模块是逻辑上组织代码的单元。每个模块可以提供特定的功能,而 FModuleManager
是用于管理这些模块的类。
-
动态加载:Unreal Engine 的模块可以根据需要加载,
FModuleManager
提供了接口来加载和卸载这些模块,而不需要在编译时静态链接。这意味着你可以根据具体需要来加载相应的模块,从而优化资源使用。 -
模块管理:
FModuleManager
负责管理模块的生命周期,包括模块的初始化、清理等。当一个模块被加载时,FModuleManager
会确保模块的所有依赖项都已被正确处理。 -
提高灵活性:通过
FModuleManager
,你可以在运行时决定是否加载某个模块,这样可以实现更灵活的程序设计,允许你根据条件或配置来控制哪些功能被启用。
FARFilter
FARFilter
是 Unreal Engine 中用于定义和处理 Actor 的过滤器的结构体。(FARFilter
中的 "FAR" 是 Filter Asset Registry 的缩写。)它通常在进行查找(例如通过 GetAllActorsOfClass
或其他类似函数)时使用,以限制返回的结果。