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 或其他类似函数)时使用,以限制返回的结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/447749.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

利士策分享,美国“假旗”行动,是否成为了网络空间的阴霾?

利士策分享&#xff0c;美国“假旗”行动&#xff0c;是否成为了网络空间的阴霾? 在当今这个信息化时代&#xff0c;网络空间已经成为国家间竞争与合作的重要领域。然而&#xff0c;美国却频繁采取一种名为“假旗行动”的卑劣手段&#xff0c;污染全球网络空间&#xff0c;给世…

Java 二分查找算法详解及通用实现模板案例示范

1. 引言 二分查找&#xff08;Binary Search&#xff09;是一种常见的搜索算法&#xff0c;专门用于在有序数组或列表中查找元素的位置。它通过每次将搜索空间缩小一半&#xff0c;从而极大地提高了查找效率。相比于线性查找算法&#xff0c;二分查找的时间复杂度为 O(log n)&…

Arthas常用的命令(三)--monitor、jad 、stack

monitor&#xff1a;监控方法的执行情况 监控指定类中方法的执行情况 用来监视一个时间段中指定方法的执行次数&#xff0c;成功次数&#xff0c;失败次数&#xff0c;耗时等这些信息 参数说明 方法拥有一个命名参数 [c:]&#xff0c;意思是统计周期&#xff08;cycle of ou…

linux线程 | 同步与互斥(上)

前言&#xff1a;本节内容主要是线程的同步与互斥。 本篇文章的主要内容都在讲解互斥的相关以及周边的知识。大体的讲解思路是通过数据不一致问题引出锁。 然后谈锁的使用以及申请锁释放锁的原子性问题。 那么&#xff0c; 废话不多说&#xff0c; 现在开始我们的学习吧&#x…

软件测试工程师面试整理 —— 操作系统与网络基础!

在软件测试中&#xff0c;了解操作系统和网络基础知识对于有效地进行测试工作至关重要。无论是在配置测试环境、调试网络问题&#xff0c;还是在进行性能测试和安全测试时&#xff0c;这些知识都是不可或缺的。 1. 操作系统基础 操作系统&#xff08;Operating System, OS&am…

OgreNext高级材质中增加线宽,点大小,虚线模式绘制支持

修改Ogre高级材质系统&#xff0c;增加线宽&#xff0c;点大小&#xff0c;虚线模式&#xff0c;虚线参数的支持,效果如下&#xff1a; 需要修改的代码文件如下&#xff1a; 修改如下 代码文本&#xff1a; //范围[0.2 - 51] 0.2 * [0,255];Ogre::uint8 mLineWidth;//范围[…

【数据结构】:破译排序算法--数字世界的秩序密码(二)

文章目录 前言一.比较排序算法1.Bubble Sort冒泡排序1.1.冒泡排序原理1.2.冒泡排序过程1.3.代码实现1.4.复杂度和稳定性 2.Quick Sort快速排序2.1递归快速排序2.1.1.递归快速排序原理2.1.2.递归快速排序过程2.1.3.代码实现 2.2.非递归快速排序2.2.1.非递归快速排序原理2.2.2.非…

MATLAB智能优化算法-学习笔记(5)——蚁群算法求解容量受限的车辆路径问题

蚁群算法在求解容量受限的车辆路径问题(Capacitated Vehicle Routing Problem, CVRP)中具有广泛应用。这类问题属于组合优化问题,涉及将若干辆具有容量限制的车辆,从配送中心出发为多个客户点提供服务,要求每辆车满足各客户的需求且总运载量不超过车辆容量,最终需要找到一…

python深浅拷贝,可变变量与不可变变量

赋值 在 python 中&#xff0c;赋值是将一个值或对象分配给一个变量的过程。赋值操作符是 &#xff0c;用于将右侧的值或对象赋给左侧的变量。 赋值&#xff1a;l2的值会随着原对象l1的值一同改变 l1 [1, 2, 3, 4] print(l1:, l1) l2 l1 print(l2:, l2) 给li列表新增元素 …

检测头篇 | 手把手教你如何去更换YOLOv8的检测头为ASFF_Detect

前言:Hello大家好,我是小哥谈。自适应空间特征融合(ASFF)的主要原理旨在解决单次检测器中不同尺度特征的不一致性问题。具体来说,ASFF通过动态调整来自不同尺度特征金字塔层的特征贡献,确保每个检测对象的特征表示是一致且最优的。本文所做出的改进是将YOLOv8的检测头更换…

使用 Spring 框架构建 MVC 应用程序:初学者教程

Spring Framework 是一个功能强大、功能丰富且设计精良的 Java 平台框架。它提供了一系列编程和配置模型&#xff0c;旨在简化和精简 Java 中健壮且可测试的应用程序的开发过程。 人们常说 Java 太复杂了&#xff0c;构建简单的应用程序需要很长时间。尽管如此&#xff0c;Jav…

论文翻译 | OpenICL: An Open-Source Framework for In-context Learning

摘要 近年来&#xff0c;上下文学习&#xff08;In-context Learning&#xff0c;ICL&#xff09;越来越受到关注&#xff0c;并已成为大型语言模型&#xff08;Large Language Model&#xff0c;LLM&#xff09;评估的新范式。与传统微调方法不同&#xff0c;ICL无需更新任何参…

龙信科技:引领电子物证技术,助力司法公正

文章关键词&#xff1a;电子数据取证、电子物证、手机取证、计算机取证、云取证、介质取证 在信息技术飞速发展的今天&#xff0c;电子物证在司法领域扮演着越来越重要的角色。苏州龙信信息科技有限公司&#xff08;以下简称“龙信科技”&#xff09;作为电子数据取证领域的先…

bat(批处理脚本学习)

输出banner echo off echo () echo JL echo ^|^| echo LJ echo _,--"""""""---. echo , …

从零实现高并发内存池

目录 1. 项目介绍1.1 这个项目具体功能是什么&#xff1f;1.2 本项目的知识储备 2. 什么是内存池2.1 池化技术2.2 内存池主要解决的问题2.3 malloc 3. 定长内存池设计4. 高并发内存池整体框架设计4.1 Thread Cache的设计思路4.2 Central Cache的设计思路4.3 Page Cache的设计思…

【C语言】分支结构switch

switch分支语句 多适用于明确表达式结果的情况&#xff0c;多个分支&#xff0c;用if过于繁琐。 case后跟具体的表达式值&#xff0c;break&#xff1b;跳出分支语句。 #include <stdio.h> #include <math.h> /* 功能&#xff1a;选择结构&#xff08;switch&…

Qt初识_项目文件解析

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 Qt初识_项目文件解析 收录于专栏【Qt开发】 本专栏旨在分享学习Qt的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. pro文件解析 2.…

java异步多线程Async学习记录

java异步多线程Async学习记录 第1步:声明线程池AsyncConfiguration import org.springframework.context.annotation.Bean; import org.springframework

vue+element的confirm提示消息文字变色和换行

效果: 思路: 可以考虑采用模板字符串的思路实现 代码: this.confirm(您确定要<b style"Color: red">${text}</b>的数据项&#xff1f;<br/>单位名称: ${row.companyName} <br/>属性: ${row.attributeName}).then(() > {console.log(确定…

SCM供应商管理怎么做?

在企业的供应链管理中&#xff0c;供应商管理是至关重要的一环。然而&#xff0c;传统的供应商管理方式常常面临诸多痛点&#xff0c;导致管理效率低下、成本增加、风险增大。不注重供应商管理的企业&#xff0c;常常会面临以下问题&#xff1a; 供应商档案管理难&#xff1a;…