Unity Asset workflow Manual阅读记录(AssetDatabase部分,Version ----2020.3)

Asset workflow

这一章主要介绍了Unity与资源打交道的相关功能,资源在Unity里也叫Assets,介绍大概分为以下几个部分:

  • 常见Asset的类型
  • Asset Packages
  • 使用Asset Store
  • AssetBundles
  • The Asset Database
  • Scripting with assets

同样还有三个相关的内容:

  • Unity Accelerator under the Unity Services section
  • Asset Server (Team License) under the Legacy section
  • Asset Store Publishing(应该是在Asset Store上发布自己的assets)


How Unity imports assets

当资源文件位于Unity的工程里时,Unity会自动导入和管理相关数据,在导入一个资源文件时,Unity会自动做下面三件事:

  • 为对应的assets文件创建独一无二的ID
  • 为该文件创建一个.meta文件
  • Unity process the asset

对于特别复杂的物体导入Unity时,可能会有更复杂的操作,后面再提,Unity还有单独的一章Importing,可以在ImportSettings进行相关设置。

Unique IDs
Unity里每一个资源文件,都会有一个独特的ID,Unity应该会有一个数据结构去记载这些文件的ID,然后在Unity的Editor界面下,Unity会不断用Loop去检查Assets里的文件,如果找到了文件A,但没有找到对应的ID(感觉这里是不是把文件的路径和ID做了一个Map?),那就说明A文件是新增的文件,那么Unity会为A创建一个Unique ID,这个ID是Unity内部记录该文件的reference,有了ID作为引用去跟别的资源或脚本关联,就不用担心文件的重命名和路径移动等问题了,这些ID会记录到对应的.meta文件里。


.meta文件
.meta文件是Unity自动生成的,但是在Project视窗里被默认隐藏了,但可以手动开启显示(You can make them visible by selecting Visible Meta Files from the Mode project setting)。.meta文件会记录对应Unity Asset的ID,也正是这个原因,为了方便查找,.meta文件往往会放在asset文件的同目录下,关于.meta文件需要注意:

  • 当在Unity的Editor界面下的Project里操作文件时,Unity都会对相应的.meta文件进行合适的操作
  • 但如果在Unity外部操作,去移动或重命名一个资源文件,需要同时移动或重命名对应的.meta文件
  • 如果上面这样操作没有对相应的.meta文件进行处理,那么打开UnityEditor时,拿移动文件来举例,Unity会发现资源里有一个文件没有对应的.meta文件,还有一个.meta文件没有找到相同路径的资源文件,那么Unity会把前者当做一个新的资源,重新生成一个新的.meta文件,对于原本的.meta文件,Unity会自动删除这个孤儿。。。

举个例子,一个Texture资源被多个Material引用,一旦自己去Unity外部的文件资源管理器里删除该Texture的.meta文件,那么回到Unity后,这些Material就都找不到原本使用的Texture了,脚本组件也是一样的道理


Empty folders, meta files, and version control
Unity里Assets文件夹下的文件夹都会有各自的.meta文件,Unity里空的文件夹也会有.meta文件,但是有的版本控制工具不支持空文件夹,所以它会出现只有.meta文件,没有空文件夹的情况。

针对这种情况,Unity对空文件夹有一些特殊的处理,分为两种情况,有空文件夹没.meta文件,和有.meta文件没有空文件夹:
(1)如果Unity检测到一个空文件夹,但是没有检测到对应的.meta文件,然后Unity知道这个空文件夹之前是有对应的.meta文件的(也就是说判断出来这个空文件夹不是新生成的),那么Unity就判断是版本控制工具删掉了对应的.meta文件,所以Unity会删掉这个空文件夹。
(2)同理,如果Unity检测到了一个文件夹的.meta文件,但是没有看到文件夹,那么就会自动生成一个空的文件夹。


Asset processing
当Assets处于Unity里时,或者在打开UnityEditor的情况下,把任意外部的file拖拽进Unity时,Unity都会自动读取这个文件,并进行处理,把它转换成Unity内部使用的相关格式,这些文件本身不变,但相关转换后的数据会存储在Unity工程的Library目录下。

这样做的好处有:

  • 保留原始数据,实际转换的数据放在Library里,这样在Editor下的Runtime就可以直接读取GameReadyData,Runtime下如何修改都不会影响实际的asset
  • 转换成Internal数据后,可以在Unity的Inspector等窗口里显示其属性,在Editor里更改属性能直接在Scene里立马看到表现效果

