诚如之前所说,虚幻4主要的一些特性都是由UObject穿针引线在一起的,想把虚幻玩到比较深的程度,UObject是迟早要面对、回避不得的问题,所以,准备在其它主题之前,先把UObject好好弄一下。UObject主要完成了哪些工作呢?私以为:

反射系统

UObject体系构建了整个虚幻反射系统的核心,每个UObject都来自于一个UClass,这个Class可以是Unreal Header Tool(以后统一遵循官网命名:UHT)生成的,也可以是来自于Blueprint生成的(UBlueprintGeneratedClass)。反射可以说是现在主流引擎的构建基础,对国内多数人而言,可能更熟悉的是Unity透过Mono构建出来的反射,它的重要性不言而喻。

反射很大一坨的东西,具体就不说了,它最大的作用,相当于在运行时动态生成代码,可以省掉很多手写代码的工作量。否则像UE这样复杂的界面,全部Hardcode,100人是绝对不够的,改一次所需的时间也是无法接受的。有了反射之后,剩下的很多就是很好理解的一条路就顺下来了:属性编辑器自动生成、自动消息包收发、自动序列化、自动生成BP节点、BP和C++的自动接口交互、自动浅拷贝深拷贝、甚至按照设定规则来进行拷贝……不胜枚举。

共通性都是一样:Get Class,Get Property,或者Get Function,分析Property和Function的属性,然后,设值、获取值、Invoke函数……

垃圾回收和生命期管理

UObject构建了虚幻的垃圾回收(GC)系统。GC这东西众说纷纭,但博主本人持乐观态度。最近的公司业务就遇到这么个事儿:脚本里需要发动态包,于是就需要在脚本里手动生成一个动态包,并挂接在包上面。为了完成这个目的,我就必须在脚本中制作一个生成动态包的节点,然后问题来了,我们必须还得要一个回收动态包的节点,否则这个动态包就无法回收……于是最后放弃了,回到了包里加各种Reserved的老路上去……有了GC,多数情况下都不用管这事儿……你让一个策划去理解回收这种事情,就是在给他们添麻烦,那本不是他们业务内的范畴。

GC的存在价值,并非是让事情变得简单这么简单,更多时候它能让你节省下很多编程心力,把精力花在真正该关注的地方。真GC出问题时去查错所带来的成本,未必比忘写delete带来的成本要大,说不定反而更小。

虚幻的垃圾回收系统,基本上就是从Root开始,不断遍历所有的Property,标记其为使用中。最后再遍历一遍,确认哪些Object没有标使用中就给它删掉。基本上,你不需要管这个过程,因为反射的作用,所以相关的信息都是UE自动就帮我们处理好的。有几个要注意的:

"Singleton",需要一直存在的,直接AddToRoot。

F类本身是不走垃圾回收的,但是F 类内部又有U类,这种情况下你需要注意AddReferencedObjects。把F类内部的U类给加入到GC树上。

Classes里的类,标UPROPERTY的UObject属性会被自动加入到当前类的GC列表里,但不标的会不会,没有具体跟,反正习惯随手写个就行了。

TArray和TMap里面的UObject会被自动加入GC列表,但是如果写的是std::vector和std::map,则应该是不会的,需要手动用AddReferencedObjects加进去。

资源管理

UObject最后一个作用是构建了虚幻的资源管理体系。包括资源的搜索、资源之间的引用管理,下面详细展开。

首先要先说一下虚幻的Object命名,由于资源也都是UObject,所以其命名与UObject是同一个标准。按照现在的要求,是[类名']路径名/路径名/Asset名.[包内路径.]Object本名:[属性名]['](一般是Object所在类名+一个数字后缀)。比如:

Brush'/Script/Engine.Default__Brush'

BillboardComponent'/Script/Engine.Default__TextRenderActor:Sprite'

/Engine/TemplateResources/MI_Template_BaseGray_03_Metal.MI_Template_BaseGray_03_Metal

这个名称解析跟UE3和UDK略有不同,UE3由于基于upk来对包进行管理,而又限制Content文件夹下的Upk包不能重名,所以不需要前面的路径名。UE4基于Asset,Content不同子目录下可以有同名UAsset,所以路径名就是不可或缺的了。除此之外,Asset跟UPK没有太多不同,我们后面说包,也是指的UAsset,虽然看起来这个不像包。

