UE 将UObject写到Package,加载Package获取UObject

1,将UObject写到Package中

//CachedMesh 就是要写的UObject对象	
UStaticMesh* CachedMesh = CachedFontData.GetGlyphMesh(ShapedGlyph.GlyphIndex, TextParamValue.bOutline, TextParamValue.Extrude, TextParamValue.Bevel, TextParamValue.BevelType, TextParamValue.BevelSegments, TextParamValue.ArcRadius);
				
FString objectName = TEXT("MyCreateObject");

// 创建包
//FString packageName = TEXT("/Game/") + saveFolder/* + TEXT("/Test3D_") + FString::FromInt(index)*/;
FString packageName = TEXT("/、Meshs/Text3D")/* + saveFolder + TEXT("/Test3D_") + FString::FromInt(index)*/;
UPackage* package = CreatePackage(*packageName);
package->MarkPackageDirty();
FString StaticMeshName = (TEXT("Test3D_") + CachedMesh->GetFName().ToString() + TEXT("_") + FString::FromInt(ShapedGlyph.GlyphIndex));
UStaticMesh* AssetOnly = DuplicateObject(CachedMesh, package, FName(*StaticMeshName));
AssetOnly->SetFlags(RF_Public | RF_NeedPostLoadSubobjects | RF_Standalone);
FString packageNameEX;
packageName = packageName + TEXT("/Test3D_") + CachedMesh->GetFName().ToString() + TEXT("_") + FString::FromInt(ShapedGlyph.GlyphIndex);
FPackageName::TryConvertLongPackageNameToFilename(packageName, packageNameEX, TEXT(".uasset"));

// 保存Package
FSavePackageArgs SaveArgs = { nullptr, nullptr, EObjectFlags::RF_Standalone | EObjectFlags::RF_Public, SAVE_None, false, true, true, FDateTime::MinValue(), GError, nullptr };
UPackage::Save(package, AssetOnly, *packageNameEX, SaveArgs);

2,加载Package,读取其中的UObject

	TextParam TextParamValue{};
	FString packageName = TEXT("/Meshs/Text3D");
	IFileManager& MyFileManager = IFileManager::Get();
	FString packageNameEX;
	FPackageName::TryConvertLongPackageNameToFilename(packageName, packageNameEX, TEXT(""));
	if (MyFileManager.DirectoryExists(*packageNameEX))
	{
		TArray<FString> AssetName;
		MyFileManager.FindFiles(AssetName, *packageNameEX, TEXT("*.uasset"));
		FPXCachedFontData& CachedFontData = GetCachedFontData(DefaultFont);
		for (int i = 0; i < AssetName.Num(); i++)
		{
			TSet<FName> LoadTags = {};
			FString PackageName = packageNameEX + TEXT("/") + AssetName[i];
			UPackage* FoundPackage = FindObjectFast<UPackage>(nullptr, FName(*PackageName));
			if (FoundPackage == nullptr)
			{
				FLinkerInstancingContext InstancingContext(MoveTemp(LoadTags));
				FoundPackage = LoadPackage(nullptr, *PackageName, LOAD_None, nullptr, &InstancingContext);
				if (FoundPackage == nullptr)
					continue;
			}
			FString StaticMeshName = AssetName[i];
			StaticMeshName.RemoveFromEnd(TEXT(".uasset"));
			FoundPackage->GetLinker()->LoadAllObjects(true);
			UObject* CurrentObject = FoundPackage;
			CurrentObject = StaticFindObjectFastInternal(nullptr, CurrentObject, *StaticMeshName);
			UStaticMesh* StaticMesh = dynamic_cast<UStaticMesh*>(CurrentObject);
			if (StaticMesh == nullptr)
				continue;
			StaticMeshName = StaticMesh->GetName();
			TArray<FString> stringArray;
			StaticMeshName.ParseIntoArray(stringArray, TEXT("_"), false);
            //这步不需要,是项目的代码
			CachedFontData.AddGlyphMesh(StaticMesh, FCString::Atoi(*(stringArray.Last())), TextParamValue.bOutline, TextParamValue.Extrude, TextParamValue.Bevel, TextParamValue.BevelType, TextParamValue.BevelSegments, TextParamValue.ArcRadius);
		}
	}

3,代码解析

LoadObject

LoadObject主要是把磁盘中的东西加载到一个UObject里面去,因为涉及的对象可能会引用其他的资产,所以会触发一个递归的加载。过程如下:

  1. CreatePackage:因为每个UObject的最外层outer都是UPackage,所以会先调用CreatePackage创建一个UPackage,比如我们加载的路径是"Game/http://xx.xxx",那么"Game/xx"就是包名,创建的具体方法就是NewObject<UPacakge>。
  2. FLinkerLoad::CreateLinker:创建一个LinkerLoad,LinkerLoad主要负责去磁盘中加载UObject的数据,然后管理对应资产之间的一些引用。FLinkerLoad继承了FLinkTables,里面有一个导入和导出模块的定义。相关代码在下方
  3. FLinkerLoad::LoadAllObjects:加载包里所有的UObject,这里就是根据上面的ExportMap中的UClass信息,生成对应的UObject,然后把数据反序列化进去。
  4. StaticFindObjectFast:根据ObjectName找到加载完成的UObject并返回