Library文件夹下的东西都是Unity自动生成的,不应该也没有必要去改变人为的改变里面的东西,版本控制里也不应该提交Library文件夹下的内容。


Importing complex assets
对于复杂的资源,Unity可能会在Project里生成不止一个物体,下面是Unity对一些复杂资源的处理方式:

  • 导入一个带有Materials或者embedded textures的.fbx文件时,Unity会把里面的Material和embedded textures提取出来作为单独的资源文件
  • 导入一个图像文件作为多个2D sprites时,需要使用2D Sprite Editor对这个大的image进行划分,从而得到多个单独的Sprite Asset文件
  • 导入一个包含多个动画timeline或多个clips的3D文件时,Unity会根据其Animation Import Settings来划分出单独的动画timeline或AnimationClip

Assets and their import settings
资源文件的.meta文件里除了会包含资源对应的unique ID,还会记录其相关的Inspector窗口下看到的Import Settings信息,拿Texture资源举例,.meta文件会记录其Texture Type、Wrap Mode、Filter Mode和Aniso Level等Import Settings.

当修改Inspector数据时,是如何改变Unity内部相关数据结构的呢? Unity会在用户更改Inspector里的数据时,把修改后的数据记录到资源对应的.meta文件里,然后Unity会Re-import这个资源,从而改变Library里存放的Game-ready Data.

Unity项目用于版本控制的时候,注意提交Assets和ProjectSettings文件夹就行了,Temp和Library文件夹千万不要加上去:

When backing up a project, or adding a project to a version control repository, include the main Unity project folder, containing both the Assets and ProjectSettings folders. Unity relies on the information in these folders in order to reimport your assets and reconstruct your game or application. Don’t back up the Library and Temp folders or put them under version control.



Unity里的常见资源类型

Image文件
Unity支持通用的图像文件,比如BMP、TIF、TGA、JPG和PSD。 If you save your layered Photoshop (.psd) files in your Assets folder, Unity imports them as flattened images.

FBX and Model files
Unity支持导入FBX和SketchUp文件
Note: 也可以直接使用3D制作软件内置的格式,比如.max、.blend、.mb、.ma,把这些文件直接放到Unity的Assets目录下,Unity会在Import这些文件的时候,会自动调用文件格式对应的3D软件的FBX文件导出的插件功能,不过还是建议直接在美术软件里导出.fbx文件(Importing native 3D formats requires that the 3D modeling software be installed on the same computer as Unity.)

Meshes and animations
Unity支持以下格式的模型文件格式,Your Mesh file does not need to have an animation to be imported. 如果使用动画,可以导入一个文件,这个文件包含多个动画片段,也可以导入多个文件,每一个文件代表一个动画片段,这些都会在Importing章节里详细介绍

Audio files
如果在Assets文件夹里存了未压缩的音频文件,Unity会根据相关的压缩设置来导入对应的音频文件。

Other asset types
所有情况下,Unity都不会修改放进Unity工程里的源文件,当在Unity的Inspector里改变资源的导入属性时,Unity会进行Re-import操作,改变Unity内部相关的game-ready data. 对于.blender这样的特殊文件,需要在安装Unity的电脑上同时安装Blender软件,这样Unity会自动调用Blender的转fbx的插件。

Standard Assets
Unity附带了很多的Standard Assets,包括以下内容:

  • 2D
  • Cameras
  • Characters
  • CrossPlatformInput
  • Effects
  • Environment
  • ParticleSystems
  • Prototyping
  • Utility
  • Vehicles


Asset package

Unity可以把一批资源文件进行压缩,存储到一个后缀为.unitypackage的文件里,有点像是一个zip文件一样,不过这里压缩的是Unity的文件,包括对应的.meta文件。

从Unity2020.1开始,UnityEditor里没有内置的AssetStore Window了,需要去 https://assetstore.unity.com/上下,下载完了后,可以直接import,也可以在package manager里进行导入。

下载下来的.unitypacke默认目录

  • macOS: ~/Library/Unity/Asset Store-5.x
  • Windows: C:\Users\accountName\AppData\Roaming\Unity\Asset Store-5.x


The Asset Database