理论上,所有的UObject都可以交由StaticLoadObject来加载(事实上也确实是这么做的),但是很多类是有基于LoadObject的特殊实现的,比如UClass(Blueprint Class),就必须用StaticLoadClass,而地图必须使用LoadMap,LevelStreaming这样地图相关的加载流程。这些变种的主要区别是会针对相应的情况做一些特殊的处理和操作。但是核心都绕不开StaticLoadObject。所以搞明白这个StaticLoadObject,实际上就搞明白了虚幻主要的资源组织结构。

主要的流程如下:

解析路径,找到对应包(UAsset或者UPK),如果还没加载则加载包。

判断Object是否已经加载,如果已经加载则直接返回。

对资源包的加载,会把整个资源包的所有Object全部预加载的(创建并调用PreLoad,对于资源等需要PostLoad的调用PostLoad)。同时,加载包时创建ULinkerLoad,这个LinkerLoad会自动分析每个包与其他包之间的关联,通过Imports来记录本包对其它包的引用,通过Exports记录本包内的Object。

加载后,看看目标对象是不是个Redirector,如果是Redirector,则说明"曾经有个包在这里,但是被移动到新地方去了",就重定位到必要的地方。

说了这么多,其实你明白原理就很简单:虚幻所有对象都是按照一个包含了路径、包内路径、对象类名的唯一名称来命名的。而虚幻所有的包都是会记录对其它包的引用的。

所以一旦一个包的路径、对象的包内路径、以及对象类名本身发生变化,都可能会导致旧有资源的丢失和重定向。

当然,相关也都有一些机制可以帮助你事后修正(比如Redirector,Engine.ini里的Redirector config),但是,那都是补救措施,不能100%保证成功补救。好的情况,重新定位一下资源引用什么的就可以解决,但是最糟糕的情况下,有可能会导致数据丢失(其中最容易发生的就是因为BP类名修改,导致子BP类无法找到父BP类而导致子类无法正常使用只能删了重来……)

所以,在做UE4的包路径转移、资源名修改之前,一定要做好备份工作。最好是把所有原型迭代完毕后,统一进行类似操作,并经常存档或发SVN、GIT。

相关的注意事项:

Redirector需要提醒一点,虚幻里进行资源文件从一个文件夹到另一个文件夹的移动,一定要在编辑器中进行。因为虚幻资源之间的引用关系是通过前面说的Object命名来保证的,而路径名又是Object的一部分,名称不对等很容易发生问题。而编辑器移动资源后,有时候会发现移动前所在的路径下多了一个1KB字节左右小尾巴,这个小尾巴就是Redirector,同样不要手动删除,而是要在资源查看器里,通过对Redirector(需要Filter开启)的Fix up命令来进行删除。

先把Redirector打开

然后Fixup,或者

右键直接文件夹,Fix up Redirectors in Folder。

由于包是"Link Load"的,加载过程中会分析引用,所以如果包比较碎,这里就会由于做了更多的文件访问而导致速度变慢。单如果单个包内数据量较大,则也会导致加载单个包时速度变慢的情况,归根到底,就是权衡啊权衡。(一般说来,10个1k > 1个10k)

Transient对象不会被存盘,Transient包(GetTransientPackage)是一个特殊的包,所有临时对象都应该创建在这个包里面。

异步实际并非真正异步。LoadObject加载过程中有一系列的全局变量,而且这些全局变量维护时没有任何锁,所以也无法真正做到异步加载。所以虽然您看到接口上有LoadPackageAsync,但那个的实现是在主线程每帧区分时间片来实现的。不过话说回来,多线程读包真的有必要吗?机械硬盘的访问速度本身是最大的限制因素,读包过程中的多线程,CPU其实帮不上任何忙。

真正大量磁盘或网络数据的异步加载可以参考Texture Streaming(为何只有Texture做了Streaming就是因为这玩意儿现在是游戏最吃资源的了,十个模型的资源量不见得比得上一张贴图啊),先把Object和少量基本信息当作占位符加载进来,Object的实际数据则放到其他线程里慢慢加载。如果您有类似需求,可以考虑这个方案。不过感觉是没必要,比如我们游戏常用的角色异步加载什么的,其实走主线程时间片完全够了。

编辑器中的资源会被标记为Standalone,在无引用时仍然存在,其它还有一系列不会被GC的情况,需要注意。

http://blog.csdn.net/noslopforever/article/details/40562219