class FLinkerTables
{
	/** The list of FObjectImports found in the package */
	//这个是这个包引用的对象,如果资产引用了其他资产,在这里会有体现
	TArray<FObjectImport> ImportMap;
	/** The list of FObjectExports found in the package */
	//这个是这个包要导出的对象,我们LoadObject需要加载的对象都在这里面记录
	TArray<FObjectExport> ExportMap;
}

LoadClass

LoadClass本质就是调用了LoadObject,代码如下:

UClass* StaticLoadClass( UClass* BaseClass, UObject* InOuter, const TCHAR* InName, const TCHAR* Filename, uint32 LoadFlags, UPackageMap* Sandbox )
{
    UClass* Class = LoadObject<UClass>( InOuter, InName, Filename, LoadFlags, Sandbox );
    return Class;
}

关于LoadClass的路径,LoadClass填路径要按照这样的格式"Game/xxx.xx_C",相比LoadObject,路径名后面多了一个"_C"。这种路径分为两个部分,一个是包名,也就是"."(点)前面的部分为。一个是ObjectName,UClass的ObjectName多个"_C"。在LoadObject的时候,会先把所有相关的UObject加载好,在FUObjectHashTables进行管理,然后根据这个ObjectName进行查找,所以如果LoadClass的时候后面不加个"_C",UClass是被加载到内存里的,但是就是在后面查找的时候会查找不到。

FindObject

有了上面对UObject的管理,UE也提供了FindObject这个接口用于查找Object,相关代码在StaticFindObjectFastInternalThreadSafe里面。内容也很简单,就不贴具体代码了,就是在上面提到的FUObjectHashTables里面找,先从HashOuter,找不到就到PackageToObjectListMap,再找不到就到Hash里面找。

参考:UE5:UObject加载与管理 - 知乎

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

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

相关文章

Ansible简介版

目录 架构 环境部署 一、Ansible安装部署 1.yum安装Ansible 2.修改主机清单文件 3.配置密钥对验证 4.ansible-doc 5.看被控主机 二、常用模块 1.Command模块 2.Shell模块 3.Cron模块 1.添加 2.删除 4.User模块 5.Group模块 1.创建组 ​编辑 ​编辑 ​编辑…

【redis】redis持久化分析

目录 持久化Redis持久化redis持久化的方式持久化策略的设置1. RDB&#xff08;快照&#xff09;fork(多进程)RDB配置触发RDB备份自动备份手动执行命令备份&#xff08;save | bgsave&#xff09;flushall命令主从同步触发动态停止RDB RDB 文件恢复验证 RDB 文件是否被加载 RDB …

c# - - - winform程序四个角添加圆角效果

winform 给窗体四个角添加圆角效果。 在窗体 Load 事件中添加如下代码&#xff1a; // 创建了一个圆角矩形的路径&#xff0c;并将其设置为控件的形状 System.Drawing.Drawing2D.GraphicsPath path new System.Drawing.Drawing2D.GraphicsPath(); int radius 30; path.AddAr…

KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记13 - STM32的SDIO学习5 - 卡的轮询读写擦

KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记13 - STM32的SDIO学习5 - 卡的轮询读写擦 一、前情提要二、目标三、技术方案3.1 读写擦的操作3.1.1 读卡操作3.1.2 写卡操作3.1.3 擦除操作 3.2 一些技术点3.2.1 轮询标志位的选择不唯一3.2.2 写和擦的卡状态查询3.2.3 写的速度 四、代…

跟TED演讲学英文:What moral decisions should driverless cars make by Iyad Rahwan

What moral decisions should driverless cars make? Link: https://www.ted.com/talks/iyad_rahwan_what_moral_decisions_should_driverless_cars_make Speaker: Iyad Rahwan Date: September 2016 文章目录 What moral decisions should driverless cars make?Introduct…

【笔试训练】day20

1.经此一役小红所向无敌 默认小红血量无限。直接计算出经过几轮攻击后&#xff0c;会出现人员伤亡。 对于对立来说他最多承受n轮光的攻击&#xff0c;对于光来说&#xff0c;他最多承受立得m轮攻击。 所以在经过min(n,m)轮回合之后&#xff0c;他们两个人至少死一个。活下来的…

已解决Error: Could Not Find a Version That Satisfies the Requirement XXX

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

大数据面试题(十):Hive的高频面试考点(二)

文章目录 Hive的高频面试考点 一、请说明Hive中 sort by ,order by ,cluster by ,distribute by各代表什么意思