前面提到了,当一个资源放到Unity里时,Unity会执行Import操作,会把资源的格式转换为Unity的internal格式,数据会放在Library文件夹下。这种转换是很有必要的,因为往往原生的数据格式的存储方式更倾向去节省文件存储空间,但它往往并不适用于GPU、CPU等硬件的读取,举个例子,Unity导入一个.png图片作为texture时,它不会在runtime使用原始的.png文件,而是会创建一种新的图片格式的文件,存在Library文件夹里,这种格式是Unity内部的imported version,Unity会把它加载给GPU做图形显示

Asset Database翻译过来就是资源数据库,它存储了这些被转换到Unity内部格式的临时数据。

Asset import dependencies
The Asset Database keeps track of all the dependencies for each asset, and keeps a cache of the imported versions of all the Assets. 也就是说Assset Database记录了一个asset在导入Unity时依赖的所有东西,举个例子,一个导入到Unity的Internal数据m_Data,它会依赖以下东西

  • 存放在Unity的源数据,毕竟m_Data是根据源数据导入到Unity内生成的
  • target platform of your project,项目的目标平台,它决定了m_Data的格式
  • 资源的Import Settings,比如说texture的压缩方式

如果上述依赖的东西发生了更改,那么Cache就失效了,Unity就会Re-import,然后更新这些Cache

Asset caching
The Asset Cache is where Unity stores the imported versions of assets. 其实应该就是之前提到的Unity将资源转换为的Game-ready data,存放在Library文件夹下,一般VCS是不会引入这个文件夹的。

However, if you work as part of a team and use a version control system, it might be beneficial to also use Unity Accelerator, which shares the Asset Cache across your LAN.

像我之前开发的项目,太大了,每个新人打开Unity,光是那么多的资源,电脑就得导入好久。为了解决这个问题,Unity提供了一个叫Unity Accelerator的东西,它可以在所有人用相同的局部网的情况下,在服务器为团队的每个人存储和提供the cached versions of Assets。

关于Package的Dependency
前面说的Dependency应该和这里Package Manager的Dependency不一样,对于Package Manager,提到dependency的时候,往往指的是一个specific package version,指的是工程使用的package版本,这些dependencies会放在工程的manifest文件里,Dependency也氛围Direct Dependency和Indirect Dependency两种,如果projects直接使用一个Package A,那么A是项目的Direct Dependency,但如果这个Package A又需要依赖Package B,那么对于项目来说,B是项目的Indirect Dependency.


Source Assets and Artifacts
Unity在Library文件夹里维护了两种database文件,它们一起叫做Asset Database,分为两类:

  • The source Asset Database: 记录关于源文件的meta信息,通过这个可以判断该文件是否被修改过,从而是否需要reimport,里面存的信息有:文件的hash、上一次修改的date、GUIDs或者其他信息
  • The Artifact database: Artifacts are the results of the import process, Each Artifact contains the import dependency information, Artifact meta-information and a list of Artifact files.

二者的信息可以在下列相对路径里找到:

  • Source Asset Database: Library\SourceAssetDB
  • Artifact Database: Library\ArtifactDB


Importing an Asset
前面提到,把资源放进Unity,在Unity打开工程的时候Unity会自动import这些资源,但Unity同样提供了脚本来进行资源Import:

// 使用AssetDatabase.ImportAsset方法导入资源
using UnityEngine;
using UnityEditor;

public class ImportAsset {
    
    
    [MenuItem ("AssetDatabase/ImportExample")]
    static void ImportExample ()
    {
    
    
        AssetDatabase.ImportAsset("Assets/Textures/texture.jpg", ImportAssetOptions.Default);
    }
}

这里有一个导入时可以指定的参数枚举ImportAssetOptions,具体有以下选项可以指定:

  • Default
  • ForceUpdate:User Initiated asset import,应该是用于强行reimport目标资源,即使资源没发生改动
  • ForceSynchronousImport:保证调用这个函数的时候,立马进行资源import,比如导入脚本资源,脚本可能不会马上被导入( For example, when importing a scripts + prefabs, scripts have to be fully compiled before Prefab is serialized, otherwise it might get old variables.)
  • ImportRecursive:当Import一个文件夹时,同时也import里面所有的内容
  • DontDownloadFromCacheServer:强迫产生一个完全的重新导入,不使用cache里原有的信息
  • ForceUncompressedImport:Forces asset import as uncompressed for edition facilities.

