UE5: Content browser工具编写02

DebugHeader.h 中的全局变量,已经在一个cpp file中被include了,如果在另一个cpp file中再include它,就会有一些conflicts。先全部给加一个static

  • Add static keyword to debug functions
  • Wrap all the functions inside of a namespace
  • print message to the screen when pressing delete unused assets
#pragma once
#include "Misc/MessageDialog.h"
#include "Widgets/Notifications/SNotificationList.h"
#include "Framework/Notifications/NotificationManager.h"static void Print(const FString& Message, const FColor& Color)
{if (GEngine){GEngine->AddOnScreenDebugMessage(-1, 8.f, Color, Message);}
}static void PrintLog(const FString& Message)
{UE_LOG(LogTemp, Warning, TEXT("%s"),*Message);
}static EAppReturnType::Type ShowMsgDialog(EAppMsgType::Type MsgType, const FString& Message,
bool bShowMsgAsWarning = true) 
{if (bShowMsgAsWarning == true) {FText MsgTitle = FText::FromString(TEXT("Warning"));return FMessageDialog::Open(MsgType, FText::FromString(Message), &MsgTitle);//return FMessageDialog::Open(MsgType, FText::FromString(TEXT("Warning: ") + Message));}else{return FMessageDialog::Open(MsgType, FText::FromString(Message));}
}static void ShowNotifyInfo(const FString& Message)
{FNotificationInfo NotifyInfo(FText::FromString(Message));NotifyInfo.bUseLargeFont = true;NotifyInfo.FadeOutDuration = 7.f;FSlateNotificationManager::Get().AddNotification(NotifyInfo);
}

EditorAssetLibrary.h里面,ListAssets的功能

UFUNCTION(BlueprintCallable, Category = "Editor Scripting | Asset")
static TArray<FString> ListAssets(const FString& DirectoryPath, bool bRecursive = true, bool bIncludeFolder = false);

ListAssets 函数中,bRecursive 是一个布尔变量,通常用来控制函数是否以递归方式列出某个目录下的所有资产(Assets)。(if we go inside of the subfolder)

  • bRecursivetrue 时,函数会递归遍历指定目录以及其所有子目录,并列出其中的所有资产。
  • bRecursivefalse 时,函数只会列出指定目录中的资产,而不会深入子目录。

bool bIncludeFolder

假设你的资产结构目录如下

/Assets
├── File1.uasset
├── Folder1
│   └── File2.uasset
└── Folder2
  • bIncludeFolder = true:
    输出可能是:File1.uasset, Folder1/, Folder1/File2.uasset, Folder2/

  • bIncludeFolder = false:
    输出可能是:File1.uasset, Folder1/File2.uasset

在content folder里面,不要碰collections和developers目录。DO NOT TOUCH ROOT FOLDER (COLLECTIONS/DEVELOPERS)

示例代码

// Copyright Epic Games, Inc. All Rights Reserved.#include "SuperManager.h"
#include "ContentBrowserModule.h"
#include "DebugHeader.h"
#include "EditorAssetLibrary.h"
#include "ObjectTools.h"//DeleteAssets()#define LOCTEXT_NAMESPACE "FSuperManagerModule"void FSuperManagerModule::StartupModule()
{InitContentBrowserExtension();
}void FSuperManagerModule::ShutdownModule()
{//This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,//we call this function before unloading the module.
}#pragma region ContentBrowserMenuExtension
void FSuperManagerModule::InitContentBrowserExtension()
{FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>(TEXT("ContentBrowser"));TArray<FContentBrowserMenuExtender_SelectedPaths>& ContentBrowserModuleMenuExtenders = ContentBrowserModule.GetAllPathViewContextMenuExtenders();//FContentBrowserMenuExtender_SelectedPaths CustomContentBrowserMenuDelegate;//CustomContentBrowserMenuDelegate.BindRaw(this, &FSuperManagerModule::CustomContentBrowserMenuExtender);//ContentBrowserModuleMenuExtenders.Add(CustomContentBrowserMenuDelegate);//***same with the two lines belowContentBrowserModuleMenuExtenders.Add(FContentBrowserMenuExtender_SelectedPaths::CreateRaw(this, &FSuperManagerModule::CustomContentBrowserMenuExtender));}TSharedRef<FExtender> FSuperManagerModule::CustomContentBrowserMenuExtender(const TArray<FString>& SelectedPaths)
{TSharedRef<FExtender> MenuExtender(new FExtender());if (SelectedPaths.Num() > 0) {//define the position//-> 是一个运算符,用于访问指针所指向对象的成员。MenuExtender->AddMenuExtension(FName("Delete"),//name of extension hook//we want to insert after DELETE(extension hook)EExtensionHook::After,TSharedPtr<FUICommandList>(),//no hotkey//first bindingFMenuExtensionDelegate::CreateRaw(this, &FSuperManagerModule::AddContentBrowserMenuEntry));//second bindingFolderPathsSelected = SelectedPaths;//then we have access to the folders that the user has currently selected};return MenuExtender;
}void FSuperManagerModule::AddContentBrowserMenuEntry(FMenuBuilder& MenuBuilder)
{//in this function we can define all the details for our menu entry //and we can use the menu builder to do soMenuBuilder.AddMenuEntry(FText::FromString(TEXT("Delete Unused Assets")),FText::FromString(TEXT("Safely delete all unused assets under folder")),FSlateIcon(),//empty placeholder//SECOND BINDINGFExecuteAction::CreateRaw(this, &FSuperManagerModule::OnDeleteUnusedAssetButtonClicked));
}void FSuperManagerModule::OnDeleteUnusedAssetButtonClicked()
{if (FolderPathsSelected.Num() > 1)//delete stuff in multiple folders will cause some unexpected behaviors{DebugHeader::ShowMsgDialog(EAppMsgType::Ok, TEXT("Please select ONE folder"));return;}//DebugHeader::Print(TEXT("Currently selected folder: ")+ FolderPathsSelected[0], FColor::Green);//pure debug, can be deleted laterTArray<FString> AssetsPathName = UEditorAssetLibrary::ListAssets(FolderPathsSelected[0]);if (AssetsPathName.Num() == 0){DebugHeader::ShowMsgDialog(EAppMsgType::Ok, TEXT("No Asset found under selected folder"));return;}//not finished yet//DebugHeader::ShowMsgDialog(EAppMsgType::Ok, TEXT("Delete Unused Assets"));//DebugHeader::Print(TEXT("Unused Assets Deleted"), FColor::Red);FString Message = FString::Printf(TEXT("A total of %d found.\nConfirm deletion?"), AssetsPathName.Num());//%d 是一个格式说明符,用于表示一个整数(int 类型)EAppReturnType::Type ConfirmResult =DebugHeader::ShowMsgDialog(EAppMsgType::OkCancel, Message);//error   error   //EAppReturnType::Type ConfirmResult = DebugHeader::ShowMsgDialog(EAppMsgType::OkCancel, TEXT("A total of ") + FString::Printf(AssetsPathName.Num()) + TEXT(" found.\nConfirm deletion?"));if (ConfirmResult == EAppReturnType::Cancel)return;TArray<FAssetData>UnusedAssetsDataArray;for (const FString& AssetPathNameWWWWW : AssetsPathName){if (AssetPathNameWWWWW.Contains(TEXT("Collections")) || AssetPathNameWWWWW.Contains(TEXT("Developers"))){continue;//不执行操作,继续循环}//DO NOT TOUCH ROOT FOLDER (COLLECTIONS/DEVELOPERS)if (!UEditorAssetLibrary::DoesAssetExist(AssetPathNameWWWWW)) continue;//if we don't do this, sometimes we will get some error message saying that Assets does not existTArray<FString> AssetReferencers = UEditorAssetLibrary::FindPackageReferencersForAsset(AssetPathNameWWWWW);//it is same with(delete asset from selection)if (AssetReferencers.Num() == 0)//this asset is unused//error   error   E0137	expression must be a modifiable lvalue//报错的中文意思是:“表达式必须是可修改的左值。”//这是因为在这段代码里,你错误地使用了单等号 = ,而不是双等号 == ,在比较语句中使用了赋值运算符。{const FAssetData UnusedAssetData = UEditorAssetLibrary::FindAssetData(AssetPathNameWWWWW);UnusedAssetsDataArray.Add(UnusedAssetData);}//塞入“无用资产”动态数组if (UnusedAssetsDataArray.Num() > 0){ObjectTools::DeleteAssets(UnusedAssetsDataArray);}else{DebugHeader::ShowMsgDialog(EAppMsgType::Ok, TEXT("No Unused Asset found under selected folder"));}}}#pragma endregion#undef LOCTEXT_NAMESPACEIMPLEMENT_MODULE(FSuperManagerModule, SuperManager)

可以将 C++ 中的 delegate 比作一个 “邮递员”

比喻解释:

  1. 邮递员:邮递员负责将信件从一个地方送到另一个地方。你把信件(消息、请求等)交给邮递员,告诉他该去哪个地址送达。

  2. 委托的角色

    • 发送者:在你的代码中,发送者(或发布者)就像是给邮递员信件的人。发送者生成一个事件(例如某个操作完成)并把它交给邮递员(委托)。
    • 邮递员(委托):邮递员不处理信件的内容,只负责把信件送到指定的地址。在委托的情况下,它会将事件传递给事先注册好的接收者(或订阅者)。
    • 接收者:接收者就像是收件人,当邮递员把信件送到他们那里时,他们会根据信件的内容采取相应的行动。

具体流程:

  • 注册接收者:想象一下,收件人提前告诉邮递员自己的地址(注册委托)。这样,当邮递员接收到信件时,他就知道要把信送到哪个地方。
  • 发送事件:当某个事件发生(例如按钮被点击),发送者会把这个事件的信息交给邮递员。
  • 处理事件:邮递员把信息传递给注册的接收者,接收者根据收到的信息执行相应的操作(例如,更新界面、执行某个功能等)。

优点:

  • 解耦合:使用邮递员的方式可以避免发送者和接收者之间的直接联系。发送者不需要知道接收者是谁,只需把事件交给邮递员。这样可以让代码更灵活,方便维护和扩展。
  • 多个接收者:就像一个邮递员可以把同一封信件送到多个收件人一样,委托可以有多个绑定的接收者,所有的接收者都会在事件发生时被通知。

总结:

将 C++ 中的 delegate 比作“邮递员”可以帮助你理解它的工作原理和用途:通过一个中介,将事件或消息从发送者传递给接收者,同时保持二者之间的解耦。这种方式在事件驱动编程和回调机制中非常有效。

使用 C++ 中的 delegate 可以实现一些直接调用函数所无法实现的功能:

1. 解耦合

  • 使用直接调用:如果直接调用一个函数,调用者需要了解被调用函数的具体实现和参数。这使得代码之间的耦合度增加。
  • 使用委托:通过委托,发送者和接收者之间没有直接关系。发送者只需要发布事件,接收者可以在不影响发送者的情况下独立处理事件。这种解耦合使得代码更加灵活,方便修改和扩展。

2. 动态绑定

  • 使用直接调用:在编译时,调用的函数是固定的,无法在运行时改变。
  • 使用委托:委托允许在运行时动态绑定多个回调函数。你可以根据不同的条件选择不同的回调,这种动态性在事件处理和响应用户输入时非常有用。

3. 多重订阅

  • 使用直接调用:直接调用通常只能调用一个函数。
  • 使用委托:一个委托可以绑定多个接收者,所有订阅这个委托的函数都会被调用。这种特性非常适合于需要通知多个对象的情况,如用户界面事件(按钮点击、状态变化等)。

4. 异步处理

  • 使用直接调用:直接调用函数通常是同步的,即调用者会等待函数执行完成后才能继续执行下一步。
  • 使用委托:委托可以与异步编程结合使用,允许事件在后台线程中处理,调用者可以继续执行其他任务,而不必等待事件处理完成。

5. 简化事件处理

  • 使用直接调用:如果要处理多种类型的事件,代码中会有大量的条件语句,增加了复杂性。
  • 使用委托:通过委托,可以创建更为简洁和结构化的事件处理代码,注册和注销事件处理器变得简单直观。

6. 回调机制

  • 使用直接调用:没有灵活的回调机制,调用者在调用函数时必须事先知道它将要做什么。
  • 使用委托:允许在某些操作完成时进行回调,例如在异步操作完成后执行特定的代码,或在游戏状态改变时更新界面。

例子:

假设你有一个游戏,玩家按下按钮时要播放音效并更新得分。使用直接调用时,按钮的点击处理代码需要直接调用音效播放函数和得分更新函数,这会使得代码紧密耦合。使用委托,你可以在按钮被点击时发布一个事件,多个处理函数(音效播放、得分更新)可以同时订阅这个事件并处理。

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

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

相关文章

【Redis技能熟练掌握之十年内功】

Redis技能熟练掌握之十年内功 1.redis是什么&#xff1f;为什么要使用redis&#xff1f;2.redis一般应用于什么场景&#xff08;四个场景&#xff09;&#xff1f;3. Redis持久化机制是什么&#xff1f;各自的优缺点&#xff1f;一般咋么用&#xff1f;4. redis五个基础类型支持…

【开源免费】基于SpringBoot+Vue.JS服装销售平台(JAVA毕业设计)

博主说明&#xff1a;本文项目编号 T 054 &#xff0c;文末自助获取源码 \color{red}{T054&#xff0c;文末自助获取源码} T054&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

docker -私有镜像仓库 - harbor安装

文章目录 1、镜像仓库简介2、Harbor简介3、下载与安装3.1、下载3.2、安装3.2.1、上传harbor-offline-installer-v2.8.2.tgz到虚拟机中解压并修改配置文件3.2.2、解压tgz包3.2.3、切换到解压缩后的目录下3.2.4、准备配置文件3.2.5、修改配置文件 4、启动Harbor5、启动关闭命令6、…

gitlab添加CI自动测试

1. CI运行规格配置文件.gitlab-ci.yml yml 配置文件语法&#xff1a; https://docs.gitlab.com/17.3/ee/ci/yaml/index.html 添加.gitlab-ci.yml文件并配置 &#xff1a; ## 定义几个阶段 stages: # List of stages for jobs, and their order of execution- buil…

982. 按位与为零的三元组

1. 题目 982. 按位与为零的三元组 2. 解题思路 随机选择两个数&#xff0c;记录两个数的与结果。以及它的次数。 然后再遍历数组&#xff0c;用第三个数去与前两个数的结果&#xff0c;如果等于0&#xff0c;则满足条件。 3. 代码 3.1. 注意点 首先用简单的思路切入&…

【顺序表使用练习】发牌游戏

【顺序表使用练习】发牌游戏 1. 介绍游戏2. 实现52张牌3. 实现洗牌4. 实现发牌5. 效果展示 1. 介绍游戏 首先先为大家介绍一下设计要求 实现52张牌&#xff08;这里排除大小王&#xff09;洗牌——打乱牌的顺序发牌——3个人&#xff0c;1人5张牌 2. 实现52张牌 创建Code对象创…

MMD模型及动作一键完美导入UE5-IVP5U插件方案(二)

1、下载并启用IVP5U插件 1、下载IVP5U插件, IVP5U,点击Latest下载对应引擎版本,将插件放到Plugins目录,同时将.uplugin文件的EnableByDefault改为false 2、然后通过Edit->Plugins启用插件 2、导入pmx模型 1、直接在Content的某个目录拖入pmx模型,选择默认参数 2、…

项目实战:k8s部署考试系统

一、新建nfs服务器&#xff08;192.168.1.44&#xff09; 1.基础配置&#xff08;IP地址防火墙等&#xff09; 2.配置时间同步 [rootlocalhost ~]# yum -y install ntpdate.x86_64 [rootlocalhost ~]# ntpdate time2.aliyun.com 27 Sep 10:28:08 ntpdate[1634]: adjust tim…

【巅峰算力,静谧之作】4卡4090GPU深度学习“静音”服务器

各位同仁&#xff0c;随着人工智能浪潮的汹涌澎湃&#xff0c;我们正步入一个前所未有的创新纪元。在这个充满挑战与机遇的时代&#xff0c;我愈发频繁地在工作场景中邂逅那些致力于深度学习探索的智者们。他们&#xff0c;对计算力的渴望如同对知识的追求一般&#xff0c;永无…

React表单:formik、final-form和react-hook-form

表单无处不在&#xff0c;它是每个网站的必备部分。在用React构建web应用时&#xff0c;处理表单是不可避免的。 你可以选择自己的方式来处理&#xff0c;或者选择社区中现成的库。然而&#xff0c;当你选择一个第三方库时&#xff0c;你会立即面临一个问题&#xff1a;有太多的…

Spring Boot 学习之路 -- 配置项目

前言 最近因为业务需要&#xff0c;被拉去研究后端的项目&#xff0c;代码框架基于 Spring Boot&#xff0c;对我来说完全小白&#xff0c;需要重新学习研究…出于个人习惯&#xff0c;会以 Blog 文章的方式做一些记录&#xff0c;文章内容基本来源于「 Spring Boot 从入门到精…

SpringMVC5-域对象共享数据

目录 使用ServletAPI向request域对象共享数据 使用ModelAndView向request域对象共享数据 使用Model向request域对象共享数据 使用map向request域对象共享数据 使用ModelMap向request域对象共享数据 Model、ModelMap、Map的关系 向session域共享数据 向application域共享…

SQLite3模块使用详解

目录 一、引言 1.1 SQLite3 简介 1.2 Python sqlite3 模块 二、连接数据库 2.1 导入 sqlite3 模块 2.2 连接数据库 2.3 创建游标对象 三、执行 SQL 语句 3.1 创建表 3.2 插入数据 3.3 查询数据 3.4 更新数据 3.5 删除数据 四、处理查询结果 4.1 fetchall() 4.2…

探探Java与python中的闭包

说在前面&#xff1a;在计算机科学中&#xff0c;闭包是指一个函数以及其引用的周围环境&#xff08;变量&#xff09;所组成的整体。简单来说&#xff0c;闭包允许一个函数访问并操作其外部函数作用域中的变量&#xff0c;即使外部函数已经执行完毕。 Java函数式编程—闭包&am…

C++map与set

文章目录 前言一、map和set基础知识二、set与map使用示例1.set去重操作2.map字典统计 总结 前言 本章主要介绍map和set的基本知识与用法。 一、map和set基础知识 map与set属于STL的一部分&#xff0c;他们底层都是是同红黑树来实现的。 ①set常见用途是去重 &#xff0c;set不…

【Java】包装类【主线学习笔记】

文章目录 前言包装类基本数据类型与包装类之间的转换基本数据类型转换为包装类可以通过以下几种方式&#xff1a;包装类转换为基本数据类型可以通过以下几种方式&#xff1a;初始化值不同与String之间的转换 前言 Java是一门功能强大且广泛应用的编程语言&#xff0c;具有跨平台…

“数字武当”项目荣获2024年“数据要素×”大赛湖北分赛文化旅游赛道一等奖

9月26日&#xff0c;由国家数据局、湖北省人民政府指导的首届湖北省数据要素创新大会暨2024年“数据要素”大赛湖北分赛颁奖仪式在湖北武汉举行。由大势智慧联合武当山文化旅游发展集团有限公司参报的武当山“数字武当”项目&#xff0c;荣获文化旅游赛道一等奖。 据悉&#x…

在系统开发中提升 Excel 数据导出一致性与可维护性的统一规范与最佳实践

背景&#xff1a; 在系统开发过程中&#xff0c;数据导出为 Excel 格式是一个常见的需求。然而&#xff0c;由于各个开发人员的编码习惯和实现方式不同&#xff0c;导致导出代码风格不一。有的人使用第三方库&#xff0c;有的人则自定义实现。这种多样化不仅影响了代码的一致性…

【笔记】X射线物理基础

一、X射线衍射分析简史 1895年X射线发现 1896 年 2 月对骨折的观察&#xff1a;G.和 E. Frost是第一个使用 X 射线进行医疗用途 1897 年法国海关官员的行李扫描。 X射线衍射理论1 X射线衍射理论2 元素的特征X射线 X射线光电子的应用 电磁波的粒子属性 X射线层析成像法 X-ray…

结构设计模式 -装饰器设计模式 - JAVA

装饰器设计模式 一. 介绍二. 代码示例2.1 抽象构件&#xff08;Component&#xff09;角色2.2 具体构件&#xff08;Concrete Component&#xff09;角色2.3 装饰&#xff08;Decorator&#xff09;角色2.4 具体装饰&#xff08;Concrete Decorator&#xff09;角色2.5 测试 结…