文档连接
可寻址资产开发周期
可寻址资产的主要优点之一是将您如何安排,构建和加载内容分离。传统上,这些发展方面紧密地联系在一起。
1.传统资产管理
如果在Resources目录中安排内容,则该内容将内置到基础应用程序中,并且必须使用Resources.Load提供资源路径的方法来加载内容。要访问存储在其他位置的内容,您可以使用direct references或AssetBundles。如果使用AssetBundles,您将再次按路径加载,将您的加载和组织策略联系在一起。如果您的AssetBundle是远程的或依赖于其他捆绑包,则您必须编写代码来管理所有捆绑包的下载、加载和卸载。
2.可寻址资产管理
给资产分配一个地址,无论您在项目中的哪个位置或如何构建资产,都可以使用该地址来加载资产。您可以毫无问题地更改可寻址资产的路径或文件名。您也可以将可寻址资产从Resources文件夹或本地构建目标移至其他构建位置(包括远程构建位置),而无需更改加载代码。
资产组架构
Schemas定义了一组数据。您可以将schemas附加到Inspector中的资产组。附加到组的一组Schemas定义了构建时如何处理其内容。例如,在packed mode构建时,附加了BundledAssetGroupSchema Schemas 的组充当Asset Bundles的来源。您可以将schemas集组合到用于定义新组的模板中。您可以通过AddressableAssetSettings 的Inspector添加schema模板。
3.构建脚本
构建脚本在项目中被表示为实现了IDataBuilder接口的ScriptableObject资产。用户可以创建自己的构建脚本,然后通过其Inspecotr面板添加他们到AddressableAssetSettings object中。要在Addressables Groups 窗口(Window > Asset Management > Addressables > Groups)中应用构建脚本,请选择Play Mode Script,,然后选择一个下拉选项。当前,已实现三个脚本来支持完整的应用程序构建,并提供三个用于在编辑器中进行迭代的播放模式脚本。
播放模式脚本
Addressable Assets包具有三个构建脚本,这些脚本创建Play mode数据以帮助您加速应用程序开发。
-
Use Asset Database(更快)
使用Asset Database模式(BuildScriptFastMode)可让您在游戏流程中快速运行游戏。它直接通过Asset Database加载资产,以进行快速迭代,而无需进行分析或创建AssetBundle。 -
Simulate Groups(高级)
Simulate Groups mode(BuildScriptVirtualMode)在不创建AssetBundle的情况下分析内容的布局和依赖性。资产通过从Asset Database ResourceManager加载,就像它们是通过bundles加载一样。要查看游戏过程中bundles何时加载或卸载,请在Addressables Event Viewer窗口(Window > Asset Management > Addressables > Event Viewer)中查看资产使用情况。
Simulate Groups mode可帮助您模拟加载策略并调整内容组,以找到正式版本的适当平衡。 -
Use Existing Build(requires built groups)
Use Existing Build mode最接近于已部署的应用程序构建,但是它要求您将数据构建作为一个单独的步骤。如果您不修改资产,则此模式是最快的,因为在进入播放模式时它不处理任何数据。您必须通过选择Build > New Build > Default Build Script或者在游戏脚本中使用AddressableAssetSettings.BuildPlayerContent()
方法,在Addressables Groups窗口(Window > Asset Management > Addressables > Groups)中为该模式构建内容。
如果在New Build下有不可单击的No Build Script Available,请检查AddressableAssetSettings的Inspecotr面板并查看Build and Play Mode Scripts部分。为了在Addressables Groups窗口中的New Build下出现选项,必须有一个构建脚本ScriptableObject是能够建立类型AddressablesPlayerBuildResult与AddressableAssetSettings的Inspector窗口中Build and Play Mode Scripts部分的一个入口配对 。
要添加一个new Build或Play Mode脚本,点击Build and Play Mode Scripts部分下的+号,然后找到您的build mode资产。添加后,如果该脚本是Play Mode脚本,它将显示在Window > Asset Management > Addressables > Groups > Play Mode Script下。如果脚本能够构建[AddressablesPlayerBuildResult],它将显示在Window > Asset Management > Addressables > Groups > Build > New Build下。默认情况下提供的Build和Play Mode脚本(包括BuildSciptPackedMode)位于Assets/AddressableAssetsData/DataBuilders。有关自定义构建脚本的更多信息,请参见前面的“构建脚本”部分。
4.分析与调试
默认情况下,可寻址资产仅记录警告和错误日志。你可以启用详细的日志记录,通过打开Player settings窗口(Edit > Project Settings... > Player),导航到Other Settings > Configuration部分,然后在Scripting Define Symbols输入框添加ADDRESSABLES_LOG_ALL。
您还可以通过取消选中AddressableAssetSettings objectInspector面板中的Log Runtime Exceptions选项来禁用异常。如果需要,你可以在自己的异常处理程序中实现ResourceManager.ExceptionHandler属性,但这应该在Addressables完成运行时初始化之后完成(请参见下文)。
5.初始化对象(Initialization objects)
您可以将对象附加到Addressable Assets settings,然后在运行时将其传递给初始化过程。该CacheInitializationSettings对象在运行时控制Unity的缓存API。要创建自己的初始化对象,请创建一个实现IObjectInitializationDataProvider接口的ScriptableObject 。这个系统的Editor component组件负责创建随运行时数据序列化的ObjectInitializationData。
6.自定义URL评估
在几种情况下,您需要在运行时自定义资产(通常是AssetBundle)的路径或URL。最常见的示例是创建signed URLs。另一个可能是dynamic host determination。
下面的代码是将查询字符串附加到所有URL的示例:
//Implement a method to transform the internal ids of locations
string MyCustomTransform(IResourceLocation location)
{
if (location.ResourceType == typeof(IAssetBundleResource) && location.InternalId.StartsWith("http"))
return location.InternalId + "?customQueryTag=customQueryValue";
return location.InternalId;
}
//Override the Addressables transform method with your custom method. This can be set to null to revert to default behavior.
[RuntimeInitializeOnLoadMethod]
static void SetInternalIdTransform()
{
Addressables.InternalIdTransformFunc = MyCustomTransform;
}
当捆绑的视频文件转换成Addressables的意图加载在Android平台上它们,你必须创建一个CacheInitializationSettings object,在该object上禁用Compress Bundles,如果该object没有被添加到Initialization Objects的列表,请将其添加到AddressableAssetSettings object的Initialization Objects列表中。
7.内容更新工作流(Content update workflow)
Unity建议将游戏内容分为两类:
- Cannot Change Post Release:您永远不会期望更新的静态内容。
- Can Change Post Release:您希望更新的动态内容。
在这种体系中,标记为的内容Cannot Change Post Release随应用程序一起提供(或在安装后立即下载),并且驻留在很少的大捆绑包中。
标记为Can Change Post Release的内容最好在线存储,以尽量减少每次更新所需的数据量。可寻址资产系统的目标之一是使这种结构易于使用和修改,而不必更改脚本。
而且当您不想发布全新的应用程序构建时, Addressable Assets System还可以适应需要更改标记为Cannot Change Post Release的内容的情况。
请注意,在不允许远程更新的情况下(例如当前许多视频游戏机或没有服务器的游戏),您应该每次都进行完整而全新的构建。
这个怎么运作
可寻址对象使用内容目录将地址映射到每个资产,并指定在何处以及如何加载它。为了使您的应用程序能够修改该映射,原始应用程序必须知道此目录的在线副本。要进行设置,请在AddressableAssetSettings的Inspector面板启用 Build Remote Catalog设置。这样可以确保目录的副本已建立并从指定的路径加载。一但应用发布后此加载路径就无法更改。内容更新过程将创建目录的新版本(具有相同的文件名),以覆盖先前指定的加载路径上的文件。
构建app会生成一个唯一的app内容版本字符串,该字符串标识每个app应加载的内容目录。给定的服务器可以包含app多个版本的目录而不会发生冲突。我们将所需的数据存储在addressables_content_state.bin文件中。这包括版本字符串,以及标记为Cannot Change Post Release的组中包含的任何资产的哈希信息。默认情况下,它位于Project目录中的Assets/AddressableAssetsData/<platform>,其中<platform>表示你所在的目标平台。
该addressables_content_state.bin文件包含在Addressables system中每个Cannot Change Post Release资产组的哈希和依赖项信息。建立到StreamingAssets文件夹的所有组都应标记为Cannot Change Post Release,尽管大型远程组也可以从该名称中受益。在下一步期间(准备更新内容,如下所述),此哈希信息确定是否有任何Cannot Change Post Release组包含已更改的资产,因此需要将那些资产移至其他位置。
唯一的捆绑ID
当将AssetBundle加载到内存中时,Unity强制让具有相同的内部名称不能加载两个包。这可能会在运行时更新捆绑包方面带来一些限制。既然Addressables支持在初始化之外更新目录,则可以更新已经加载的内容。
要使此工作有效,必须发生以下两种情况之一。一种选择是在更新目录之前,卸载所有可寻址内容。第二个选项是确保更新的AssetBundle具有唯一的内部标识符。这样,这允许你加载新的bundles,然而旧的仍然在内存中。我们有一个选项可以启用第二个选项。在AddressableAssetSettings的Inspector面板中打开“Unique Bundle IDs”选项 。此选项的缺点是它需要重新构建bundles的依赖链。这意味着如果您在一个组中更改了material,则默认情况下将仅重建material的bundle。启用“Unique Bundle IDs”后,引用该material的任何资产也将需要重建。
准备内容更新
如果您在任何Cannot Change Post Release组中都修改了资产,则需要运行“ Check for Content Update Restrictions”命令。这会将所有修改后的资产从Cannot Change Post Release组中移出,并将它们移至新组。生成新的资产组:
- 在Unity编辑器中打开Addressables Groups窗口(Window > Asset Management > Addressables > Groups)。
- 在Addressables Groups窗口中,选择顶部菜单栏上的Tools,然后选择Check for Content Update Restrictions。
- 在打开的Build Data File对话框中,选择addressables_content_state.bin文件(默认情况下,该文件位于Project目录下的Assets/AddressableAssetsData/<platform>,其中<platform>是你的目标平台)。
此数据用于确定自上次构建app以来已修改了哪些资产或依赖项。系统将这些资产移至新的组,以准备内容更新构建。
注意:如果所有更改都限于Can Change Post Release组,则此命令将不执行任何操作。
重要提示:在运行准备操作之前,Unity建议分支您的版本控制系统。准备操作以适合于更新内容的方式重新排列资产组。分支确保下次运行一个新player时,您可以返回到首选的内容安排。
构建内容更新
要构建内容更新:
- 在Unity编辑器中打开Addressables Groups窗口(Window > Asset Management > Addressables > Groups)。
- 在Addressables Groups窗口中,在顶部菜单上选择Build,然后选择Update a Previous Build。
- 在打开的Build Data File对话框中,选择现有app构建的构建文件夹。构建文件夹一定包含一个addressables_content_state.bin文件(默认情况下,该文件位于Project目录下的Assets/AddressableAssetsData/<platform>,其中<platform>是你的目标平台)。
这个构建会生成内容目录,哈希文件和AssetBundles。
生成的内容目录与所选App构建中的目录名称相同,将覆盖旧的目录和哈希文件。App加载哈希文件以确定是否有新目录。系统将从与App一起提供或已经下载的现有bundles中加载未修改的资产。
系统使用addressables_content_state.bin文件中的内容版本字符串和位置信息来创建AssetBundles。不包含更新内容的AssetBundles将使用他们在构建时选择的相同名字写入更新(保持不变)。如果AssetBundle包含更新的内容,则将生成一个新的AssetBundle,其中包含更新的内容以及一个新文件名,以便它可以与原始文件共存。只有具有新文件名的AssetBundle将复制到托管你内容的位置。
系统还会为无法更改(cannot change)的内容构建AssetBundles,但您无需将它们上载到内容托管位置,因为没有可寻址资产资产条目引用它们。
请注意,您不应在构建新player和进行内容更新(例如,player code, addressables)之间更改build脚本。这可能会在你的App中导致无法预料的行为。
在运行时检查内容更新
您可以添加自定义脚本来定期检查是否有新的可寻址内容更新。可使用以下函数调用开始更新:
public static AsyncOperationHandle<List<string>> CheckForCatalogUpdates(bool autoReleaseHandle = true)
其中List
如果有新内容,则可以向用户显示一个按钮来执行更新,也可以自动执行。请注意,这取决于开发人员确保释放了过时的资产。
目录列表可以为空,如果是,则以下脚本更新所有需要更新的目录:
public static AsyncOperationHandle<List<IResourceLocator>> UpdateCatalogs(IEnumerable<string> catalogs = null, bool autoReleaseHandle = true)
返回值是更新的定位器(locator)列表。
内容更新示例
在此示例中,已交付的App知道以下组:
Local_Static | Remote_Static | Remote_NonStatic |
---|---|---|
AssetA | AssetL | AssetX |
AssetB | AssetM | AssetY |
AssetC | AssetN | AssetZ |
请注意,Local_Static和Remote_Static是Cannot Change Post Release组的一部分。
由于该版本已上线,因此有些玩家在其设备上已经有Local_Static,并且可能在本地缓存了一个或两个远程bundles。
如果您从每个组(AssetA,AssetL和AssetX)修改一个资产,然后运行Check for Content Update Restrictions,则本地可寻址设置中的结果现在为:
Local_Static | Remote_Static | Remote_NonStatic | content_update_group (non-static) |
---|---|---|---|
AssetX | AssetA | ||
AssetB | AssetM | AssetY | AssetL |
AssetC | AssetN | AssetZ |
请注意,prepare操作实际上是在编辑Cannot Change Post Release组,这似乎违反直觉。但是,关键是系统构建了以上布局,但是放弃了任何此类组的构建结果。因此,从玩家的角度来看,您得到以下结果:
|Local_Static|
|-------|
|AssetA|
|AssetB|
|AssetC|
该Local_Static bundles已经在玩家设备上,您无法更改。旧版本的AssetA不再引用。相反,它作为无效数据停留在玩家设备上。
|Remote_Static|
|-------|
|AssetL|
|AssetM|
|AssetN|
该Remote_Static bundle是不变的。如果尚未将其缓存在玩家设备上,它将在使用AssetM或AssetN时下载。像一样AssetA,旧版本的AssetL不再引用。
Remote_NonStatic (旧) |
---|
AssetX |
AssetY |
AssetZ |
该Remote_NonStatic bundle是现在老了。您可以从服务器中删除它,但是从现在开始无论哪种方式都不会下载它。如果被缓存,它将最终离开缓存。与AssetA和一样AssetL,旧版本的AssetX不再引用。
Remote_NonStatic (新) |
---|
AssetX |
AssetY |
AssetZ |
旧的Remote_NonStatic bundle将替换为新版本,以其哈希文件来区分。修改版本AssetX已与此新bundle一起更新。
content_update_group |
---|
AssetA |
AssetL |
该content_update_group bundle 包含被修改的资源,他们将被引用在之后。
请注意,上面的示例具有以下含义:
- 任何更改的本地资产将永远在用户的设备上保持未使用状态。
- 如果用户已经缓存了非静态bundle,则他们将需要重新下载bundle,包括未更改的资产(例如,AssetY和AssetZ)。理想情况下,用户没有缓存bundle,在这种情况下,他们只需要下载新Remote_NonStatic bundle即可。
- 如果用户已经缓存了Static_Remote bundle,则只需下载更新的资产(例如,AssetL通过content_update_group)。这是在理想情况下。如果用户尚未缓存这个bundle,则他们必须下载通过content_update_group的新AssetL和现已失效AssetL的Remote_Static bundle两个。不管初始缓存状态如何,在任何时候用户都将在设备上保存已失效的AssetL文件,尽管从未访问过,但仍会无限期地进行缓存。
最佳的远程内容设置将取决于您具体的使用情况。