Loading an Asset
应该要保证Import后再Load吧,没啥特别的:

using UnityEngine;
using UnityEditor;

public class ImportAsset {
    
    
    [MenuItem ("AssetDatabase/LoadAssetExample")]
    static void ImportExample ()
    {
    
    
        Texture2D t = AssetDatabase.LoadAssetAtPath("Assets/Textures/texture.jpg", typeof(Texture2D)) as Texture2D;
    }
}


File Operations using the AssetDatabase
由于Unity里的文件都与.meta文件息息相关,所以最好就不用C#自身的文件系统API了,最好就用Unity的AssetDatabase的API,如下所示:

  • AssetDatabase.Contains
  • AssetDatabase.CreateAsset
  • AssetDatabase.CreateFolder
  • AssetDatabase.RenameAsset
  • AssetDatabase.CopyAsset
  • AssetDatabase.MoveAsset
  • AssetDatabase.MoveAssetToTrash
  • AssetDatabase.DeleteAsset

Asset Database Version
Asset Database其实有两个版本,这里的Manual参考的是2020.3的版本,之前的记录说的都是Asset Database V2的版本,V2的版本是在Unity2019.3开始的默认的Asset Database的方式,而老的版本(the legacy version (version 1)) 的Unity之前版本的默认的Asset Database的版本,V1和V2上表现不一样,在Unity2020+的版本,V1已经不可以再用了

Platform Switching and reimporting
在Unity上转换platform会使得Unity去reimport相关的assets,比如不同的platform会有不同的texture的格式,所以改变平台时textures都会需要reimport。

当使用V2版本的Asset Database时,Unity内置的importers会在import 的结果里存储相应的平台的hash(the platform is part of the hash that the Asset Database uses to store the import results for Unity’s built-in importers),所以对于同一个文件,在不同的平台的导入信息会存在不同的cache file里面。

这个特性会使得当把项目转换到一个新平台的时候,往往要reimport半天的资源,但如果转回来原本的platform就快了,因为之前导入过,相关的Cache还是在的。



Refreshing the Asset Database

Unity会在以下情况下刷新Asset Database:

  • When the Unity Editor regain focus(if you have enabled Auto-Refresh in the Preferences window),即从外部exe切换到Unity的时候
  • 在menu里点击Assets->Refresh的时候
  • 从C#里调用AssetDatabase.Refresh函数的时候

还有一些其他的AssetDatabase的API可以Refresh指定的asset,并不是刷新整个database,比如CreateAsset() and ImportAsset().

在刷新Asset Database的时候,Unity做了以下事情:

  1. 查找Asset files,找到发生了改变的file,然后更新the source Asset Database
  2. 导入和编译代码相关的文件,比如.dll、.asmdef、.rsp和.cs文件
  3. It then reloads the domain, if Refresh was not invoked from a script. 这个Domain是什么,不太理解
  4. It post-processes all of the Assets for the imported code-related files
  5. It then imports non-code-related Assets and post-processes all the remaining imported Assets
  6. It then hot reloads the Assets

可以看出来,Unity会最先处理code相关的文件,对他们进行编译,然后就是处理与code相关的资源文件,最后才处理其他的无关文件,最后有个hot reload的操作,后面会再提。


The Asset Database detailed refresh process

这段内容是对前面的六个步骤的补充介绍,上述的步骤是在一个Loop里面去执行的,其中的某些步骤可能会使整个Loop重新开始,比如说在第五步里创建了一个.cs文件,那么这个Loop又会跳转到第一步重新开始执行

Unity restarts the Asset Database refresh loop under the following conditions:

  1. 如果文件在import后,文件又在磁盘上发生了改变
  2. 如果在第五步处理所有文件的时候,调用以下资源相关的函数(If, in OnPostProcessAllAssets, you call any of the following):
  • ForceReserializeAssets
  • AssetImporter.SaveAndImport
  • Any AssetDatabase API that queues an additional Refresh, such as MoveAsset, CreateAsset and ImportAsset
  1. 如果file的导入过程中,file的timestamp改变了,那么它会被加入到reimport的queue里
  2. 当在import过程,文件导入后又创建了新的文件(for example, FBX models can restart a Refresh by extracting their Textures from the model)

总而言之,就是当import过程中,资源的文件又发生改变的时候,可能又要重新import和fresh

