欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 手游 > UE5 C++: 插件编写06 | 移动文件时自动Fix up redirectors

UE5 C++: 插件编写06 | 移动文件时自动Fix up redirectors

2024/10/25 0:35:17 来源:https://blog.csdn.net/charon8778/article/details/142602587  浏览:    关键词:UE5 C++: 插件编写06 | 移动文件时自动Fix up redirectors

目录

前言:

本文内容:

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 可以确保在运行时动态加载所需的模块。例如,当你需要使用 AssetToolsModuleAssetRegistryModule 的功能时,首先要确保这些模块已经被加载。

F 前缀的含义

在 Unreal Engine 中,F 前缀通常用于表示 结构体(struct)或 (class),是 Unreal Engine 的编码约定之一。这种约定旨在帮助开发者区分不同类型的对象。

  1. F表示 "Fundamental""Type"F 主要用来标识基本类型、数据结构或类的定义。它与其他前缀(如 UA)结合使用,有助于理解对象的角色。

  2. 类型区分

    • F 开头:表示一个普通的 C++ 结构体或类,通常不具有与 Unreal 引擎的对象系统相关的特性(如反射、序列化等)。例如,FVectorFStringFAssetData
    • U 开头:表示一个 Unreal Engine 的 UObject 派生类,具有引擎的对象特性,如反射和序列化。比如 UActorUObject
    • A 开头:表示一个 Unreal Engine 的 Actor 类,通常用来表示游戏世界中的对象,例如 ACharacterAPlayerController

示例

  • FVector:表示一个三维向量,常用于位置、方向等。
  • FString:表示一个字符串,通常用于文本处理。
  • FAssetData:表示资产的元数据,通常用于查询资产信息。

FModuleManager的作用

UE中,模块是逻辑上组织代码的单元。每个模块可以提供特定的功能,而 FModuleManager 是用于管理这些模块的类。

  • 动态加载:Unreal Engine 的模块可以根据需要加载,FModuleManager 提供了接口来加载和卸载这些模块,而不需要在编译时静态链接。这意味着你可以根据具体需要来加载相应的模块,从而优化资源使用。

  • 模块管理:FModuleManager 负责管理模块的生命周期,包括模块的初始化、清理等。当一个模块被加载时,FModuleManager 会确保模块的所有依赖项都已被正确处理。

  • 提高灵活性:通过 FModuleManager,你可以在运行时决定是否加载某个模块,这样可以实现更灵活的程序设计,允许你根据条件或配置来控制哪些功能被启用。

FARFilter

FARFilter 是 Unreal Engine 中用于定义和处理 Actor 的过滤器的结构体。FARFilter 中的 "FAR" 是 Filter Asset Registry 的缩写。)它通常在进行查找(例如通过 GetAllActorsOfClass 或其他类似函数)时使用,以限制返回的结果。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com