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 是 nullptr
		FString* 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;//fixup

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

功能强大且简单易用的实时算法视频监控,智慧快消开源了。

智慧快消视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。 基于多年的深度…

Ngin入门套餐

快速了解Nginx 一、代理1.1 正向代理1.2 反向代理1.3 正向代理和反向代理的区别 二、Nginx负载均衡策略2.1 轮询&#xff08;Round Robin&#xff09;2.2 加权轮询&#xff08;Weighted Round Robin&#xff09;2.3 IP 哈希&#xff08;IP Hash&#xff09;2.4 最少连接&#x…

Unite Shanghai 2024 团结引擎专场 | 团结引擎 OpenHarmony 工程剖析

在 2024 年 7 月 24 日的 Unite Shanghai 2024 团结引擎专场演讲中&#xff0c;Unity中国 OpenHarmony 技术负责人刘伟贤对团结引擎导出的 OpenHarmony 工程进行了细节剖析&#xff0c;详细讲解 XComponent 如何与引擎结合&#xff0c;UI 线程和引擎线程的关联以及 ts/ets 的代…

PostgreSQL学习笔记六:模式SCHEMA

模式&#xff08;Schema&#xff09; PostgreSQL中的模式&#xff08;Schema&#xff09;是一个命名的数据库对象集合&#xff0c;包括表、视图、索引、数据类型、函数、存储过程和操作符等。模式的主要作用是组织和命名空间数据库对象&#xff0c;使得同一个数据库中可以包含…

Linux命令——ls

命令格式&#xff1a;命令本身选项命令的指向目标 1.ls命令作用为列出目录下的内容 #lls后的选项有[-a,-l,-h]##注意ls与选项间应用空格隔开. 如下图为&#xff08;ls命令体-l选项/根文件&#xff09;的命令行 # ls -a 为&#xff1a;列出所有文件&#xff08;包括隐藏文件&…

mysql 慢查询日志slowlog

慢查询参数 slow log 输出示例 # Time: 2024-08-08T22:39:12.80425308:00 #查询结束时间戳 # UserHost: root[root] localhost [] Id: 83 # Query_time: 2.331306 Lock_time: 0.000003 Rows_sent: 9762500 Rows_examined: 6250 SET timestamp1723127950; select *…

接口性能测试,这个还真有用啊。

一、概述 性能测试按照不同视角&#xff0c;可以分为以下几类&#xff1a; a. 用户视角的性能 用户角度感受到的网站响应速度的快和慢。从用户在浏览器输入网址/打开应用&#xff0c;到整个页面呈现给用户的耗时。包含了用户端发送请求&#xff0c;服务端收到并执行请求&…

【2024版】Pycharm安装教程+汉化教程(零基础小白都能学会)

PyCharm安装教程 点击右边链接→PyCharm安装包 以专业版为例&#xff0c;继续进行安装&#xff08;安装内容没啥太大区别&#xff0c;所以两版本都适用&#xff09; 2.打开解压后的文件夹&#xff0c;右击pycharm 2024.1.4 3.点击下一步。 4.更改安装位置&#xff0c;点击下一步…

海外云手机:出海电商养号智能化方案

随着出海电商的迅猛发展&#xff0c;使用海外云手机进行养号已经成为越来越多商家的新选择。尤其在社交电商推广和短视频引流方面&#xff0c;海外云手机不仅提高了流量的精准度&#xff0c;还助力商家实现业务的快速增长。本文将探讨海外云手机养号相较于传统模式的优势&#…

机载交互详解!

一、机载交互网络 机载交互网络是指飞机内部用于传输飞行员指令、飞行数据以及系统状态信息的通信网络。它通常由多个节点&#xff08;如传感器、控制器、显示器等&#xff09;和连接这些节点的通信链路组成。 节点&#xff1a; 传感器节点&#xff1a;负责采集飞机的各种飞…

基于YOLOv11的车辆行人实时检测系统(python+pyside6界面+系统源码+可训练的数据集+也完成的训练模型)

上百种【基于YOLOv8/v10/v11的目标检测系统】目录&#xff08;pythonpyside6界面系统源码可训练的数据集也完成的训练模型&#xff09;-CSDN博客 ............................................................................................ 摘要&#xff1a; 本文提出了…

人工智能AI与机器学习ML基础入门

小学生都能看懂的人工智能入门书籍 第一章 入门简介 TensorFlow 入门 如果你想入门人工智能&#xff08;AI&#xff09;&#xff1f;机器学习&#xff08;ML&#xff09;和深度学习是很好的起点。不过&#xff0c;一开始接触这些概念时&#xff0c;可能会被各种选项和新术语搞…

WebGl 使用uniform变量动态修改点的颜色

在WebGL中&#xff0c;uniform变量用于在顶点着色器和片元着色器之间传递全局状态信息&#xff0c;这些信息在渲染过程中不会随着顶点的变化而变化。uniform变量可以用来设置变换矩阵、光照参数、材料属性等。由于它们在整个渲染过程中共享&#xff0c;因此可以被所有使用该着色…

前端开发攻略---使用AJAX监控网络请求进度

1、XHR实现 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</title></head&…

用AI生成rtl设计(a simple synchronous FIFO)的一个实验

目录 1. 前言 2. RTL and testbench generation 2.1 RTL generation Explanation: Assumptions: 2.2 Testbench generation Explanation: 2.3 Add fsdb dump to testbench 3. 仿真与调试 3.1 RTL中的语法问题 3.2 testbench的问题 3.3 RTL中empty/full状态…

VS Code创建VUE项目(一)工具安装与项目创建

一.安装与配置npm 1.下载安装Node.js 安装Node.js 下载地址&#xff1a; Node.js — 在任何地方运行 JavaScript (nodejs.org)或下载 | Node.js 中文网 下载后一步步安装就好&#xff08;安装过程基本一路直接“NEXT”就可以了&#xff0c;直到Finished&#xff09;&#x…

第十五届蓝桥杯C/C++学B组(解)

1.握手问题 解题思路一 数学方法 50个人互相握手 &#xff08;491&#xff09;*49/2 &#xff0c;减去7个人没有互相握手&#xff08;61&#xff09;*6/2 答案&#xff1a;1024 解题思路二 思路&#xff1a; 模拟 将50个人从1到50标号&#xff0c;对于每两个人之间只握一…

内嵌服务器Netty Http Server

内嵌式服务器不需要我们单独部署&#xff0c;列如SpringBoot默认内嵌服务器Tomcat,它运行在服务内部。使用Netty 编写一个 Http 服务器的程序&#xff0c;类似SpringMvc处理http请求那样。举例&#xff1a;xxl-job项目的核心包没有SpringMvc的Controller层&#xff0c;客户端却…

李德仁院士携实验室及大势文旅团队参加“湖北旅游、武当突破”名家谈,分享数智文旅发展新经验

10月12日上午&#xff0c;2024世界武当太极大会在湖北省十堰市武当山盛大开幕。 2023年国家科学技术最高奖获得者、中国科学院、中国工程院院士、武汉大学李德仁教授携测绘遥感信息工程国家重点实验室&#xff08;后简称“实验室”&#xff09;团队以及大势智慧文旅团队&#…

gcc学习

理论 在使用 GCC (GNU Compiler Collection) 进行 C 或 C 程序的编译时&#xff0c;可以将整个过程分为四个主要阶段&#xff1a;预处理、编译、汇编和链接。下面是每个阶段的命令示例&#xff1a; 1. 预处理-E 预处理阶段会处理所有的预处理指令&#xff08;如 #include 和…