Look for changes on disk
Unity是如何发现磁盘上的哪些文件发生了改动的呢,它是通过扫描Assets和Packages文件夹,与上一次scan的结果,查看是否有文件变化,它会搜集出来这些changes,放到一个list里,准备Step2

Update Source Asset Database
根据上面的list,Unity会通过GUID来操作相关的文件,比如说删除文件等

Dependency tracking
前面提到过一次,这里再详细说一下,Asset Database提供了两种资源Dependency: Static Dependency和Dynamic Dependency。

Static Dependency指的是importer依赖的值,这种值在资源import之前就已经定好了,而且该值不会受资源import过程的影响(Static dependencies are known before the Asset is imported, and are not affected by the behavior of the importer during the import process)
下面的属性都属于Static Dependencies:

  • Asset的名字
  • ID of the importer associated with the Asset
  • The version of the importer
  • The currently selected build target platform

Dynamic Dependency指的是资源间的依赖,比如说一个Shader对另一个Shader的依赖,一个Prefab对其他Prefab的依赖。
The importer might also use a global state conditionally_ _based on the content of the source asset, in which case it also becomes a dynamic dependency. Examples of this are the target platform, the Project’s color space, the graphics API, the scripting runtime version, or the Texture compression
state.

Unity stores these dynamic dependencies of an Asset in an Asset Import Context.

Import and compile code-related files
在前面的list里,Unity会单独把与code相关的文件记录下来,发送到script compilation pipeline,编译器会为这些文件生成assemblies和assembly definition files。

Reload the domain
If Unity detects any script changes, it reloads the C# domain(什么是domain,后面的Appendix会提一下), It does this because new Scripted Importers could have been created, and their logic could potentially impact the import result of Assets in the Refresh queue. This step restarts the Refresh() to ensure any new Scripted Importers take effect.

当Unity检测到脚本改变的时候,它会重载C# domain,因为可能已经生成了新的脚本Importer,对应的逻辑可能会影响在Refresh queue里的资源导入结果,这一步会重新调用Refresh函数,保证创建的脚本Importer发挥了作用

Import non-code-related Assets
当Unity导入完code和code相关部分的资源后,并reload domain后,会开始处理剩余的code无关的资源,每一个资源都有其对应类型的Importer,会根据文件后缀名去判断是否处理文件,比如TextureImpoter会找到发生改变的.jpb、.png和.psd文件,负责将其导入Unity

两类Importers
Unity分为两类Importers:Native Importers和Scripted Importers
Native Importers是Unity内置的Importer,它为Unity基本的资源类型提供了Import功能(比如3Dmodels, Textures和audio files)

Unity提供的Native Importers可以参考这里,里面提供了FBXImporter、TextureImporter和NativeFormatImporter等,NativeFormatImporter针对的是Unity内部的格式,比如.anim、.controller等

Unity提供了Scripted Importers使用户可以定制自己的Importer,同时也可以override Unity原本已有的Native Importer,注意,Unity提供的一些Impoter本身也是Scripted Importer,Unity提供的Scripted Importer有:

  • StyleSheetImporter ( for .uss files )
  • UIElementsViewImporter ( for .uxml files )

在Unity导入一个asset文件时,会产生一个AssetImportContext文件,The AssetImportContext is used to report the Static Dependencies of an asset,在这个过程中,Unity还可能会调用很多回调函数:

在Asset Importer之前可能会调用的函数:

  • OnPreprocessAsset
  • OnPreprocessAnimation
  • OnPreprocessAudio
  • OnPreprocessModel
  • OnPreprocessSpeedTree
  • OnPreprocessTexture

在Asset Importer之后可能会调用的函数:

  • OnAssignMaterialModel
  • OnPostprocessAnimation
  • OnPostprocessAssetbundleNameChanged
  • OnPostprocessAudio
  • OnPostprocessCubemap
  • OnPostprocessGameObjectWithAnimatedUserProperties
  • OnPostprocessGameObjectWithUserProperties
  • OnPostprocessMaterial
  • OnPostprocessMeshHierarchy
  • OnPostprocessModel
  • OnPostprocessSpeedTree
  • OnPostprocessSprites
  • OnPostprocessTexture

当所有的importing完成的时候还会调用下面的回调函数:

  • OnPostprocessAllAssets

