Version: 2021.1
资源数据库
AssetDatabase 批处理

刷新资源数据库

Unity 在以下情况下会刷新资源数据库:

  • Unity Editor 重新获得焦点时(如果已在 Preferences 窗口中启用 Auto-Refresh
  • 从菜单中选择 Assets > Refresh
  • 从 C# 调用 AssetDatabase.Refresh

其他一些 AssetDatabase API 会触发 Refresh(),但是仅针对您指定的资源。例如,CreateAsset()ImportAsset()

Unity 在资源数据库刷新期间执行以下步骤:

  1. 查找资源文件的更改,然后更新源资源数据库
  2. 导入并编译与代码相关的文件,例如 .dll、.asmdef、.asmref、.rsp 和 .cs 文件。
  3. 然后,如果未从脚本调用 Refresh,重新加载该域。
  4. 对导入的代码相关文件的所有资源进行后期处理
  5. 然后导入与代码无关的资源,并对所有剩余的导入资源进行后期处理
  6. 随后对资源进行热重载

资源数据库详细刷新过程

Unity 在资源数据库刷新期间执行以上部分中描述的步骤。本部分将进一步详细描述这一过程。这些步骤在一个循环中执行,某些步骤可能导致刷新过程重新启动(例如,导入资源时会创建其他资源,Unity 也需要导入这些资源)。

Unity 在以下情况下会重新启动资源数据库刷新循环:

  • 如果导入资源后,导入器用过的文件在磁盘中发生改变。
  • 如果在 OnPostProcessAllAssets 中调用了以下任一项:
  • 如果所导入文件的时间戳在导入时发生改变,会使该文件排队等待重新导入
  • 导入器在导入过程中创建了文件(例如,FBX 模型可以通过从模型提取纹理来重新启动“刷新”)。

查找磁盘中的更改

Unity 查找磁盘中的更改时会扫描项目中的 AssetsPackages 文件夹,从而检查自上次扫描以来是否已添加、修改或删除任何文件。它将所有更改收集到列表中,以供下一步处理。

更新源资源数据库

Unity 收集文件列表后,将为添加或修改的文件获取文件哈希。然后会使用这些文件的 GUID 来更新资源数据库,并会删除被检测到“已删除”的文件的条目。

依赖项跟踪

资源数据库跟踪两类资源依赖项:静态依赖项动态依赖项。如果资源的任何依赖项改变,Unity 都会触发该资源的重新导入。

静态依赖项

静态依赖项是导入器所依赖的值、设置或属性。静态依赖项在导入资源之前为已知状态,并且在导入过程中不受导入器行为的影响。如果资源的静态依赖项改变,Unity 将重新导入该资源。

一些常见静态依赖项如下:

  • 资源的名称
  • 资源关联的导入器的 ID
  • 导入器的版本
  • 当前选择的构建目标平台
动态依赖项

Unity 通常会在导入过程中发现资源的动态依赖项。这是因为这些依赖项是按源资源的内容定义的。例如,一个着色器可能引用另一个着色器,而一个预制件可能依赖于其他预制件。

导入器还可以根据源资源的内容,有条件地使用全局状态,在这种情况下也将成为动态依赖项。这种情况的示例包括目标平台、项目的颜色空间、图形 API、脚本运行时版本或纹理压缩状态。

Unity 将资源的这些动态依赖项存储在资源导入上下文 (Asset Import Context) 中。

导入和编译代码相关文件

在一系列已更改或已添加的文件中,Unity 收集与代码相关的文件,并将其发送到脚本编译管线。编译器从项目中的脚本文件和程序集定义文件生成程序集。有关此步骤的更多信息,请参阅脚本编译程序集定义文件的相关文档。

重新加载域

如果 Unity 检测到任何脚本更改,则会重新加载 C# 域。这样做的原因是可能已创建新的脚本化导入器 (Scripted Importer),它们的逻辑可能会影响“刷新”队列中的资源导入结果。此步骤会重新启动 Refresh() 以确保所有新的脚本化导入器生效。

导入与代码无关的资源

Unity 导入所有与代码相关的资源并重新加载域后,将继续导入其余资源。每个资源的导入器都会处理该类型的资源,并根据文件扩展名来识别应导入的文件类型。例如,TextureImporter 负责导入 .jpg、.png 和 .psd 文件等。

有两种类型的导入器:原生导入器 (Native Importer) 和脚本化导入器 (Scripted Importer),分别在单独的阶段进行处理。原生导入器组首先被处理,并包括大部分 Unity 的内置导入器。接下来处理脚本化导入器,它们是 C# 编写的自定义导入器,可扩展 Unity 的导入功能。

导入器导入资源文件时,会生成 AssetImportContext

AssetImportContext 用于报告资源的静态依赖项。

另外,在导入步骤中,会发生多次回调。

预处理资源导入器调用:

后处理资源导入器调用:

所有导入完成后触发的最后一个后处理回调是 OnPostprocessAllAssets

过程中可能会发生许多事件,这些事件将对 Asset 文件夹重新启动刷新过程,其中一些事件包括:

  • 如果资源导入失败

  • 如果在刷新的导入阶段修改了资源。例如,如果列表中的文件被修改,因此其修改日期与上次刷新的日期不符。如果在 Editor 获得焦点时开始从版本控制系统中提取文件,则会发生这种情况。

  • 如果资源在导入期间创建了其他资源。例如:导入 FBX 时,可以从 FBX 中提取纹理并将其置于项目中,这意味着 Unity 必须导入这些纹理(及其生成的任何 Artifact)。

  • 如果在某次预处理/或后处理回调期间或者在 OnPostProcessAllAssets 内强制重新导入某个文件,例如,使用 AssetDatabase.ForceReserializeAssetsAssetImport.SaveAndReimport。注意,如果执行此操作,必须小心,不要引起无限的重新导入循环。

  • 如果在编译脚本后发生程序集重新加载。如果在刷新过程中生成 C# 文件,必须先编译这个新文件,以便 Unity 重新启动刷新。

  • 如果将资源另存为“仅文本”,但是必须将此资源序列化为二进制文件,这时会发生重新启动。(例如,必须将包含地形的场景序列化为二进制文件,因为如果在文本文件中将地形数据视为一系列字符,则此数据将很难处理。)

热重载

热重载是指在 Editor 开启的状态下由 Unity 导入脚本和资源并应用所有更改的过程。无论 Editor 是否处于运行模式 (Play Mode),都可能发生此情况。无需重新启动应用程序和 Editor 即可使更改生效。

更改并保存脚本时,Unity 会热重载项目的所有脚本数据。它首先将所有可序列化变量的值存储在所有加载的脚本中,重新加载脚本,然后恢复这些值。在热重载期间,存储在不可序列化变量中的所有数据都将丢失。

Note: 由(内置 DefaultImporter)[BuiltInImporters]导入的资源在脚本资源之前导入,因此不会为默认资源调用任何脚本定义的 PostProcessAllAssets 回调。

刷新结束

一旦完成所有这些步骤,就完成了 Refresh() 并使用相关信息更新了 Artifact 数据库,还会在磁盘中生成必要的导入结果文件。

资源数据库
AssetDatabase 批处理