虚幻4 Object和序列化相关推荐

  1. C# 类对象数据存储(Object自定义序列化)

    获取Object对象的所有成员变量: FieldInfo[] fields = obj.GetType().GetFields(); // obj可以为任意类型对象 获取变量名称: string na ...

  2. 虚幻4随笔 三 从UE3到UE4

     笔者有幸参与过两个UE3项目,完全不同的使用方法,总共用了5.6年.引擎学习最好还是能参与项目,自己看的话往往容易纠结到一些细节上去,而引擎之所以是引擎,重要的恰恰是在容易被人忽视的工作流上.单从 ...

  3. PHP Session中保存Object

    在PHP中,使用Session保存Object时,PHP会将Object自动序列化.在读取Session变量时,准确地说是在session_start时,PHP会将Session中已序列化的Objec ...

  4. 每日一博 - Java序列化一二事儿

    文章目录 what Why 作用 常用API java.io.Serializable java.io.Externalizable java.io.ObjectOutputStream java.i ...

  5. Java程序员必备:序列化全方位解析

    前言 相信大家日常开发中,经常看到Java对象"implements Serializable".那么,它到底有什么用呢?本文从以下几个角度来解析序列这一块知识点~ 什么是Java ...

  6. python建立数据库并序列化_Python之数据序列化(json、pickle、shelve)

    一.python类型数据和JSON数据格式互相转换 pthon 中str类型到JSON中转为unicode类型,None转为null,dict对应object 二. 序列化/反序列化 将对象转换为可通 ...

  7. 快速序列化组件MessagePack介绍

    简介 MessagePack for C#(MessagePack-CSharp)是用于C#的极速MessagePack序列化程序,比MsgPack-Cli快10倍,与其他所有C#序列化程序相比,具有 ...

  8. java 复制对象_Java程序员必备:序列化全方位解析

    前言 相信大家日常开发中,经常看到Java对象"implements Serializable".那么,它到底有什么用呢?本文从以下几个角度来解析序列这一块知识点~ 什么是Java ...

  9. I/O(输入/输出)---序列化与反序列化

    概念: 序列化就是将对象的状态存储到特定的介质中的过程,也就是将对象状态转换为可保持或传输格式的过程. 反序列化则是从特定存储介质中将数据重新构建对象的过程.可以将存储在文件上的对象信息读取,然后重新 ...

最新文章

  1. currenttimemillis 毫秒还是秒_Elasticsearch(ES)如何做到亿级数据查询毫秒级返回
  2. 一文详解C++文件读写(FileStorage、txt)
  3. 计算机主机电池馈电,电脑主机电池没电引起故障怎么处理
  4. linux内核dentry结构学习
  5. JSON与Struts2的结合使用
  6. php 获取请求,php获取http请求的头信息的方法
  7. PowerDesigner pdm生成Access的方法
  8. ifen.os x pe.dmg天翼云_3.3K屏显纵览天下 11代酷睿横行职场 华硕灵耀X纵横值得选择...
  9. SE_01 需求分析
  10. springboot中banner图制作
  11. 深度学习之ISAR超分辨率成像
  12. 鸿蒙系统1004无标题,华为P50 Pro外观基本确认:居中开孔全面屏首发鸿蒙操作系统...
  13. 企业核心-不是技术而是人才
  14. c++ linux utf-8 编码 中文汉字分割(超简单代码)
  15. android高斯模糊平均值,高斯模糊
  16. PyQt5 教程 《日期和时间》
  17. 个人网站搭建及IIS部署(2019/3/11)个人心得分享
  18. 【Matlab】RGB, HSV 颜色空间绘制
  19. Android基于环信SDK开发IM即时聊天(二)
  20. r4be和服务器主板稳定性,升级进化 华硕R4BE主板细节解析_华硕 Rampage IV Black Edition_主板评测-中关村在线...

热门文章

  1. C++ 比较两个字符串的“大小”
  2. 组合体视图的画图步骤_(完整版)组合体视图画法教案
  3. delphi 实现屏幕旋转代码_代码检查 | 如何用Processing实现3D世界
  4. 子进程中获取父进程id_进程全家桶,看这一篇就够了 | 原力计划
  5. 7的整除特征 三位一截_「每周一课」数字和除号握手言和,来攻克整除问题
  6. python 字典由值找键_python字典怎么根据值返回键
  7. cocos android 剪切板,Cocos Creator 点击按钮复制到剪切版
  8. 在Windows 10上安装TensorFlow 2.2.0 RC4版
  9. 17.立体匹配——匹配两个图 Matlab实战,立体效果_3
  10. android+proguard目录,Android proguard问题:路径可能不是null或空字符串.路径=“空”...