当发生以下情况时,the refresh process will be restarted:

  • 导入asset失败
  • Refresh阶段asset被改变,比如在Import阶段,再去拉VCS
  • 如果导入一个asset会产生其他的asset
  • If you force the re-import of a file during one of the pre/post process callbacks or inside OnPostProcessAllAssets, for example, using AssetDatabase.ForceReserializeAssets or AssetImport.SaveAndReimport. Note, you must be careful not to cause infinite reimport loops if you do this.
  • If an Assembly Reload happens after compiling scripts. If you generate a C# file during the refresh process, that new file must then be compiled, so Unity restarts the refresh.
  • If you save an asset as “Text only” but the Asset must be serialized as binary, a restart will happen. (For example, Scenes with Terrains in them must be serialized as Binary, since the terrain data would be unwieldy if viewed as an array of characters in a text file.)

Hot reloading
Hot reloading refers to the process where Unity imports and applies any changes to scripts and assets while the Editor is open. 其实就是打开UnityEditor时Unity自动导入和刷新更改后的文件的过程,比如更改了一个C#脚本,回到Unity,Unity就会自动hot reloading来编译该脚本

Unity会先改变所有已经load进来的脚本里所有的serializable variables,It first stores all serializable variables in all loaded scripts and, and after it loads the scripts, it restores them. All of the data that was not serializable is lost after a hot reload.

Note: Default assets are imported before script assets, so any script-defined PostProcessAllAssets callbacks are not called for default assets.

End of Refresh
Once all these steps have completed, the Refresh() is complete and the Artifact Database is updated with the relevant information, as well as having the necessary import result files generated on disk.



Batching With the AssetDatabase

当使用Unity的AssetDatabase的代码去修改Assets内的文件时,可以使用Batching来减少这一段操作所用的时间。比如如果不使用Batching,Unity会这样处理这段代码:

// 第一次process,再对整个进行Refresh操作
AssetDatabase.CopyAsset("Assets/Asset1.txt", "Assets/Text/Asset1.txt");
// 第二次process,再对整个进行Refresh操作
AssetDatabase.MoveAsset("Assets/Asset2.txt", "Assets/Text/Asset2.txt");
// 第三次process,再对整个进行Refresh操作
AssetDatabase.DeleteAsset("Assets/Asset3.txt");

适用于Batching是下面这几个函数:

  • AssetDatabase.ImportAsset
  • AssetDatabase.MoveAsset
  • AssetDatabase.CopyAsset
  • AddObjectToAsset

Methos to process operation
可以使用AssetDatabase.StartAssetEditingAssetDatabase.StopAssetEditing来设置batching区间,在这个期间,AssetDatabase不会再自动处理资源数据,为了处理资源的导入,Unity这里用了一个Counter机制,类似于引用计数。

If you make more than one call to StartAssetEditing, you must make the corresponding number of calls to StopAssetEditing to make the Asset Database resume its normal behavior of automatically processing changes.
This is because these functions increment and decrement a counter, rather than acting as a simple on/off switch. Calling StartAssetEditing increments the counter, and calling StopAssetEditing decrements the counter. The Asset Database resumes its normal behavior when the counter reaches zero.
The reason Unity uses a counter rather than a simple on/off boolean is so that if your code executes multiple nested “start” and “stop” pairs, the inner pairs do not accidentally re-enable the Asset Database’s normal behavior too early. Instead, each pair increments and decrements the counter by one, and if your code is correctly nested, the final outer call to StopAssetEditing sets the counter to zero.
Note: Your code should never cause the counter to go below zero. Doing so generates an error.

代码示例:

using UnityEditor;
public class StartStopAssetEditingExample : MonoBehaviour
{
    
    
    [MenuItem("APIExamples/StartStopAssetEditing")]
    static void CallAssetDatabaseAPIsBetweenStartStopAssetEditing()
    {
    
    
        try
        {
    
    
            //Place the Asset Database in a state where
            //importing is suspended for most APIs
            AssetDatabase.StartAssetEditing();
            AssetDatabase.CopyAsset("Assets/Asset1.txt", "Assets/Text/Asset1.txt");
            AssetDatabase.MoveAsset("Assets/Asset2.txt", "Assets/Text/Asset2.txt");
            AssetDatabase.DeleteAsset("Assets/Asset3.txt");
        }
        finally
        {
    
    
            //Adding a call to StopAssetEditing inside
            //a "finally" block ensures that the AssetDatabase
            //state will be reset when leaving this function
            AssetDatabase.StopAssetEditing();
        }
    }
}