Java多线程优化接口响应

同步查询 Override public MallOrder getById1(Long id) {long startTime System.currentTimeMillis();MallOrder mallOrder new MallOrder();mallOrder.setId(1L);mallOrder.setShopId(3L);mallOrder.setCustomerId(78L);mallOrder.setGoodsId(664L);mallOrder.setOrderTime…

java基础07(二维数组 方法)

目录 一. 二维数组 1. 声明 2. 初始化 3. 取值 赋值 4. 遍历 5. 一些细节 二. 方法 1. 方法的定义 1.1 无返回值方法 1.2 有返回值方法 2. 方法的调用 3. 动态参数 4. Overload 方法重载 一. 二维数组 二维数组的本质其实就是一维数组&#xff0c;只不过每个元素又是…

PCB光控打孔机第二版程序(一)

/*PCB机程序 XY同时启动 L9751 CODE61068 2018 6 19 08:00 固定位置释放吸盘*/ /*修正寻点第十二条结束调用计算坐标L5091&#xff0c;自动运行Y计算L6280 6281***/ /*** 开外部中断2关闭定时器2XY轴输出信号&#xff0c;自动运行循环检测外部中断高电平重启XY轴输出信号 增加寻…

node安装

1. node.js是用来干什么的&#xff1f; 简单来说&#xff0c;Node.js 是一个多功能的 JavaScript 运行环境&#xff0c;就像jdk是java的运行环境一样&#xff0c;不过node还提供了类似于tomcat一样的服务器功能&#xff0c;可以像后端一样运行起来拥有单独的地址和端口。 1.1…

Skywalking的重要功能详解

学习本篇文章之前首先要了解一下Sky walking的基础知识 分布式链路追踪工具Sky walking详解 一&#xff0c;Sky walking监控数据库 在admin服务中&#xff0c;连接数据库查询user表中所有数据 引入依赖 <dependency><groupId>mysql</groupId><artifactI…

Redis高级(Redis持久化,Redis主从模式,Redis哨兵模式,Redis分片集群)

目录 一、单机Redis 1. 问题说明 2. 安装Redis 1 解压安装Redis【备用】 2 配置Redis 3 启动Redis 3. 小结 二、Redis持久化 1. 持久化机制介绍 2. RDB模式 3. AOF模式 4. RDB和AOF对比 5. 小结 三、Redis主从模式 1. 介绍 2. 搭建Redis主从架构【备用】 3. 主…

软件测试与管理:黑盒测试-判定表驱动法

知识思维导图&#xff1a; 例题1&#xff1a;运用判定表驱动法设计测试用例。 某学生成绩管理系统&#xff0c;要求对“平均成绩在90分以上&#xff0c;且没有不及格科目的学生&#xff0c;或班级成绩排名在前5的学生&#xff0c;在程序中将学生的姓名用红色标识”&#xff0c;…

【前端】HTML实现个人简历信息展示页面

文章目录 前言一、 综合案例&#xff1a;个人简历信息展示页面 前言 这篇博客仅仅是对HTML的基本结构进行了一些说明&#xff0c;关于HTML的更多讲解以及CSS、Javascript部分的讲解可以关注一下下面的专栏&#xff0c;会持续更新的。 链接&#xff1a; Web前端学习专栏 下面我…

Python | Leetcode Python题解之第73题矩阵置零

题目&#xff1a; 题解&#xff1a; class Solution:def setZeroes(self, matrix: List[List[int]]) -> None:m, n len(matrix), len(matrix[0])flag_col0 Falsefor i in range(m):if matrix[i][0] 0:flag_col0 Truefor j in range(1, n):if matrix[i][j] 0:matrix[i]…

实时音视频通信的主要矛盾及解决方法

实时音视频通信的主要矛盾及解决方法 实时音视频通信的主要矛盾及解决方法实时音视频通信的主要矛盾矛盾的解决方法增加带宽减少数据量适当增加延时提高网络质量快速准确地评估带宽 总结参考 实时音视频通信的主要矛盾及解决方法 实时音视频通信的主要矛盾 实时音视频通信的主…

工厂模式+策略模式完成多种登录模式的实现

前提 &#xff08;简单工厂不属于设计模式&#xff0c;而是一种编程思想【抽象一层出来】&#xff09;工厂方法模式、抽象工厂模式 以上都是为了解耦&#xff0c;如果考虑多个纬度&#xff08;如需要同时考虑多种电器&#xff0c;多种品牌&#xff09;则优先考虑抽象工厂。 …

公网tcp转流

之前做过几次公网推流的尝试, 今天试了UDP推到公网, 再用TCP从公网拉下来, 发现不行, 就直接改用TCP转TCP了. 中间中转使用的python脚本, 感谢GPT提供技术支持: import socket import threadingdef tcp_receiver(port, forward_queue):"""接收TCP数据并将其放入…