Using try…finally for Asset Editing
上面的代码使用了tri…finally的结构,这样做是为了防止在Import期间出错,导致AssetDatabase.StopAssetEditing()没有被调用,使用try…finally可以保证这段代码的调用。
具体的例子可以看这里



Scripted Importers

Scripted Importers属于Unity 脚本API的一部分,可以用Scripted Importers定义任何文件的Unity导入流程。

可以创建一个类,实现特定文件的导入流程,这个类需要继承于抽象类ScriptedImporter,同时需要apply the ScriptedImporter attribute,注意,这里的Scripted Importer不能处理Unity本身就Natively支持导入的资源类型。

如何使用Scripted Importers
把写好的脚本放到unity的工程目录里,Unity就会自动使用这个脚本去处理相关格式的文件导入了

Real-world use of Scripted Importers
Alembic: The Alembic importer plug-in has been updated to use a Scripted Importer. For more information, visit Unity github: AlembicImporter.
USD: The USD importer plug-in has been updated to use a Scripted Importer. For more information, please visit Unity github:: USDForUnity.



## Importer Consistency 前面提到的Asset Importer,不管是Unity自带的Native Importer,还是用户自定义的Scripted Importer,都需要满足同样的性质,对于Importer来说,相同的输入,即源文件的输入,应该得到相同的结果。为了保证这一点,Unity的Asset Database提供了两种方式来进行check工作: - 在Editor里reimport资源文件,在Unity里重新导入文件的时候,Unity会把import的结果与原本的结果进行比对,如果二者不同,Unity会给与警告:`Importer() generated inconsistent result for asset(guid:) ""` - 在开启Editor的时候使用-consistencyCheck的命令行参数

Editor log
前面提到了,当Unity进行比对时,如果发现inconsistency,会在Editor里进行提示,提示会包含以下内容:

  • 哪个资源没有通过consistency check
  • 资源的GUID
  • The content hash for the asset import result
  • How it compares to the previous revision of the asset

例子如下:

ConsistencyChecker - guid: a1945cd7aab67441ba89015f97494624, dependenciesHash.value: fb8cfb407bba82d4daded6031688ba9b, artifactid: 07078a054d3f597b4c2cc47e8e4c0bde, producedFiles[0].extension: , producedFiles[0].contentHash: 8490a5ed35a4361d679e6055a386969e

ConsistencyChecker - guid: a1945cd7aab67441ba89015f97494624, dependenciesHash.value: fb8cfb407bba82d4daded6031688ba9b, artifactid: 07078a054d3f597b4c2cc47e8e4c0bde, producedFiles[1].extension: .info, producedFiles[1].contentHash: 4bd9140e19d2e44782f1131172e514ba

ConsistencyChecker - guid: a1945cd7aab67441ba89015f97494624, dependenciesHash.value: fb8cfb407bba82d4daded6031688ba9b, artifactid: 646d6432767729ea7d288c636183de97, producedFiles[0].extension: , producedFiles[0].contentHash: 5ca760170f85012ce16aa8c22e8d9ea1

ConsistencyChecker - guid: a1945cd7aab67441ba89015f97494624, dependenciesHash.value: fb8cfb407bba82d4daded6031688ba9b, artifactid: 646d6432767729ea7d288c636183de97, producedFiles[1].extension: .info, producedFiles[1].contentHash: 4bd9140e19d2e44782f1131172e514ba

Importer(ScriptedImporter:Assembly-CSharp::RandomImporter) generated inconsistent result for asset(guid:a1945cd7aab67441ba89015f97494624) "Assets/first.rand"


Appendix

什么是C# domain
Application domain是逻辑上的一个进程里的独立的容器,如下图所示:
在这里插入图片描述
使用Application Domain的好处:

  • 可以在Domain里加载和卸载DLL,不会影响其他Domain
  • 如果有个第三方的DLL,但是可能并不可靠,那么可以把它放到一个isolated app domain里,给与其less privileges,比如不允许它访问C盘数据
  • You can run different versions of DLL in every application domain.

相关代码的示例可以参考这里

猜你喜欢

转载自blog.csdn.net/alexhu2010q/article/details/115086751