From d7b49efac2e1ba2e1faa673e104c2eec84acf529 Mon Sep 17 00:00:00 2001 From: Unity Technologies <@unity> Date: Thu, 8 Feb 2024 00:00:00 +0000 Subject: [PATCH] com.unity.addressables@1.21.20 ## [1.21.20] - 2024-02-08 - Fixed an issue where scene InternalId collisions were very likely when using dynamic internal asset naming - Fixed catalogs to use back slashes rather than forward slashes for android builds. - Fixed an issue where "Failed to remove scene from Addressables profiler" warning occurs when a scene is unloaded. - Prevent a KeyNotFoundException from being logged to the console. - Fix error message to report not found when loading non-Addressable asset by guid - Fixed issue where a NullReferenceException occurs when using WaitForCompletion and the max number of concurrent requests is set to 1. - Fixed issue where there is missing asset data in the Addressables Profiler for binary catalogs. - Added note about the limitations of the Check for Content Update Restrictions tool. - Add migration upgrade prompt for legacy path pairs (ex. RemoteLoadPath) - Fixed an issue where a broken script on any Addressable Asset would make it impossible to select Addressable Assets in the AssetReference inspector - Add logging of catalog and asset bundle http operations. - Add UI to trigger CCD management API http call logging (requires newer CCD package) - CCD Automatic Profiles can now be one per-profile, rather than one per AddressableSettings instance - CCD Manager is built when using the Build to CCD and the standard Build content menu - Add support for CCD Management SDK 3.0 --- CHANGELOG.md | 2583 +++--- CHANGELOG.md.meta | 14 +- Documentation~/AddressableAssetSettings.md | 262 +- .../AddressableAssetsAsyncOperationHandle.md | 250 +- .../AddressableAssetsDevelopmentCycle.md | 42 +- .../AddressableAssetsGettingStarted.md | 30 +- Documentation~/AddressableAssetsOverview.md | 260 +- Documentation~/AddressableAssetsProfiles.md | 30 +- .../AddressablesAndSpriteAtlases.md | 78 +- Documentation~/AddressablesCCD.md | 262 +- .../AddressablesReportExploreTab.md | 38 +- .../AddressablesReportPotentialIssuesTab.md | 30 +- .../AddressablesReportSummaryTab.md | 30 +- Documentation~/AnalyzeTool.md | 342 +- Documentation~/AssetDependencies.md | 102 +- Documentation~/AssetReferences.md | 26 +- Documentation~/BuildArtifacts.md | 16 +- Documentation~/BuildLayoutReport.md | 212 +- Documentation~/BuildPlayerContent.md | 36 +- Documentation~/BuildProfileLog.md | 42 +- Documentation~/BuildingContent.md | 22 +- Documentation~/BuildingShaders.md | 22 +- Documentation~/Builds.md | 38 +- .../ContentPackingAndLoadingSchema.md | 214 +- Documentation~/ContentUpdateWorkflow.md | 28 +- Documentation~/ContinuousIntegration.md | 68 +- Documentation~/DiagnosticTools.md | 28 +- Documentation~/DownloadDependenciesAsync.md | 90 +- Documentation~/GetRuntimeAddress.md | 34 +- Documentation~/GroupSchemas.md | 94 +- Documentation~/GroupTemplates.md | 40 +- Documentation~/Groups.md | 34 +- Documentation~/GroupsWindow.md | 188 +- Documentation~/InitializeAsync.md | 112 +- Documentation~/Labels.md | 60 +- Documentation~/LoadContentCatalogAsync.md | 94 +- Documentation~/LoadingAddressableAssets.md | 40 +- Documentation~/LoadingAssetBundles.md | 134 +- Documentation~/LoadingAssetReferences.md | 22 +- Documentation~/LoadingScenes.md | 82 +- Documentation~/MemoryManagement.md | 80 +- Documentation~/ModificationEvents.md | 138 +- Documentation~/MultiProject.md | 70 +- Documentation~/PackingGroupsAsBundles.md | 52 +- Documentation~/ProfileVariables.md | 148 +- Documentation~/ProfilerModule.md | 194 +- Documentation~/RemoteContentDistribution.md | 32 +- Documentation~/RuntimeAddressables.md | 32 +- Documentation~/SamplesOverview.md | 38 +- Documentation~/SynchronousAddressables.md | 150 +- Documentation~/TableOfContents.md | 198 +- Documentation~/TransformInternalId.md | 78 +- Documentation~/UnloadingAddressableAssets.md | 32 +- Documentation~/UpdateRestrictionSchema.md | 28 +- Documentation~/addressables-preferences.md | 22 +- .../addressables-profiles-window.md | 50 +- .../addressables-report-inspector.md | 72 +- Documentation~/addressables-report-window.md | 146 +- Documentation~/addressables-report.md | 54 +- Documentation~/api_index.md | 94 +- Documentation~/asset-organization-strategy.md | 22 +- Documentation~/asset-reference-create.md | 86 +- Documentation~/asset-reference-intro.md | 72 +- Documentation~/asset-strategy-overview.md | 30 +- Documentation~/build-artifacts-included.md | 78 +- Documentation~/build-content-catalogs.md | 54 +- Documentation~/build-intro.md | 78 +- Documentation~/build-player-builds.md | 40 +- Documentation~/build-scripting-custom.md | 60 +- Documentation~/build-scripting-recompiling.md | 114 +- Documentation~/build-scripting-start-build.md | 156 +- Documentation~/build-shared-assetbundles.md | 34 +- Documentation~/builds-full-build.md | 142 +- Documentation~/builds-update-build.md | 76 +- Documentation~/config.json | 2 +- Documentation~/content-update-build-create.md | 95 +- .../content-update-build-settings.md | 136 +- Documentation~/content-update-builds-check.md | 56 +- .../content-update-builds-overview.md | 114 +- Documentation~/content-update-examples.md | 242 +- Documentation~/convert-asset-bundles.md | 28 +- Documentation~/convert-prefabs.md | 16 +- .../convert-project-to-addressables.md | 50 +- Documentation~/convert-resources-folder.md | 52 +- Documentation~/convert-scene-data.md | 76 +- Documentation~/filter.yml | 58 +- .../get-started-make-addressable.md | 46 +- Documentation~/groups-create.md | 82 +- Documentation~/groups-intro.md | 18 +- .../BuildReportInspectorRefsTo.png.meta | 4 +- .../images/HowToOpenBuildReport.png.meta | 4 +- Documentation~/index.md | 50 +- Documentation~/installation-guide.md | 34 +- Documentation~/load-addressable-assets.md | 90 +- Documentation~/load-assets-asynchronous.md | 26 +- Documentation~/load-assets-location.md | 34 +- Documentation~/load-assets.md | 58 +- Documentation~/manage-addressables-intro.md | 88 +- Documentation~/memory-assetbundles.md | 126 +- Documentation~/organize-addressable-assets.md | 148 +- Documentation~/profiles-build-load-paths.md | 18 +- Documentation~/profiles-create.md | 42 +- Documentation~/profiles-introduction.md | 68 +- Documentation~/projectMetadata.json | 6 +- .../remote-content-assetbundle-cache.md | 36 +- Documentation~/remote-content-enable.md | 50 +- Documentation~/remote-content-intro.md | 70 +- Documentation~/remote-content-predownload.md | 44 +- Documentation~/remote-content-profiles.md | 62 +- Documentation~/safely-edit-loaded-asset.md | 52 +- .../use-addresssables-introduction.md | 90 +- Editor.meta | 20 +- .../AddressableAssetSettingsDefaultObject.cs | 362 +- ...ressableAssetSettingsDefaultObject.cs.meta | 22 +- Editor/AddressableEditorInitialization.cs | 136 +- .../AddressableEditorInitialization.cs.meta | 22 +- Editor/AssemblyInfo.cs | 20 +- Editor/AssemblyInfo.cs.meta | 22 +- Editor/Build.meta | 20 +- Editor/Build/AddressableAnalytics.cs | 1008 +-- Editor/Build/AddressableAnalytics.cs.meta | 22 +- .../Build/AddressableAssetSettingsLocator.cs | 828 +- .../AddressableAssetSettingsLocator.cs.meta | 22 +- Editor/Build/AddressablesBuildScriptHooks.cs | 148 +- .../AddressablesBuildScriptHooks.cs.meta | 22 +- Editor/Build/AddressablesDataBuilderInput.cs | 242 +- .../AddressablesDataBuilderInput.cs.meta | 22 +- Editor/Build/AddressablesDataBuilders.cs | 286 +- Editor/Build/AddressablesDataBuilders.cs.meta | 22 +- .../Build/AddressablesPlayerBuildProcessor.cs | 442 +- .../AddressablesPlayerBuildProcessor.cs.meta | 22 +- Editor/Build/AnalyzeRules.meta | 16 +- .../Build/AnalyzeRules/AnalyzeResultData.cs | 178 +- .../AnalyzeRules/AnalyzeResultData.cs.meta | 22 +- Editor/Build/AnalyzeRules/AnalyzeRule.cs | 252 +- Editor/Build/AnalyzeRules/AnalyzeRule.cs.meta | 22 +- Editor/Build/AnalyzeRules/AnalyzeSystem.cs | 458 +- .../Build/AnalyzeRules/AnalyzeSystem.cs.meta | 22 +- .../Build/AnalyzeRules/BuildBundleLayout.cs | 278 +- .../AnalyzeRules/BuildBundleLayout.cs.meta | 22 +- Editor/Build/AnalyzeRules/BundleRuleBase.cs | 1354 +-- .../Build/AnalyzeRules/BundleRuleBase.cs.meta | 22 +- .../CheckBundleDupeDependencies.cs | 620 +- .../CheckBundleDupeDependencies.cs.meta | 22 +- .../CheckResourcesDupeDependencies.cs | 124 +- .../CheckResourcesDupeDependencies.cs.meta | 22 +- .../CheckSceneDupeDependencies.cs | 136 +- .../CheckSceneDupeDependencies.cs.meta | 22 +- Editor/Build/BuildPipelineTasks.meta | 16 +- .../AddHashToBundleNameTask.cs | 214 +- .../AddHashToBundleNameTask.cs.meta | 22 +- .../BuildLayoutGenerationTask.cs | 2494 +++--- .../BuildLayoutGenerationTask.cs.meta | 22 +- .../BuildPipelineTasks/ExtractDataTask.cs | 152 +- .../ExtractDataTask.cs.meta | 22 +- .../GenerateLocationListsTask.cs | 768 +- .../GenerateLocationListsTask.cs.meta | 22 +- Editor/Build/BuildUtility.cs | 218 +- Editor/Build/BuildUtility.cs.meta | 22 +- Editor/Build/CcdBuildEvents.cs | 1926 +++-- Editor/Build/CcdBuildEvents.cs.meta | 22 +- Editor/Build/ContentUpdateScript.cs | 2186 ++--- Editor/Build/ContentUpdateScript.cs.meta | 22 +- Editor/Build/DataBuilderInterfaces.cs | 134 +- Editor/Build/DataBuilderInterfaces.cs.meta | 22 +- Editor/Build/DataBuilders.meta | 16 +- .../AddressableAssetsBuildContext.cs | 334 +- .../AddressableAssetsBuildContext.cs.meta | 22 +- .../AddressableAssetsBundleBuildParameters.cs | 194 +- ...essableAssetsBundleBuildParameters.cs.meta | 22 +- Editor/Build/DataBuilders/BuildScriptBase.cs | 626 +- .../DataBuilders/BuildScriptBase.cs.meta | 22 +- .../Build/DataBuilders/BuildScriptFastMode.cs | 130 +- .../DataBuilders/BuildScriptFastMode.cs.meta | 22 +- .../DataBuilders/BuildScriptPackedMode.cs | 3310 ++++---- .../BuildScriptPackedMode.cs.meta | 22 +- .../DataBuilders/BuildScriptPackedPlayMode.cs | 188 +- .../BuildScriptPackedPlayMode.cs.meta | 22 +- .../DataBuilders/BuildScriptVirtualMode.cs | 874 +- .../BuildScriptVirtualMode.cs.meta | 22 +- Editor/Build/DirectoryUtility.cs | 176 +- Editor/Build/DirectoryUtility.cs.meta | 22 +- .../Build/FastModeInitializationOperation.cs | 260 +- .../FastModeInitializationOperation.cs.meta | 22 +- Editor/Build/FileRegistry.cs | 160 +- Editor/Build/FileRegistry.cs.meta | 22 +- Editor/Build/Layout.meta | 16 +- Editor/Build/Layout/BuildLayout.cs | 2760 +++---- Editor/Build/Layout/BuildLayout.cs.meta | 22 +- Editor/Build/Layout/BuildLayoutEnums.cs | 548 +- Editor/Build/Layout/BuildLayoutEnums.cs.meta | 22 +- Editor/Build/Layout/BuildLayoutHelpers.cs | 306 +- .../Build/Layout/BuildLayoutHelpers.cs.meta | 22 +- Editor/Build/Layout/BuildLayoutPrinter.cs | 566 +- .../Build/Layout/BuildLayoutPrinter.cs.meta | 22 +- Editor/Build/Layout/BuildLayoutSummary.cs | 420 +- .../Build/Layout/BuildLayoutSummary.cs.meta | 22 +- Editor/Build/LinkXMLGenerator.cs | 76 +- Editor/Build/LinkXMLGenerator.cs.meta | 22 +- Editor/Build/MonoScriptBundleNaming.cs | 56 +- Editor/Build/MonoScriptBundleNaming.cs.meta | 22 +- ...vertUnchangedAssetsToPreviousAssetState.cs | 496 +- ...nchangedAssetsToPreviousAssetState.cs.meta | 22 +- Editor/Build/SceneManagerState.cs | 358 +- Editor/Build/SceneManagerState.cs.meta | 22 +- Editor/Build/ShaderBundleNaming.cs | 54 +- Editor/Build/ShaderBundleNaming.cs.meta | 22 +- Editor/BuildReportVisualizer.meta | 16 +- .../BuildReport Resources.meta | 16 +- .../BuildReport Resources/Icons.meta | 16 +- .../Icons/FileNoIcon.png.meta | 316 +- .../Icons/FileNoIcon@2x.png.meta | 316 +- .../Icons/FileNoIcon@3x.png.meta | 316 +- .../Icons/PlatformAndroidIcon.png.meta | 268 +- .../Icons/PlatformAndroidIcon@2x.png.meta | 268 +- .../Icons/PlatformLuminIcon.png.meta | 268 +- .../Icons/PlatformLuminIcon@2x.png.meta | 268 +- .../Icons/PlatformPS4Icon.png.meta | 268 +- .../Icons/PlatformPS4Icon@2x.png.meta | 268 +- .../Icons/PlatformStadiaIcon.png.meta | 316 +- .../Icons/PlatformStadiaIcon@2x.png.meta | 316 +- .../Icons/PlatformStandaloneOSXIcon.png.meta | 268 +- .../Icons/PlatformSwitchIcon.png.meta | 268 +- .../Icons/PlatformSwitchIcon@2x.png.meta | 268 +- .../Icons/PlatformWSAPlayerIcon.png.meta | 268 +- .../Icons/PlatformWSAPlayerIcon@2x.png.meta | 268 +- .../Icons/PlatformWebGLIcon.png.meta | 268 +- .../Icons/PlatformWebGLIcon@2x.png.meta | 268 +- .../Icons/PlatformXboxOneIcon.png.meta | 268 +- .../Icons/PlatformXboxOneIcon@2x.png.meta | 268 +- .../Icons/PlatformiOSIcon.png.meta | 268 +- .../Icons/PlatformiOSIcon@2x.png.meta | 268 +- .../Icons/PlatformtvOSIcon.png.meta | 268 +- .../Icons/PlatformtvOSIcon@2x.png.meta | 268 +- .../Icons/d_History.Forward.png.meta | 268 +- .../Icons/d_History.Forward@2x.png.meta | 268 +- .../Icons/d_icon dropdown@2x.png.meta | 198 +- .../BuildReportListView.cs | 544 +- .../BuildReportListView.cs.meta | 22 +- .../BuildReportWindow.cs | 774 +- .../BuildReportWindow.cs.meta | 34 +- Editor/BuildReportVisualizer/ContentView.meta | 16 +- .../ContentView/AssetsContentView.cs | 772 +- .../ContentView/AssetsContentView.cs.meta | 22 +- .../ContentView/BundlesContentView.cs | 962 +-- .../ContentView/BundlesContentView.cs.meta | 22 +- .../ContentView/ContentView.cs | 622 +- .../ContentView/ContentView.cs.meta | 22 +- .../ContentView/DetailsView.cs | 190 +- .../ContentView/DetailsView.cs.meta | 22 +- .../DuplicatedAssetsContentView.cs | 608 +- .../DuplicatedAssetsContentView.cs.meta | 22 +- .../ContentView/GroupsContentView.cs | 958 +-- .../ContentView/GroupsContentView.cs.meta | 22 +- .../ContentView/LabelsContentView.cs | 796 +- .../ContentView/LabelsContentView.cs.meta | 22 +- .../BuildReportVisualizer/DetailsPanel.meta | 16 +- .../DetailsPanel/DetailsContentView.cs | 1118 +-- .../DetailsPanel/DetailsContentView.cs.meta | 22 +- .../DetailsPanel/DetailsContents.cs | 58 +- .../DetailsPanel/DetailsContents.cs.meta | 22 +- .../DetailsPanel/DetailsSummaryView.cs | 384 +- .../DetailsPanel/DetailsSummaryView.cs.meta | 22 +- .../DetailsPanel/DetailsUtility.cs | 100 +- .../DetailsPanel/DetailsUtility.cs.meta | 22 +- .../BuildReportVisualizer/IAddressableView.cs | 28 +- .../IAddressableView.cs.meta | 22 +- .../IBuildReportConsumer.cs | 30 +- .../IBuildReportConsumer.cs.meta | 22 +- .../MainPanelSummaryTab.cs | 310 +- .../MainPanelSummaryTab.cs.meta | 22 +- Editor/BuildReportVisualizer/MainToolbar.cs | 190 +- .../BuildReportVisualizer/MainToolbar.cs.meta | 22 +- .../ToggleTextExpansionButton.cs | 62 +- .../ToggleTextExpansionButton.cs.meta | 22 +- .../UIToolKitAssets.meta | 16 +- .../UIToolKitAssets/StyleSheets.meta | 16 +- .../StyleSheets/DetailsPanelSummary.uss | 104 +- .../StyleSheets/DetailsPanelSummary.uss.meta | 22 +- .../StyleSheets/DetailsViewDark.uss | 6 +- .../StyleSheets/DetailsViewDark.uss.meta | 4 +- .../StyleSheets/DetailsViewLight.uss | 6 +- .../StyleSheets/DetailsViewLight.uss.meta | 4 +- .../StyleSheets/DrillableListItemStyle.uss | 114 +- .../DrillableListItemStyle.uss.meta | 22 +- .../StyleSheets/MainToolbarButtons.uss | 52 +- .../StyleSheets/MainToolbarButtons.uss.meta | 22 +- .../StyleSheets/MainToolbarButtonsDark.uss | 26 +- .../MainToolbarButtonsDark.uss.meta | 22 +- .../StyleSheets/MainToolbarButtonsLight.uss | 22 +- .../MainToolbarButtonsLight.uss.meta | 22 +- .../StyleSheets/ReportListItem.uss | 170 +- .../StyleSheets/ReportListItem.uss.meta | 22 +- .../StyleSheets/SummaryTab.uss | 122 +- .../StyleSheets/SummaryTab.uss.meta | 22 +- .../StyleSheets/SummaryTabCardDark.uss | 6 +- .../StyleSheets/SummaryTabCardDark.uss.meta | 22 +- .../StyleSheets/SummaryTabCardLight.uss | 6 +- .../StyleSheets/SummaryTabCardLight.uss.meta | 22 +- .../StyleSheets/SummaryTabDark.uss | 6 +- .../StyleSheets/SummaryTabDark.uss.meta | 22 +- .../StyleSheets/SummaryTabLight.uss | 6 +- .../StyleSheets/SummaryTabLight.uss.meta | 22 +- .../StyleSheets/TreeViewItem.uss | 112 +- .../StyleSheets/TreeViewItem.uss.meta | 22 +- .../StyleSheets/TreeViewNavigableItem.uss | 42 +- .../TreeViewNavigableItem.uss.meta | 22 +- .../UIToolKitAssets/UXML.meta | 16 +- .../UXML/BuildReportWindow.uxml | 48 +- .../UXML/BuildReportWindow.uxml.meta | 20 +- .../UIToolKitAssets/UXML/ContentTab.uxml | 26 +- .../UIToolKitAssets/UXML/ContentTab.uxml.meta | 20 +- .../UIToolKitAssets/UXML/DetailsPanel.uxml | 44 +- .../UXML/DetailsPanel.uxml.meta | 20 +- .../UXML/DetailsPanelSummaryAsset.uxml | 8 +- .../UXML/DetailsPanelSummaryAsset.uxml.meta | 20 +- .../UXML/DetailsPanelSummaryBundle.uxml | 8 +- .../UXML/DetailsPanelSummaryBundle.uxml.meta | 20 +- .../DetailsPanelSummaryNavigableBundle.uxml | 26 +- .../DetailsPanelSummaryNavigableItem.uxml | 18 +- .../UXML/DrillableListViewItem.uxml | 16 +- .../UXML/DrillableListViewItem.uxml.meta | 20 +- .../UIToolKitAssets/UXML/MainPanel.uxml | 26 +- .../UIToolKitAssets/UXML/MainPanel.uxml.meta | 20 +- .../UIToolKitAssets/UXML/MainToolbar.uxml | 34 +- .../UXML/MainToolbar.uxml.meta | 20 +- .../UIToolKitAssets/UXML/PotentialIssues.uxml | 28 +- .../UXML/PotentialIssues.uxml.meta | 20 +- .../UIToolKitAssets/UXML/ReportsListItem.uxml | 26 +- .../UXML/ReportsListItem.uxml.meta | 20 +- .../UXML/ReportsListPanel.uxml | 6 +- .../UXML/ReportsListPanel.uxml.meta | 20 +- .../UIToolKitAssets/UXML/SummaryTab.uxml | 6 +- .../UIToolKitAssets/UXML/SummaryTab.uxml.meta | 20 +- .../UIToolKitAssets/UXML/TreeViewItem.uxml | 14 +- .../UXML/TreeViewItem.uxml.meta | 20 +- .../UXML/TreeViewNavigableItem.uxml | 16 +- .../UXML/TreeViewNavigableItem.uxml.meta | 20 +- Editor/BuildReportVisualizer/Utility.meta | 16 +- .../Utility/BuildReportHelperConsumer.cs | 428 +- .../Utility/BuildReportHelperConsumer.cs.meta | 22 +- .../Utility/BuildReportUtility.cs | 958 +-- .../Utility/BuildReportUtility.cs.meta | 22 +- .../Utility/DetailsListItem.cs | 82 +- .../Utility/DetailsListItem.cs.meta | 22 +- .../Utility/DetailsStack.cs | 76 +- .../Utility/DetailsStack.cs.meta | 22 +- .../Utility/DetailsSummaryBuilder.cs | 276 +- .../Utility/DetailsSummaryBuilder.cs.meta | 22 +- .../Utility/SummaryRowBuilder.cs | 302 +- .../Utility/SummaryRowBuilder.cs.meta | 22 +- .../Utility/TreeBuilder.cs | 152 +- .../Utility/TreeBuilder.cs.meta | 22 +- Editor/Diagnostics.meta | 16 +- Editor/Diagnostics/AddressableIconNames.cs | 36 +- .../Diagnostics/AddressableIconNames.cs.meta | 22 +- Editor/Diagnostics/Data.meta | 16 +- .../Data/EventDataPlayerSession.cs | 586 +- .../Data/EventDataPlayerSession.cs.meta | 22 +- .../Data/EventDataPlayerSessionCollection.cs | 180 +- .../EventDataPlayerSessionCollection.cs.meta | 22 +- Editor/Diagnostics/Data/EventDataSample.cs | 54 +- .../Diagnostics/Data/EventDataSample.cs.meta | 22 +- Editor/Diagnostics/Data/EventDataSet.cs | 364 +- Editor/Diagnostics/Data/EventDataSet.cs.meta | 22 +- Editor/Diagnostics/Data/EventDataStream.cs | 98 +- .../Diagnostics/Data/EventDataStream.cs.meta | 22 +- Editor/Diagnostics/GUI.meta | 16 +- Editor/Diagnostics/GUI/EventGraphListView.cs | 574 +- .../GUI/EventGraphListView.cs.meta | 22 +- Editor/Diagnostics/GUI/EventListView.cs | 238 +- Editor/Diagnostics/GUI/EventListView.cs.meta | 22 +- Editor/Diagnostics/GUI/EventViewerWindow.cs | 1232 +-- .../Diagnostics/GUI/EventViewerWindow.cs.meta | 22 +- Editor/Diagnostics/GUI/Graph.meta | 16 +- .../Diagnostics/GUI/Graph/GraphDefinition.cs | 48 +- .../GUI/Graph/GraphDefinition.cs.meta | 22 +- .../GUI/Graph/GraphLayerBackground.cs | 118 +- .../GUI/Graph/GraphLayerBackground.cs.meta | 22 +- .../GUI/Graph/GraphLayerBarChart.cs | 178 +- .../GUI/Graph/GraphLayerBarChart.cs.meta | 22 +- .../Diagnostics/GUI/Graph/GraphLayerBase.cs | 82 +- .../GUI/Graph/GraphLayerBase.cs.meta | 22 +- .../GUI/Graph/GraphLayerEventMarker.cs | 226 +- .../GUI/Graph/GraphLayerEventMarker.cs.meta | 22 +- .../Diagnostics/GUI/Graph/GraphLayerLabel.cs | 116 +- .../GUI/Graph/GraphLayerLabel.cs.meta | 22 +- Editor/Diagnostics/GUI/Graph/GraphUtility.cs | 140 +- .../GUI/Graph/GraphUtility.cs.meta | 22 +- Editor/Diagnostics/GUI/Graph/IGraphLayer.cs | 28 +- .../Diagnostics/GUI/Graph/IGraphLayer.cs.meta | 22 +- Editor/Diagnostics/GUI/GraphColors.cs | 48 +- Editor/Diagnostics/GUI/GraphColors.cs.meta | 22 +- Editor/Diagnostics/Profiler.meta | 16 +- ...ddressablesProfilerDetailsDataInspector.cs | 840 +- ...sablesProfilerDetailsDataInspector.cs.meta | 4 +- .../AddressablesProfilerDetailsTreeView.cs | 402 +- ...ddressablesProfilerDetailsTreeView.cs.meta | 4 +- .../AddressablesProfilerDetailsView.cs | 1358 +-- .../AddressablesProfilerDetailsView.cs.meta | 22 +- .../Profiler/AddressablesProfilerModule.cs | 76 +- .../AddressablesProfilerModule.cs.meta | 22 +- .../AddressablesProfilerUnsupported.cs | 96 +- .../AddressablesProfilerUnsupported.cs.meta | 22 +- .../AddressablesProfilerViewController.cs | 112 +- ...AddressablesProfilerViewController.cs.meta | 22 +- .../Profiler/BuildLayoutsManager.cs | 390 +- .../Profiler/BuildLayoutsManager.cs.meta | 4 +- .../Profiler/ContentDataListView.cs | 210 +- .../Profiler/ContentDataListView.cs.meta | 4 +- .../Profiler/ContentDataTreeView.cs | 380 +- .../Profiler/ContentDataTreeView.cs.meta | 4 +- Editor/Diagnostics/Profiler/ContentSearch.cs | 684 +- .../Profiler/ContentSearch.cs.meta | 4 +- Editor/Diagnostics/Profiler/GUIElements.meta | 16 +- .../Profiler/GUIElements/AssetLabel.cs | 274 +- .../Profiler/GUIElements/AssetLabel.cs.meta | 22 +- .../Profiler/HelpDisplayManager.cs | 290 +- .../Profiler/HelpDisplayManager.cs.meta | 4 +- .../ProfilerDetailsTreeViewItemData.cs | 758 +- .../ProfilerDetailsTreeViewItemData.cs.meta | 22 +- .../Profiler/ProfilerGUIUtilities.cs | 598 +- .../Profiler/ProfilerGUIUtilities.cs.meta | 4 +- .../Diagnostics/Profiler/ProfilerStrings.cs | 54 +- .../Profiler/ProfilerStrings.cs.meta | 4 +- .../Diagnostics/Profiler/ProfilerTemplates.cs | 92 +- .../Profiler/ProfilerTemplates.cs.meta | 22 +- Editor/Diagnostics/Profiler/UXML.meta | 16 +- .../Diagnostics/Profiler/UXML/HelpDisplay.cs | 78 +- .../Profiler/UXML/HelpDisplay.cs.meta | 22 +- .../Profiler/UXML/HelpDisplay.uxml | 30 +- .../Profiler/UXML/HelpDisplay.uxml.meta | 20 +- .../Profiler/UXML/InspectorPane.cs | 74 +- .../Profiler/UXML/InspectorPane.cs.meta | 22 +- .../Profiler/UXML/InspectorPane.uxml | 120 +- .../Profiler/UXML/InspectorPane.uxml.meta | 20 +- .../Profiler/UXML/MissingReport.cs | 70 +- .../Profiler/UXML/MissingReport.cs.meta | 22 +- .../Profiler/UXML/MissingReport.uxml | 28 +- .../Profiler/UXML/MissingReport.uxml.meta | 20 +- .../Profiler/UXML/TreeColumnNames.cs | 36 +- .../Profiler/UXML/TreeColumnNames.cs.meta | 4 +- .../Diagnostics/Profiler/UXML/TreeViewPane.cs | 48 +- .../Profiler/UXML/TreeViewPane.cs.meta | 22 +- .../Profiler/UXML/TreeViewPane.uxml | 60 +- .../Profiler/UXML/TreeViewPane.uxml.meta | 20 +- .../Profiler/UXML/Unsupported.uxml | 20 +- .../Profiler/UXML/Unsupported.uxml.meta | 20 +- .../Diagnostics/Profiler/UXML/stylesheet.uss | 136 +- .../Profiler/UXML/stylesheet.uss.meta | 22 +- .../Diagnostics/ResourceManagerCacheWindow.cs | 304 +- .../ResourceManagerCacheWindow.cs.meta | 22 +- Editor/Diagnostics/ResourceProfilerWindow.cs | 260 +- .../ResourceProfilerWindow.cs.meta | 22 +- Editor/GUI.meta | 20 +- .../AddressableAssetEntryCollectionEditor.cs | 146 +- ...ressableAssetEntryCollectionEditor.cs.meta | 22 +- Editor/GUI/AddressableAssetGroupInspector.cs | 634 +- .../AddressableAssetGroupInspector.cs.meta | 22 +- .../AddressableAssetGroupTemplateInspector.cs | 934 +-- ...essableAssetGroupTemplateInspector.cs.meta | 22 +- .../GUI/AddressableAssetSettingsInspector.cs | 1779 ++-- .../AddressableAssetSettingsInspector.cs.meta | 22 +- .../AddressableAssetsSettingsGroupEditor.cs | 1788 ++-- ...dressableAssetsSettingsGroupEditor.cs.meta | 22 +- ...sableAssetsSettingsGroupEditorBuildMenu.cs | 458 +- ...AssetsSettingsGroupEditorBuildMenu.cs.meta | 22 +- .../AddressableAssetsSettingsGroupTreeView.cs | 3462 ++++---- ...essableAssetsSettingsGroupTreeView.cs.meta | 22 +- ...AddressableAssetsSettingsLabelMaskPopup.cs | 660 +- ...ssableAssetsSettingsLabelMaskPopup.cs.meta | 22 +- Editor/GUI/AddressableAssetsWindow.cs | 360 +- Editor/GUI/AddressableAssetsWindow.cs.meta | 22 +- Editor/GUI/AddressableReadOnlyAttribute.cs | 44 +- .../GUI/AddressableReadOnlyAttribute.cs.meta | 22 +- Editor/GUI/AddressablesGUIUtility.cs | 422 +- Editor/GUI/AddressablesGUIUtility.cs.meta | 22 +- Editor/GUI/AnalyzeRuleGUI.cs | 248 +- Editor/GUI/AnalyzeRuleGUI.cs.meta | 22 +- Editor/GUI/AnalyzeWindow.cs | 162 +- Editor/GUI/AnalyzeWindow.cs.meta | 22 +- Editor/GUI/AssetInspectorGUI.cs | 1226 +-- Editor/GUI/AssetInspectorGUI.cs.meta | 22 +- Editor/GUI/AssetInspectorGUIGroupsPopup.cs | 454 +- .../GUI/AssetInspectorGUIGroupsPopup.cs.meta | 22 +- Editor/GUI/AssetLabelReferenceDrawer.cs | 70 +- Editor/GUI/AssetLabelReferenceDrawer.cs.meta | 22 +- Editor/GUI/AssetPublishEditor.cs | 188 +- Editor/GUI/AssetPublishEditor.cs.meta | 22 +- Editor/GUI/AssetReferenceDrawer.cs | 2414 +++--- Editor/GUI/AssetReferenceDrawer.cs.meta | 22 +- Editor/GUI/AssetSettingsAnalyzeTreeView.cs | 1066 +-- .../GUI/AssetSettingsAnalyzeTreeView.cs.meta | 22 +- Editor/GUI/BuildProfileSettingsEditor.cs | 300 +- Editor/GUI/BuildProfileSettingsEditor.cs.meta | 22 +- Editor/GUI/CacheInitializationDataDrawer.cs | 238 +- .../GUI/CacheInitializationDataDrawer.cs.meta | 22 +- Editor/GUI/ContentUpdatePreviewWindow.cs | 686 +- Editor/GUI/ContentUpdatePreviewWindow.cs.meta | 22 +- Editor/GUI/GUIElements.meta | 16 +- Editor/GUI/GUIElements/DocumentationButton.cs | 212 +- .../GUIElements/DocumentationButton.cs.meta | 22 +- Editor/GUI/GUIElements/GUIUtility.cs | 108 +- Editor/GUI/GUIElements/GUIUtility.cs.meta | 4 +- Editor/GUI/GUIElements/LabeledLabel.cs | 164 +- Editor/GUI/GUIElements/LabeledLabel.cs.meta | 22 +- Editor/GUI/GUIElements/Ribbon.cs | 498 +- Editor/GUI/GUIElements/Ribbon.cs.meta | 22 +- Editor/GUI/GUIElements/RibbonButton.cs | 200 +- Editor/GUI/GUIElements/RibbonButton.cs.meta | 22 +- Editor/GUI/GUIElements/SearchStringFilters.cs | 486 +- .../GUIElements/SearchStringFilters.cs.meta | 22 +- Editor/GUI/GUIElements/StyleSheets.meta | 4 +- Editor/GUI/GUIElements/StyleSheets/Ribbon.uss | 128 +- .../GUIElements/StyleSheets/Ribbon.uss.meta | 22 +- .../GUIElements/StyleSheets/Ribbon_dark.uss | 144 +- .../StyleSheets/Ribbon_dark.uss.meta | 22 +- .../GUIElements/StyleSheets/Ribbon_light.uss | 106 +- .../StyleSheets/Ribbon_light.uss.meta | 22 +- Editor/GUI/GUIElements/UXML.meta | 4 +- Editor/GUI/GUIElements/UXML/Ribbon.uxml | 18 +- Editor/GUI/GUIElements/UXML/Ribbon.uxml.meta | 20 +- .../GUI/GUIElements/VisualElementsWrapper.cs | 58 +- .../GUIElements/VisualElementsWrapper.cs.meta | 22 +- Editor/GUI/HostingServicesAddServiceWindow.cs | 190 +- .../HostingServicesAddServiceWindow.cs.meta | 22 +- Editor/GUI/HostingServicesListTreeView.cs | 444 +- .../GUI/HostingServicesListTreeView.cs.meta | 22 +- .../GUI/HostingServicesProfileVarsTreeView.cs | 298 +- ...HostingServicesProfileVarsTreeView.cs.meta | 22 +- Editor/GUI/HostingServicesWindow.cs | 1030 +-- Editor/GUI/HostingServicesWindow.cs.meta | 22 +- Editor/GUI/LabelWindow.cs | 448 +- Editor/GUI/LabelWindow.cs.meta | 22 +- Editor/GUI/ProfileDataSourceDropdownWindow.cs | 1420 ++-- .../ProfileDataSourceDropdownWindow.cs.meta | 22 +- Editor/GUI/ProfileTreeView.cs | 586 +- Editor/GUI/ProfileTreeView.cs.meta | 4 +- Editor/GUI/ProfileValueReferenceDrawer.cs | 162 +- .../GUI/ProfileValueReferenceDrawer.cs.meta | 22 +- Editor/GUI/ProfileWindow.cs | 1644 ++-- Editor/GUI/ProfileWindow.cs.meta | 22 +- Editor/GUI/SerializedTypeDrawer.cs | 190 +- Editor/GUI/SerializedTypeDrawer.cs.meta | 22 +- Editor/GUI/UpgradeNotifications.cs | 67 + Editor/GUI/UpgradeNotifications.cs.meta | 3 + Editor/HostingServices.meta | 16 +- Editor/HostingServices/BaseHostingService.cs | 346 +- .../BaseHostingService.cs.meta | 22 +- .../HostingServices/HostingServicesManager.cs | 1192 +-- .../HostingServicesManager.cs.meta | 22 +- Editor/HostingServices/HttpHostingService.cs | 1190 +-- .../HttpHostingService.cs.meta | 22 +- Editor/HostingServices/IHostingService.cs | 164 +- .../HostingServices/IHostingService.cs.meta | 22 +- .../IHostingServiceConfigurationProvider.cs | 32 +- ...ostingServiceConfigurationProvider.cs.meta | 22 +- Editor/Icons.meta | 20 +- .../AddressableAssetsIconY1756Basic.png.meta | 172 +- .../AddressableAssetsIconY1756Scene.png.meta | 172 +- Editor/Icons/white_help@2x.png.meta | 248 +- Editor/Settings.meta | 20 +- .../Settings/AddressableAssetBuildSettings.cs | 236 +- .../AddressableAssetBuildSettings.cs.meta | 22 +- Editor/Settings/AddressableAssetEntry.cs | 2024 ++--- Editor/Settings/AddressableAssetEntry.cs.meta | 22 +- .../AddressableAssetEntryCollection.cs | 136 +- .../AddressableAssetEntryCollection.cs.meta | 22 +- Editor/Settings/AddressableAssetGroup.cs | 1682 ++-- Editor/Settings/AddressableAssetGroup.cs.meta | 22 +- .../Settings/AddressableAssetGroupSchema.cs | 342 +- .../AddressableAssetGroupSchema.cs.meta | 22 +- .../AddressableAssetGroupSchemaSet.cs | 482 +- .../AddressableAssetGroupSchemaSet.cs.meta | 22 +- .../AddressableAssetGroupSchemaTemplate.cs | 144 +- ...ddressableAssetGroupSchemaTemplate.cs.meta | 22 +- .../Settings/AddressableAssetGroupTemplate.cs | 552 +- .../AddressableAssetGroupTemplate.cs.meta | 22 +- .../AddressableAssetGroupTemplateInterface.cs | 36 +- ...essableAssetGroupTemplateInterface.cs.meta | 22 +- .../Settings/AddressableAssetPostProcessor.cs | 44 +- .../AddressableAssetPostProcessor.cs.meta | 22 +- .../AddressableAssetProfileSettings.cs | 1790 ++-- .../AddressableAssetProfileSettings.cs.meta | 22 +- Editor/Settings/AddressableAssetSettings.cs | 6133 +++++++------- .../Settings/AddressableAssetSettings.cs.meta | 22 +- Editor/Settings/AddressableAssetUtility.cs | 1520 ++-- .../Settings/AddressableAssetUtility.cs.meta | 22 +- Editor/Settings/AddressableScenesManager.cs | 186 +- .../Settings/AddressableScenesManager.cs.meta | 22 +- .../Settings/AddressablesFileEnumeration.cs | 496 +- .../AddressablesFileEnumeration.cs.meta | 22 +- .../Settings/AssetReferenceDrawerUtilities.cs | 944 +-- .../AssetReferenceDrawerUtilities.cs.meta | 4 +- Editor/Settings/BuiltinSceneCache.cs | 264 +- Editor/Settings/BuiltinSceneCache.cs.meta | 22 +- .../Settings/CacheInitializationSettings.cs | 90 +- .../CacheInitializationSettings.cs.meta | 22 +- Editor/Settings/CcdFolder.cs | 168 +- Editor/Settings/CcdFolder.cs.meta | 22 +- Editor/Settings/GlobalInitialization.cs | 68 +- Editor/Settings/GlobalInitialization.cs.meta | 22 +- Editor/Settings/GroupSchemas.meta | 16 +- .../GroupSchemas/BundledAssetGroupSchema.cs | 2760 +++---- .../BundledAssetGroupSchema.cs.meta | 22 +- .../GroupSchemas/ContentUpdateGroupSchema.cs | 154 +- .../ContentUpdateGroupSchema.cs.meta | 22 +- .../GroupSchemas/PlayerDataGroupSchema.cs | 220 +- .../PlayerDataGroupSchema.cs.meta | 22 +- Editor/Settings/KeyDataStore.cs | 476 +- Editor/Settings/KeyDataStore.cs.meta | 22 +- Editor/Settings/LabelTable.cs | 284 +- Editor/Settings/LabelTable.cs.meta | 22 +- Editor/Settings/OrgData.cs | 76 +- Editor/Settings/OrgData.cs.meta | 22 +- Editor/Settings/Preferences.cs | 304 +- Editor/Settings/Preferences.cs.meta | 22 +- Editor/Settings/ProfileDataSourceSettings.cs | 1068 +-- .../ProfileDataSourceSettings.cs.meta | 22 +- Editor/Settings/ProfileGroupType.cs | 440 +- Editor/Settings/ProfileGroupType.cs.meta | 22 +- Editor/Settings/ProfileValueReference.cs | 332 +- Editor/Settings/ProfileValueReference.cs.meta | 22 +- Editor/Settings/ProjectConfigData.cs | 816 +- Editor/Settings/ProjectConfigData.cs.meta | 22 +- Editor/Unity.Addressables.Editor.asmdef | 82 +- Editor/Unity.Addressables.Editor.asmdef.meta | 14 +- LICENSE.md | 10 +- LICENSE.md.meta | 14 +- Runtime.meta | 20 +- Runtime/Addressables.cs | 4888 +++++------ Runtime/Addressables.cs.meta | 22 +- Runtime/AddressablesImpl.cs | 3042 +++---- Runtime/AddressablesImpl.cs.meta | 22 +- Runtime/AssemblyInfo.cs | 24 +- Runtime/AssemblyInfo.cs.meta | 22 +- Runtime/AssetLabelReference.cs | 106 +- Runtime/AssetLabelReference.cs.meta | 22 +- Runtime/AssetReference.cs | 1898 ++--- Runtime/AssetReference.cs.meta | 26 +- Runtime/AssetReferenceUIRestriction.cs | 190 +- Runtime/AssetReferenceUIRestriction.cs.meta | 22 +- Runtime/IKeyEvaluator.cs | 46 +- Runtime/IKeyEvaluator.cs.meta | 22 +- Runtime/Initialization.meta | 16 +- .../AddressablesRuntimeProperties.cs | 446 +- .../AddressablesRuntimeProperties.cs.meta | 22 +- Runtime/Initialization/CacheInitialization.cs | 400 +- .../CacheInitialization.cs.meta | 22 +- .../Initialization/CheckCatalogsOperation.cs | 246 +- .../CheckCatalogsOperation.cs.meta | 22 +- .../CleanBundleCacheOperation.cs | 420 +- .../CleanBundleCacheOperation.cs.meta | 22 +- .../InitializationObjectsOperation.cs | 254 +- .../InitializationObjectsOperation.cs.meta | 22 +- .../Initialization/InitializationOperation.cs | 662 +- .../InitializationOperation.cs.meta | 22 +- .../Initialization/PackedPlayModeBuildLogs.cs | 102 +- .../PackedPlayModeBuildLogs.cs.meta | 22 +- .../ResourceManagerRuntimeData.cs | 354 +- .../ResourceManagerRuntimeData.cs.meta | 26 +- .../Initialization/UpdateCatalogsOperation.cs | 256 +- .../UpdateCatalogsOperation.cs.meta | 22 +- Runtime/ResourceLocators.meta | 16 +- Runtime/ResourceLocators/CcdManagedData.cs | 150 +- .../ResourceLocators/CcdManagedData.cs.meta | 22 +- .../ResourceLocators/ContentCatalogData.cs | 2284 ++--- .../ContentCatalogData.cs.meta | 22 +- .../DynamicResourceLocators.cs | 176 +- .../DynamicResourceLocators.cs.meta | 22 +- Runtime/ResourceLocators/IResourceLocator.cs | 76 +- .../ResourceLocators/IResourceLocator.cs.meta | 22 +- .../LegacyResourcesLocator.cs | 102 +- .../LegacyResourcesLocator.cs.meta | 26 +- .../ResourceLocators/ResourceLocationData.cs | 236 +- .../ResourceLocationData.cs.meta | 26 +- .../ResourceLocators/ResourceLocationMap.cs | 364 +- .../ResourceLocationMap.cs.meta | 26 +- Runtime/ResourceManager.meta | 16 +- Runtime/ResourceManager/AssemblyInfo.cs | 24 +- Runtime/ResourceManager/AssemblyInfo.cs.meta | 22 +- Runtime/ResourceManager/AsyncOperations.meta | 20 +- .../AsyncOperations/AsyncOperationBase.cs | 1232 +-- .../AsyncOperationBase.cs.meta | 26 +- .../AsyncOperations/AsyncOperationHandle.cs | 1218 +-- .../AsyncOperationHandle.cs.meta | 22 +- .../AsyncOperations/AsyncOperationStatus.cs | 56 +- .../AsyncOperationStatus.cs.meta | 22 +- .../AsyncOperations/ChainOperation.cs | 516 +- .../AsyncOperations/ChainOperation.cs.meta | 22 +- .../AsyncOperations/DownloadStatus.cs | 66 +- .../AsyncOperations/DownloadStatus.cs.meta | 22 +- .../AsyncOperations/GroupOperation.cs | 462 +- .../AsyncOperations/GroupOperation.cs.meta | 22 +- .../AsyncOperations/ProviderOperation.cs | 608 +- .../AsyncOperations/ProviderOperation.cs.meta | 22 +- .../UnityWebRequestOperation.cs | 44 +- .../UnityWebRequestOperation.cs.meta | 22 +- Runtime/ResourceManager/CcdManager.cs | 64 +- Runtime/ResourceManager/CcdManager.cs.meta | 22 +- Runtime/ResourceManager/Diagnostics.meta | 16 +- .../Diagnostics/DiagnosticEvent.cs | 270 +- .../Diagnostics/DiagnosticEvent.cs.meta | 22 +- .../Diagnostics/DiagnosticEventCollector.cs | 396 +- .../DiagnosticEventCollector.cs.meta | 26 +- .../Diagnostics/Profiling.meta | 16 +- .../Diagnostics/Profiling/FrameDataStructs.cs | 174 +- .../Profiling/FrameDataStructs.cs.meta | 4 +- .../Profiling/ProfilerFrameData.cs | 202 +- .../Profiling/ProfilerFrameData.cs.meta | 4 +- .../Diagnostics/Profiling/ProfilerRuntime.cs | 586 +- .../Profiling/ProfilerRuntime.cs.meta | 22 +- .../ResourceManager/ResourceLocations.meta | 20 +- .../ResourceLocations/ILocationSizeData.cs | 40 +- .../ILocationSizeData.cs.meta | 22 +- .../ResourceLocations/IResourceLocation.cs | 126 +- .../IResourceLocation.cs.meta | 26 +- .../ResourceLocations/ResourceLocationBase.cs | 338 +- .../ResourceLocationBase.cs.meta | 26 +- Runtime/ResourceManager/ResourceManager.cs | 2464 +++--- .../ResourceManager/ResourceManager.cs.meta | 26 +- .../ResourceManager/ResourceProviders.meta | 20 +- .../ResourceProviders/AssetBundleProvider.cs | 1946 ++--- .../AssetBundleProvider.cs.meta | 22 +- .../AssetDatabaseProvider.cs | 260 +- .../AssetDatabaseProvider.cs.meta | 26 +- .../ResourceProviders/AtlasSpriteProvider.cs | 60 +- .../AtlasSpriteProvider.cs.meta | 22 +- .../ResourceProviders/BinaryAssetProvider.cs | 48 +- .../BinaryAssetProvider.cs.meta | 22 +- .../ResourceProviders/BinaryDataProvider.cs | 406 +- .../BinaryDataProvider.cs.meta | 22 +- .../ResourceProviders/BundledAssetProvider.cs | 486 +- .../BundledAssetProvider.cs.meta | 24 +- .../ResourceProviders/IInstanceProvider.cs | 274 +- .../IInstanceProvider.cs.meta | 26 +- .../ResourceProviders/IResourceProvider.cs | 390 +- .../IResourceProvider.cs.meta | 26 +- .../ResourceProviders/ISceneProvider.cs | 240 +- .../ResourceProviders/ISceneProvider.cs.meta | 22 +- .../ResourceProviders/IUpdateReceiver.cs | 28 +- .../ResourceProviders/IUpdateReceiver.cs.meta | 22 +- .../ResourceProviders/InstanceProvider.cs | 96 +- .../InstanceProvider.cs.meta | 24 +- .../ResourceProviders/JSONAssetProvider.cs | 46 +- .../JSONAssetProvider.cs.meta | 22 +- .../LegacyResourcesProvider.cs | 226 +- .../LegacyResourcesProvider.cs.meta | 26 +- .../ResourceProviders/ResourceProviderBase.cs | 330 +- .../ResourceProviderBase.cs.meta | 26 +- .../ResourceProviders/SceneProvider.cs | 616 +- .../ResourceProviders/SceneProvider.cs.meta | 22 +- .../ResourceProviders/Simulation.meta | 20 +- .../Simulation/VirtualAssetBundle.cs | 1222 +-- .../Simulation/VirtualAssetBundle.cs.meta | 26 +- .../Simulation/VirtualAssetBundleProvider.cs | 396 +- .../VirtualAssetBundleProvider.cs.meta | 26 +- .../VirtualAssetBundleRuntimeData.cs | 140 +- .../VirtualAssetBundleRuntimeData.cs.meta | 26 +- .../Simulation/VirtualBundledAssetProvider.cs | 176 +- .../VirtualBundledAssetProvider.cs.meta | 26 +- .../ResourceProviders/TextDataProvider.cs | 410 +- .../TextDataProvider.cs.meta | 22 +- .../ResourceProviders/WebRequestQueue.cs | 345 +- .../ResourceProviders/WebRequestQueue.cs.meta | 22 +- .../Unity.ResourceManager.asmdef | 62 +- .../Unity.ResourceManager.asmdef.meta | 14 +- Runtime/ResourceManager/Util.meta | 20 +- .../Util/BinaryStorageBuffer.cs | 1728 ++-- .../Util/BinaryStorageBuffer.cs.meta | 22 +- .../Util/ComponentSingleton.cs | 250 +- .../Util/ComponentSingleton.cs.meta | 22 +- .../Util/DelayedActionManager.cs | 402 +- .../Util/DelayedActionManager.cs.meta | 22 +- Runtime/ResourceManager/Util/DelegateList.cs | 242 +- .../ResourceManager/Util/DelegateList.cs.meta | 22 +- Runtime/ResourceManager/Util/Exceptions.cs | 402 +- .../ResourceManager/Util/Exceptions.cs.meta | 22 +- .../ResourceManager/Util/ListWithEvents.cs | 212 +- .../Util/ListWithEvents.cs.meta | 22 +- .../Util/MonoBehaviourCallbackHooks.cs | 72 +- .../Util/MonoBehaviourCallbackHooks.cs.meta | 22 +- .../Util/OperationCacheKeys.cs | 314 +- .../Util/OperationCacheKeys.cs.meta | 22 +- .../ResourceManager/Util/PlatformUtilities.cs | 20 +- .../Util/PlatformUtilities.cs.meta | 22 +- .../Util/ResourceManagerConfig.cs | 1472 ++-- .../Util/ResourceManagerConfig.cs.meta | 22 +- .../Util/UnityWebRequestUtilities.cs | 390 +- .../Util/UnityWebRequestUtilities.cs.meta | 22 +- Runtime/ResourceProviders.meta | 16 +- .../ContentCatalogProvider.cs | 1014 +-- .../ContentCatalogProvider.cs.meta | 22 +- Runtime/Services.meta | 16 +- Runtime/Services/PlatformMappingService.cs | 348 +- .../Services/PlatformMappingService.cs.meta | 22 +- Runtime/Unity.Addressables.asmdef | 53 +- Runtime/Unity.Addressables.asmdef.meta | 14 +- Runtime/Utility.meta | 16 +- .../Utility/ResourceManagerEventCollector.cs | 330 +- .../ResourceManagerEventCollector.cs.meta | 26 +- Runtime/Utility/SerializationUtilities.cs | 424 +- .../Utility/SerializationUtilities.cs.meta | 22 +- Samples~/AddressablesUtility.meta | 16 +- Samples~/AddressablesUtility/.sample.json | 6 +- .../AddressablesUtility.cs | 54 +- .../AddressablesUtility.cs.meta | 22 +- Samples~/ComponentReference.meta | 16 +- Samples~/ComponentReference/.sample.json | 6 +- .../ComponentReference/ComponentReference.cs | 174 +- .../ComponentReference.cs.meta | 22 +- Samples~/CustomAnalyzeRules.meta | 16 +- Samples~/CustomAnalyzeRules/.sample.json | 6 +- Samples~/CustomAnalyzeRules/Editor.meta | 16 +- .../CustomAnalyzeRules/Editor/AddressHasC.cs | 120 +- .../Editor/AddressHasC.cs.meta | 22 +- ...ndleDupeDependenciesMultiIsolatedGroups.cs | 202 +- ...upeDependenciesMultiIsolatedGroups.cs.meta | 22 +- .../Editor/PathAddressIsPath.cs | 164 +- .../Editor/PathAddressIsPath.cs.meta | 4 +- Samples~/CustomBuildAndPlaymodeScripts.meta | 16 +- .../.sample.json | 6 +- .../CustomBuildAndPlaymodeScripts/Editor.meta | 16 +- .../Editor/CustomBuild.asset | 40 +- .../Editor/CustomBuild.asset.meta | 16 +- .../Editor/CustomBuildScript.cs | 2568 +++--- .../Editor/CustomBuildScript.cs.meta | 22 +- .../Editor/CustomPlayMode.asset | 40 +- .../Editor/CustomPlayMode.asset.meta | 16 +- .../Editor/CustomPlayModeScript.cs | 184 +- .../Editor/CustomPlayModeScript.cs.meta | 22 +- .../LoadSceneForCustomBuild.cs | 46 +- .../LoadSceneForCustomBuild.cs.meta | 22 +- .../CustomBuildAndPlaymodeScripts/README.txt | 26 +- .../README.txt.meta | 14 +- Samples~/DisableAssetImportOnBuild.meta | 16 +- .../DisableAssetImportOnBuild/.sample.json | 6 +- .../DisableAssetImportOnBuild/Editor.meta | 16 +- .../Editor/DisableAssetImportOnBuild.cs | 128 +- .../Editor/DisableAssetImportOnBuild.cs.meta | 22 +- Samples~/ImportExistingGroup.meta | 16 +- Samples~/ImportExistingGroup/.sample.json | 6 +- Samples~/ImportExistingGroup/Editor.meta | 16 +- .../Editor/ImportExistingGroup.cs | 358 +- .../Editor/ImportExistingGroup.cs.meta | 22 +- Samples~/PrefabSpawner.meta | 16 +- Samples~/PrefabSpawner/.sample.json | 6 +- Samples~/PrefabSpawner/PrefabSpawnerSample.cs | 130 +- .../PrefabSpawner/PrefabSpawnerSample.cs.meta | 22 +- Samples~/Tests.meta | 16 +- Samples~/Tests/SamplesTests.cs | 188 +- Samples~/Tests/SamplesTests.cs.meta | 22 +- .../Unity.Addressables.Samples.Tests.asmdef | 46 +- ...ity.Addressables.Samples.Tests.asmdef.meta | 14 +- .../Unity.Addressables.SamplesFolder.asmdef | 38 +- ...ity.Addressables.SamplesFolder.asmdef.meta | 14 +- Tests.meta | 16 +- Tests/Editor.meta | 16 +- Tests/Editor/AddressableAnalyticsTests.cs | 736 +- .../Editor/AddressableAnalyticsTests.cs.meta | 22 +- Tests/Editor/AddressableAssetEntryTests.cs | 1988 ++--- .../Editor/AddressableAssetEntryTests.cs.meta | 22 +- .../AddressableAssetEntryTreeViewTests.cs | 804 +- ...AddressableAssetEntryTreeViewTests.cs.meta | 22 +- .../AddressableAssetFolderSubfolderTests.cs | 542 +- ...dressableAssetFolderSubfolderTests.cs.meta | 22 +- .../Editor/AddressableAssetReferenceTests.cs | 576 +- .../AddressableAssetReferenceTests.cs.meta | 22 +- .../AddressableAssetSettingsLocatorTests.cs | 1248 +-- ...dressableAssetSettingsLocatorTests.cs.meta | 22 +- Tests/Editor/AddressableAssetSettingsTests.cs | 2956 +++---- .../AddressableAssetSettingsTests.cs.meta | 22 +- Tests/Editor/AddressableAssetTestBase.cs | 416 +- Tests/Editor/AddressableAssetTestBase.cs.meta | 22 +- Tests/Editor/AddressableAssetUtilityTests.cs | 1012 +-- .../AddressableAssetUtilityTests.cs.meta | 22 +- ...essableAssetsBundleBuildParametersTests.cs | 216 +- ...leAssetsBundleBuildParametersTests.cs.meta | 22 +- Tests/Editor/AddressableAssetsWindowTests.cs | 270 +- .../AddressableAssetsWindowTests.cs.meta | 22 +- Tests/Editor/AnalyzeRules.meta | 16 +- .../AnalyzeRules/AnalyzeRuleBaseTests.cs | 282 +- .../AnalyzeRules/AnalyzeRuleBaseTests.cs.meta | 22 +- .../CheckBundleDupeDependencyTests.cs | 662 +- .../CheckBundleDupeDependencyTests.cs.meta | 22 +- .../CheckResourcesDupeDependenciesTests.cs | 226 +- ...heckResourcesDupeDependenciesTests.cs.meta | 22 +- .../CheckSceneDupeDependenciesTests.cs | 414 +- .../CheckSceneDupeDependenciesTests.cs.meta | 22 +- Tests/Editor/AssetGroupTests.cs | 450 +- Tests/Editor/AssetGroupTests.cs.meta | 22 +- Tests/Editor/AssetReferenceDrawerTests.cs | 2484 +++--- .../Editor/AssetReferenceDrawerTests.cs.meta | 22 +- Tests/Editor/BinaryStorageBufferTests.cs | 948 +-- Tests/Editor/BinaryStorageBufferTests.cs.meta | 22 +- Tests/Editor/Build.meta | 16 +- .../Build/AddHashToBundleNameTaskTests.cs | 162 +- .../AddHashToBundleNameTaskTests.cs.meta | 22 +- .../Build/AddressableBuildTaskTestBase.cs | 108 +- .../AddressableBuildTaskTestBase.cs.meta | 22 +- .../AddressablesPlayerBuildProcessorTests.cs | 292 +- ...ressablesPlayerBuildProcessorTests.cs.meta | 22 +- .../Build/BuildLayoutGenerationTaskTests.cs | 1438 ++-- .../BuildLayoutGenerationTaskTests.cs.meta | 22 +- Tests/Editor/Build/BuildMenuTests.cs | 262 +- Tests/Editor/Build/BuildMenuTests.cs.meta | 4 +- Tests/Editor/Build/BuildScriptFastTests.cs | 44 +- .../Editor/Build/BuildScriptFastTests.cs.meta | 22 +- .../BuildScriptPackedIntegrationTests.cs | 252 +- .../BuildScriptPackedIntegrationTests.cs.meta | 22 +- .../Build/BuildScriptPackedPlayTests.cs | 172 +- .../Build/BuildScriptPackedPlayTests.cs.meta | 22 +- Tests/Editor/Build/BuildScriptPackedTests.cs | 2070 ++--- .../Build/BuildScriptPackedTests.cs.meta | 22 +- Tests/Editor/Build/BuildScriptTests.cs | 1294 +-- Tests/Editor/Build/BuildScriptTests.cs.meta | 22 +- Tests/Editor/Build/BuildScriptVirtualTests.cs | 44 +- .../Build/BuildScriptVirtualTests.cs.meta | 22 +- Tests/Editor/Build/DataBuilderInputTests.cs | 136 +- .../Build/DataBuilderInputTests.cs.meta | 22 +- .../Build/GenerateLocationListsTaskTests.cs | 630 +- .../GenerateLocationListsTaskTests.cs.meta | 22 +- Tests/Editor/BuildReportWindowTests.cs | 242 +- Tests/Editor/BuildReportWindowTests.cs.meta | 22 +- Tests/Editor/BuiltinSceneCacheTests.cs | 214 +- Tests/Editor/BuiltinSceneCacheTests.cs.meta | 22 +- Tests/Editor/ComponentSingletonTests.cs | 230 +- Tests/Editor/ComponentSingletonTests.cs.meta | 22 +- Tests/Editor/ContentCatalogTests.cs | 978 +-- Tests/Editor/ContentCatalogTests.cs.meta | 22 +- Tests/Editor/ContentUpdateTests.cs | 2744 +++--- Tests/Editor/ContentUpdateTests.cs.meta | 22 +- Tests/Editor/CustomTestSchema.cs | 22 +- Tests/Editor/CustomTestSchema.cs.meta | 22 +- Tests/Editor/CustomTestSchemaSubClass.cs | 20 +- Tests/Editor/CustomTestSchemaSubClass.cs.meta | 22 +- Tests/Editor/Diagnostics.meta | 16 +- Tests/Editor/Diagnostics/BuildLayoutTests.cs | 1296 +-- .../Diagnostics/BuildLayoutTests.cs.meta | 4 +- .../EventDataPlayerSessionCollectionTests.cs | 180 +- ...ntDataPlayerSessionCollectionTests.cs.meta | 4 +- .../EventDataPlayerSessionTests.cs | 514 +- .../EventDataPlayerSessionTests.cs.meta | 4 +- .../Diagnostics/EventDataSetStreamTests.cs | 182 +- .../EventDataSetStreamTests.cs.meta | 4 +- Tests/Editor/Diagnostics/EventDataSetTests.cs | 372 +- .../Diagnostics/EventDataSetTests.cs.meta | 4 +- .../Diagnostics/EventGraphListViewTests.cs | 36 +- .../EventGraphListViewTests.cs.meta | 4 +- Tests/Editor/Diagnostics/ProfilerTests.cs | 56 +- .../Editor/Diagnostics/ProfilerTests.cs.meta | 22 +- Tests/Editor/Diagnostics/SegmentIteration.cs | 170 +- .../Diagnostics/SegmentIteration.cs.meta | 22 +- Tests/Editor/DocExampleCode.meta | 16 +- .../DocExampleCode/AddExceptionHandler.cs | 58 +- .../AddExceptionHandler.cs.meta | 22 +- .../DocExampleCode/AsynchronousLoading.cs | 96 +- .../AsynchronousLoading.cs.meta | 22 +- Tests/Editor/DocExampleCode/BatchBuild.cs | 130 +- .../Editor/DocExampleCode/BatchBuild.cs.meta | 22 +- Tests/Editor/DocExampleCode/BuildLauncher.cs | 256 +- .../DocExampleCode/BuildLauncher.cs.meta | 22 +- .../DocExampleCode/CustomBuildScript.cs | 62 +- .../DocExampleCode/CustomBuildScript.cs.meta | 22 +- .../DocExampleCode/CustomDataBuilder.cs | 64 +- .../DocExampleCode/CustomDataBuilder.cs.meta | 22 +- .../DocExampleCode/DeclaringReferences.cs | 170 +- .../DeclaringReferences.cs.meta | 22 +- .../DocExampleCode/DisableBuildWarnings.cs | 36 +- .../DisableBuildWarnings.cs.meta | 22 +- Tests/Editor/DocExampleCode/DownloadError.cs | 94 +- .../DocExampleCode/DownloadError.cs.meta | 22 +- Tests/Editor/DocExampleCode/IDTransformer.cs | 76 +- .../DocExampleCode/IDTransformer.cs.meta | 22 +- .../Editor/DocExampleCode/InstantiateAsset.cs | 74 +- .../DocExampleCode/InstantiateAsset.cs.meta | 22 +- .../DocExampleCode/InstantiateReference.cs | 54 +- .../InstantiateReference.cs.meta | 22 +- Tests/Editor/DocExampleCode/LoadLocation.cs | 200 +- .../DocExampleCode/LoadLocation.cs.meta | 22 +- Tests/Editor/DocExampleCode/LoadMultiple.cs | 110 +- .../DocExampleCode/LoadMultiple.cs.meta | 22 +- Tests/Editor/DocExampleCode/LoadReference.cs | 84 +- .../DocExampleCode/LoadReference.cs.meta | 22 +- Tests/Editor/DocExampleCode/LoadScene.cs | 56 +- Tests/Editor/DocExampleCode/LoadScene.cs.meta | 22 +- Tests/Editor/DocExampleCode/LoadSingle.cs | 68 +- .../Editor/DocExampleCode/LoadSingle.cs.meta | 22 +- .../DocExampleCode/LoadSynchronously.cs | 72 +- .../DocExampleCode/LoadSynchronously.cs.meta | 22 +- .../Editor/DocExampleCode/LoadWithAddress.cs | 90 +- .../DocExampleCode/LoadWithAddress.cs.meta | 22 +- Tests/Editor/DocExampleCode/LoadWithEvent.cs | 82 +- .../DocExampleCode/LoadWithEvent.cs.meta | 22 +- .../DocExampleCode/LoadWithIEnumerator.cs | 82 +- .../LoadWithIEnumerator.cs.meta | 22 +- Tests/Editor/DocExampleCode/LoadWithLabels.cs | 116 +- .../DocExampleCode/LoadWithLabels.cs.meta | 22 +- .../DocExampleCode/LoadWithReference.cs | 84 +- .../DocExampleCode/LoadWithReference.cs.meta | 22 +- Tests/Editor/DocExampleCode/LoadWithTask.cs | 174 +- .../DocExampleCode/LoadWithTask.cs.meta | 22 +- .../DocExampleCode/MiscellaneousTopics.cs | 356 +- .../MiscellaneousTopics.cs.meta | 22 +- Tests/Editor/DocExampleCode/MyRule.cs | 84 +- Tests/Editor/DocExampleCode/MyRule.cs.meta | 22 +- .../DocExampleCode/OperationHandleTypes.cs | 64 +- .../OperationHandleTypes.cs.meta | 22 +- Tests/Editor/DocExampleCode/Preload.cs | 36 +- Tests/Editor/DocExampleCode/Preload.cs.meta | 22 +- .../DocExampleCode/PreloadWithProgress.cs | 112 +- .../PreloadWithProgress.cs.meta | 22 +- .../DocExampleCode/PrintBucketInformation.cs | 54 +- .../PrintBucketInformation.cs.meta | 22 +- Tests/Editor/DocExampleCode/Readme.txt | 34 +- Tests/Editor/DocExampleCode/Readme.txt.meta | 14 +- .../DocExampleCode/ScriptReference.meta | 16 +- .../ScriptReference/ContentBuiltCheck.cs | 66 +- .../ScriptReference/ContentBuiltCheck.cs.meta | 22 +- .../UsingAddResourceLocator.cs | 108 +- .../UsingAddResourceLocator.cs.meta | 22 +- .../ScriptReference/UsingBuildPath.cs | 48 +- .../ScriptReference/UsingBuildPath.cs.meta | 22 +- .../UsingCheckForCatalogUpdates.cs | 66 +- .../UsingCheckForCatalogUpdates.cs.meta | 22 +- .../ScriptReference/UsingCleanBundleCache.cs | 120 +- .../UsingCleanBundleCache.cs.meta | 22 +- .../UsingClearDependencyCacheAsync.cs | 28 +- .../UsingClearDependencyCacheAsync.cs.meta | 22 +- .../UsingClearResourceLocators.cs | 28 +- .../UsingClearResourceLocators.cs.meta | 22 +- .../UsingDownloadDependencies.cs | 28 +- .../UsingDownloadDependencies.cs.meta | 22 +- .../UsingDownloadDependenciesAsync.cs | 28 +- .../UsingDownloadDependenciesAsync.cs.meta | 22 +- .../ScriptReference/UsingGetDownloadSize.cs | 32 +- .../UsingGetDownloadSize.cs.meta | 22 +- .../UsingGetDownloadSizeAsync.cs | 30 +- .../UsingGetDownloadSizeAsync.cs.meta | 22 +- .../ScriptReference/UsingGetLocatorInfo.cs | 154 +- .../UsingGetLocatorInfo.cs.meta | 22 +- .../UsingInitializationOperation.cs | 28 +- .../UsingInitializationOperation.cs.meta | 22 +- .../ScriptReference/UsingInitialize.cs | 34 +- .../ScriptReference/UsingInitialize.cs.meta | 22 +- .../ScriptReference/UsingInitializeAsync.cs | 172 +- .../UsingInitializeAsync.cs.meta | 22 +- .../ScriptReference/UsingInstanceProvider.cs | 132 +- .../UsingInstanceProvider.cs.meta | 22 +- .../ScriptReference/UsingInstantiate.cs | 28 +- .../ScriptReference/UsingInstantiate.cs.meta | 22 +- .../ScriptReference/UsingInstantiateAsync.cs | 340 +- .../UsingInstantiateAsync.cs.meta | 22 +- .../UsingInternalIdTransformFunc.cs | 122 +- .../UsingInternalIdTransformFunc.cs.meta | 22 +- .../ScriptReference/UsingLoadAsset.cs | 28 +- .../ScriptReference/UsingLoadAsset.cs.meta | 22 +- .../ScriptReference/UsingLoadAssetAsync.cs | 238 +- .../UsingLoadAssetAsync.cs.meta | 22 +- .../ScriptReference/UsingLoadAssets.cs | 28 +- .../ScriptReference/UsingLoadAssets.cs.meta | 22 +- .../ScriptReference/UsingLoadAssetsAsync.cs | 28 +- .../UsingLoadAssetsAsync.cs.meta | 22 +- .../UsingLoadContentCatalog.cs | 28 +- .../UsingLoadContentCatalog.cs.meta | 22 +- .../UsingLoadContentCatalogAsync.cs | 28 +- .../UsingLoadContentCatalogAsync.cs.meta | 22 +- .../UsingLoadResourceLocations.cs | 28 +- .../UsingLoadResourceLocations.cs.meta | 22 +- .../UsingLoadResourceLocationsAsync.cs | 28 +- .../UsingLoadResourceLocationsAsync.cs.meta | 22 +- .../ScriptReference/UsingLoadScene.cs | 28 +- .../ScriptReference/UsingLoadScene.cs.meta | 22 +- .../ScriptReference/UsingLoadSceneAsync.cs | 28 +- .../UsingLoadSceneAsync.cs.meta | 22 +- .../ScriptReference/UsingLog.cs | 40 +- .../ScriptReference/UsingLog.cs.meta | 22 +- .../ScriptReference/UsingLogError.cs | 34 +- .../ScriptReference/UsingLogError.cs.meta | 22 +- .../ScriptReference/UsingLogErrorFormat.cs | 36 +- .../UsingLogErrorFormat.cs.meta | 22 +- .../ScriptReference/UsingLogException.cs | 96 +- .../ScriptReference/UsingLogException.cs.meta | 22 +- .../ScriptReference/UsingLogFormat.cs | 38 +- .../ScriptReference/UsingLogFormat.cs.meta | 22 +- .../ScriptReference/UsingLogWarning.cs | 32 +- .../ScriptReference/UsingLogWarning.cs.meta | 22 +- .../ScriptReference/UsingLogWarningFormat.cs | 36 +- .../UsingLogWarningFormat.cs.meta | 22 +- .../UsingPlayerBuildDataPath.cs | 116 +- .../UsingPlayerBuildDataPath.cs.meta | 22 +- .../ScriptReference/UsingRelease.cs | 28 +- .../ScriptReference/UsingRelease.cs.meta | 22 +- .../ScriptReference/UsingReleaseInstance.cs | 28 +- .../UsingReleaseInstance.cs.meta | 22 +- .../UsingRemoveResourceLocator.cs | 28 +- .../UsingRemoveResourceLocator.cs.meta | 22 +- .../ScriptReference/UsingResolveInternalId.cs | 28 +- .../UsingResolveInternalId.cs.meta | 22 +- .../ScriptReference/UsingResourceLocators.cs | 28 +- .../UsingResourceLocators.cs.meta | 22 +- .../ScriptReference/UsingResourceManager.cs | 28 +- .../UsingResourceManager.cs.meta | 22 +- .../ScriptReference/UsingRuntimePath.cs | 28 +- .../ScriptReference/UsingRuntimePath.cs.meta | 22 +- .../UsingStreamingAssetsSubFolder.cs | 42 +- .../UsingStreamingAssetsSubFolder.cs.meta | 22 +- .../ScriptReference/UsingUnloadSceneAsync.cs | 158 +- .../UsingUnloadSceneAsync.cs.meta | 22 +- .../UsingWebRequestOverride.cs | 64 +- .../UsingWebRequestOverride.cs.meta | 22 +- Tests/Editor/DocExampleCode/TestStub.cs | 30 +- Tests/Editor/DocExampleCode/TestStub.cs.meta | 22 +- .../DocExampleCode/WebRequestOverride.cs | 70 +- .../DocExampleCode/WebRequestOverride.cs.meta | 22 +- Tests/Editor/DomainReloadTests.cs | 136 +- Tests/Editor/DomainReloadTests.cs.meta | 22 +- .../EditorAddressablesAssetsTestFixture.cs | 222 +- ...ditorAddressablesAssetsTestFixture.cs.meta | 22 +- .../EditorPlatformMappingServiceTests.cs | 42 +- .../EditorPlatformMappingServiceTests.cs.meta | 22 +- Tests/Editor/GUI.meta | 3 + Tests/Editor/GUI/UpgradeNotificationsTests.cs | 126 + .../GUI/UpgradeNotificationsTests.cs.meta | 3 + Tests/Editor/GroupSchemaTests.cs | 1010 +-- Tests/Editor/GroupSchemaTests.cs.meta | 22 +- Tests/Editor/HideResourceFoldersScope.cs | 86 +- Tests/Editor/HideResourceFoldersScope.cs.meta | 22 +- Tests/Editor/HostingServices.meta | 16 +- .../AbstractTestHostingService.cs | 108 +- .../AbstractTestHostingService.cs.meta | 22 +- .../HostingServiceInterfaceTests.cs | 354 +- .../HostingServiceInterfaceTests.cs.meta | 22 +- .../HostingServicesManagerTests.cs | 1546 ++-- .../HostingServicesManagerTests.cs.meta | 22 +- .../HostingServicesWindowUtilitiesTests.cs | 198 +- ...ostingServicesWindowUtilitiesTests.cs.meta | 22 +- .../HttpHostingServiceTests.cs | 774 +- .../HttpHostingServiceTests.cs.meta | 22 +- .../HostingServices/TestHostingService.cs | 74 +- .../TestHostingService.cs.meta | 22 +- Tests/Editor/KeyDataStoreTests.cs | 160 +- Tests/Editor/KeyDataStoreTests.cs.meta | 22 +- Tests/Editor/OptionalPackages.meta | 3 + Tests/Editor/OptionalPackages/Ccd.meta | 8 + .../OptionalPackages/Ccd/CcdBuildMenuTests.cs | 874 ++ .../Ccd/CcdBuildMenuTests.cs.meta | 3 + .../Ccd/CcdManagementServiceSdkMock.cs | 60 + .../Ccd/CcdManagementServiceSdkMock.cs.meta | 11 + .../OptionalPackages/Ccd/CcdNotFoundTests.cs | 29 + .../Ccd/CcdNotFoundTests.cs.meta | 3 + .../Editor/OptionalPackages/Diagnostics.meta | 3 + .../Diagnostics/Profiler.meta | 3 + .../AddressablesProfilerDetailsViewTests.cs | 99 + .../OptionalPackages/PlaceholderTests.cs | 16 + .../OptionalPackages/PlaceholderTests.cs.meta | 3 + Tests/Editor/OrgDataTests.cs | 74 +- Tests/Editor/OrgDataTests.cs.meta | 22 +- .../Editor/ProfileDataSourceSettingsTests.cs | 194 +- .../ProfileDataSourceSettingsTests.cs.meta | 22 +- Tests/Editor/ProfileGroupTypeTests.cs | 312 +- Tests/Editor/ProfileGroupTypeTests.cs.meta | 22 +- Tests/Editor/ProfileSettingsTests.cs | 770 +- Tests/Editor/ProfileSettingsTests.cs.meta | 22 +- Tests/Editor/ProfileValueReferenceTests.cs | 154 +- .../Editor/ProfileValueReferenceTests.cs.meta | 22 +- Tests/Editor/ResourceCleanupTests.cs | 106 +- Tests/Editor/ResourceCleanupTests.cs.meta | 22 +- Tests/Editor/ResourcesTestUtility.cs | 64 +- Tests/Editor/ResourcesTestUtility.cs.meta | 22 +- Tests/Editor/SearchFiltersTests.cs | 200 +- Tests/Editor/SearchFiltersTests.cs.meta | 22 +- Tests/Editor/TestObject.cs | 56 +- Tests/Editor/TestObject.cs.meta | 22 +- Tests/Editor/TestSubObject.cs | 16 +- Tests/Editor/TestSubObject.cs.meta | 22 +- .../Unity.Addressables.Editor.Tests.asmdef | 96 +- ...nity.Addressables.Editor.Tests.asmdef.meta | 14 +- Tests/Runtime.meta | 16 +- ...sableAssetSettingsResourceLocationTests.cs | 280 +- ...AssetSettingsResourceLocationTests.cs.meta | 22 +- Tests/Runtime/AddressablesImplTests.cs | 1110 +-- Tests/Runtime/AddressablesImplTests.cs.meta | 4 +- Tests/Runtime/AddressablesIntegrationTests.cs | 724 +- .../AddressablesIntegrationTests.cs.meta | 22 +- .../AddressablesIntegrationTestsImpl.cs | 7353 +++++++++-------- .../AddressablesIntegrationTestsImpl.cs.meta | 22 +- Tests/Runtime/AddressablesTestFixture.cs | 585 +- Tests/Runtime/AddressablesTestFixture.cs.meta | 22 +- Tests/Runtime/AddressablesTestUtilities.cs | 543 +- .../Runtime/AddressablesTestUtilities.cs.meta | 22 +- Tests/Runtime/AssemblyInfo.cs | 12 +- Tests/Runtime/AssemblyInfo.cs.meta | 22 +- Tests/Runtime/AssetBundleProviderTests.cs | 681 +- .../Runtime/AssetBundleProviderTests.cs.meta | 22 +- Tests/Runtime/AssetReferenceDrawerTests.cs | 370 +- .../Runtime/AssetReferenceDrawerTests.cs.meta | 22 +- Tests/Runtime/AssetReferenceTestBehavior.cs | 36 +- .../AssetReferenceTestBehavior.cs.meta | 22 +- Tests/Runtime/AsyncTaskTests.cs | 370 +- Tests/Runtime/AsyncTaskTests.cs.meta | 22 +- Tests/Runtime/BuiltInDataTests.cs | 194 +- Tests/Runtime/BuiltInDataTests.cs.meta | 22 +- Tests/Runtime/CleanBundleCacheTests.cs | 780 +- Tests/Runtime/CleanBundleCacheTests.cs.meta | 22 +- ...iagnosticEventCollectorIntegrationTests.cs | 594 +- ...sticEventCollectorIntegrationTests.cs.meta | 22 +- Tests/Runtime/DynamicContentUpdateTests.cs | 1084 +-- .../Runtime/DynamicContentUpdateTests.cs.meta | 22 +- Tests/Runtime/DynamicResourceLocationTests.cs | 428 +- .../DynamicResourceLocationTests.cs.meta | 22 +- Tests/Runtime/IgnoreFailingLogMessage.cs | 42 +- Tests/Runtime/IgnoreFailingLogMessage.cs.meta | 22 +- Tests/Runtime/Initialization.meta | 16 +- .../AddrRuntimePropertiesTests.cs | 448 +- .../AddrRuntimePropertiesTests.cs.meta | 22 +- .../FastModeInitializationTests.cs | 202 +- .../FastModeInitializationTests.cs.meta | 22 +- .../InitializationObjectsAsyncTests.cs | 618 +- .../InitializationObjectsAsyncTests.cs.meta | 22 +- Tests/Runtime/LegacyResourceTests.cs | 366 +- Tests/Runtime/LegacyResourceTests.cs.meta | 22 +- .../Runtime/ManualPercentCompleteOperation.cs | 88 +- .../ManualPercentCompleteOperation.cs.meta | 22 +- Tests/Runtime/ObjectReferenceMonoBehaviour.cs | 22 +- .../ObjectReferenceMonoBehaviour.cs.meta | 22 +- Tests/Runtime/OptionalPackages.meta | 3 + Tests/Runtime/OptionalPackages/Ccd.meta | 3 + .../OptionalPackages/Ccd/CcdManagerTests.cs | 247 + .../Ccd/CcdManagerTests.cs.meta | 3 + Tests/Runtime/ResourceManager.meta | 16 +- Tests/Runtime/ResourceManager/Operations.meta | 16 +- .../Operations/AsyncOperationHandleTests.cs | 418 +- .../AsyncOperationHandleTests.cs.meta | 22 +- .../Operations/BaseOperationBehaviorTests.cs | 754 +- .../BaseOperationBehaviorTests.cs.meta | 22 +- .../Operations/ChainOperationTests.cs | 92 +- .../Operations/ChainOperationTests.cs.meta | 22 +- .../Operations/ProviderOperationTests.cs | 1328 +-- .../Operations/ProviderOperationTests.cs.meta | 22 +- .../ResourceManager/OperationsCacheTests.cs | 274 +- .../OperationsCacheTests.cs.meta | 4 +- .../ResourceManagerBaseTests.cs | 498 +- .../ResourceManagerBaseTests.cs.meta | 22 +- .../ResourceManagerFastModeTests.cs | 54 +- .../ResourceManagerFastModeTests.cs.meta | 22 +- .../ResourceManagerLegacyModeTests.cs | 68 +- .../ResourceManagerLegacyModeTests.cs.meta | 22 +- .../ResourceManagerPackedModeTests.cs | 18 +- .../ResourceManagerPackedModeTests.cs.meta | 22 +- .../ResourceManager/ResourceManagerTests.cs | 904 +- .../ResourceManagerTests.cs.meta | 22 +- .../ResourceManagerUtilityTests.cs | 442 +- .../ResourceManagerUtilityTests.cs.meta | 22 +- .../ResourceManagerVirtualModeTests.cs | 134 +- .../ResourceManagerVirtualModeTests.cs.meta | 22 +- Tests/Runtime/ResourceManager/TestUtil.meta | 16 +- .../ResourceManager/TestUtil/MockProvider.cs | 128 +- .../TestUtil/MockProvider.cs.meta | 22 +- .../Unity.ResourceManager.Tests.asmdef | 36 +- .../Unity.ResourceManager.Tests.asmdef.meta | 14 +- .../VirtualAssetBundleProviderTests.cs | 280 +- .../VirtualAssetBundleProviderTests.cs.meta | 22 +- Tests/Runtime/ResourceProviders.meta | 16 +- .../ContentCatalogProviderTests.cs | 760 +- .../ContentCatalogProviderTests.cs.meta | 22 +- .../ResourceProviders/TextDataProviderStub.cs | 120 +- .../TextDataProviderStub.cs.meta | 4 +- .../RuntimePlatformMappingServiceTests.cs | 46 +- ...RuntimePlatformMappingServiceTests.cs.meta | 22 +- Tests/Runtime/SceneTests.cs | 1230 +-- Tests/Runtime/SceneTests.cs.meta | 22 +- Tests/Runtime/SyncAddressableTests.cs | 1426 ++-- Tests/Runtime/SyncAddressableTests.cs.meta | 22 +- Tests/Runtime/TestBehaviourWithReference.cs | 16 +- .../TestBehaviourWithReference.cs.meta | 22 +- Tests/Runtime/TestObject.cs | 70 +- Tests/Runtime/TestObject.cs.meta | 22 +- Tests/Runtime/TestObject2.cs | 32 +- Tests/Runtime/TestObject2.cs.meta | 22 +- .../TestObjectWithSerializableField.cs | 46 +- .../TestObjectWithSerializableField.cs.meta | 22 +- Tests/Runtime/TestReflectionHelpers.cs | 36 +- Tests/Runtime/TestReflectionHelpers.cs.meta | 22 +- Tests/Runtime/TextDataProviderTests.cs | 154 +- Tests/Runtime/TextDataProviderTests.cs.meta | 4 +- .../Unity.Addressables.Runtime.Tests.asmdef | 64 +- ...ity.Addressables.Runtime.Tests.asmdef.meta | 14 +- package.json | 10 +- package.json.meta | 14 +- readme.md | 2 +- readme.md.meta | 18 +- 1292 files changed, 127600 insertions(+), 125541 deletions(-) create mode 100644 Editor/GUI/UpgradeNotifications.cs create mode 100644 Editor/GUI/UpgradeNotifications.cs.meta create mode 100644 Tests/Editor/GUI.meta create mode 100644 Tests/Editor/GUI/UpgradeNotificationsTests.cs create mode 100644 Tests/Editor/GUI/UpgradeNotificationsTests.cs.meta create mode 100644 Tests/Editor/OptionalPackages.meta create mode 100644 Tests/Editor/OptionalPackages/Ccd.meta create mode 100644 Tests/Editor/OptionalPackages/Ccd/CcdBuildMenuTests.cs create mode 100644 Tests/Editor/OptionalPackages/Ccd/CcdBuildMenuTests.cs.meta create mode 100644 Tests/Editor/OptionalPackages/Ccd/CcdManagementServiceSdkMock.cs create mode 100644 Tests/Editor/OptionalPackages/Ccd/CcdManagementServiceSdkMock.cs.meta create mode 100644 Tests/Editor/OptionalPackages/Ccd/CcdNotFoundTests.cs create mode 100644 Tests/Editor/OptionalPackages/Ccd/CcdNotFoundTests.cs.meta create mode 100644 Tests/Editor/OptionalPackages/Diagnostics.meta create mode 100644 Tests/Editor/OptionalPackages/Diagnostics/Profiler.meta create mode 100644 Tests/Editor/OptionalPackages/Diagnostics/Profiler/AddressablesProfilerDetailsViewTests.cs create mode 100644 Tests/Editor/OptionalPackages/PlaceholderTests.cs create mode 100644 Tests/Editor/OptionalPackages/PlaceholderTests.cs.meta create mode 100644 Tests/Runtime/OptionalPackages.meta create mode 100644 Tests/Runtime/OptionalPackages/Ccd.meta create mode 100644 Tests/Runtime/OptionalPackages/Ccd/CcdManagerTests.cs create mode 100644 Tests/Runtime/OptionalPackages/Ccd/CcdManagerTests.cs.meta diff --git a/CHANGELOG.md b/CHANGELOG.md index 15d8fdeb..e0636761 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,1283 +1,1300 @@ -# Changelog -All notable changes to this package will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). - -## [1.21.19] - 2023-10-17 -- Fixed an issue where scene InternalId collisions were very likely when using dynamic internal asset naming -- Fixed catalogs to use back slashes rather than forward slashes for android builds. -- Fixed an issue where "Failed to remove scene from Addressables profiler" warning occurs when a scene is unloaded. - -## [1.21.18] - 2023-09-23 -- Fixed an issue where scene InternalId collisions were very likely when using dynamic internal asset naming -- Fixed an issue where Android paths were being delimited with '\' rather than '/' - -## [1.21.17] - 2023-08-16 -- Fixed issue where sprite is missing normal texture when using "Use Existing Build" build mode -- Fixed a bug where a GUI style was misspelled in the Editor and was recently fixed -- Fixed an issue where asset loading would occasionally stop working if domain reload was disabled -- Fixed an issue where Android paths were being delimited with '\' rather than '/' - -## [1.21.15] - 2023-08-03 -- Fixed an issue where using binary catalogs causes a crash on Android with ARM7. -- DownloadDepedenciesAsync no longer loads asset bundles into memory -- Fixed an exception getting thrown in the Addressables Report when drilling into a bundle chain - -## [1.21.14] - 2023-06-14 -- Fixed an issue where CleanBundleCache was giving an invalid handle error when Send Profiler Events was turned on -- Fixed issue where provider data wasn't set for catalog downloads, so web request timeouts would default to 0 instead of the given value -- Added the ability to manage Addressables labels from the asset inspector -- Fixed an issue where the Addressables build cache would get cleared even if you pressed no in the popup window. -- Optimised gc allocations with Addressables profiling module data transfer. -- Fixed issue with binary catalog and asset bundle download redirect limit causing an error when set to -1 (default) -- Fixed issue where player preferences for logging runtime exceptions weren't being compiled out using the Editor scripting define -- Fixed an issue where in some cases sprites would not load properly when using a binary catalog - -## [1.21.12] - 2023-05-04 -- Fixed issue with a potential race conditon when calling GetAssetBundle to load local files using WaitForCompletion -- Fixed compiler error when using the profiler module on a noncaching platform. -- Fixed issue where stack overflow occurs for http requests on Unity 2022.1+ when insecure requests are disallowed. -- Added groups field to Inspector and move assets popup. -- Fixed issue where sprite atlas cannot be assigned to an AssetReferenceAtlasedSprite. - -## [1.21.10] - 2023-04-10 -- Fixed Addressables profiler not correctly displaying loaded Asset subObjects where a Asset was loaded due to a direct reference to one of its subObjects. -- Fixed an issue where bundles built with the Append Hash to FIlename bundle naming option had strange interactions with the Prevent Updates option -- Improved performance of BuildLayoutGenerationTask - -## [1.21.9] - 2023-03-07 -- Removed code within WriteObjectToByteList that would never be reached -- Fixed an issue where SceneOps would have update called on them twice per frame -- Fixed an issue where in some circumstances an Operation would continue to have update called on it even after it finished. -- Fixed an issue with Labels window after a domain reload causing a null reference exception. -- Added Remove all unused labels option to labels popup window. -- Fixed issue when not including the address and guid in catalog using content update workflow, would always indicate the asset as changed -- Fixed Addressables profiler module help links to documentation. -- Fixed issue where scenes unloaded due to another scene loading in single mode, would result in the profiler module still reporting the scene as loaded. -- Groups window will now show labels of entries that are not a part of the settings. -- Fixed 404s when uploading files with incorrect environment ID -- Fixed issue where BuildLayoutGenerationTask would sometimes fail in large projects - -## [1.21.8] - 2023-02-09 -- Optimised PostProcessBundles -- Fixed issue where having a runtime profile variable or property to evaluate web urls on Windows platforms can result in malformed urls. -- Fixed possible `NullRefernceException` when importing new assets and `AddressableAssetUtility+SortedDelegate,Register` was called. -- Fixed an issue where EditorGUI.changed would not be properly set in certain circumstances when updating AssetReferences using the inspector -- Fixed CCD build and release to properly upload static groups -- Fixed CCD build and release to allow both static and managed groups in the same profile -- Include additional object dependency information in build layout report -- Addressables Profiler module compatible with Unity Editor 2022.2+ -- Addressables Build Report window added. Compatible with Unity Editor 2022.2+ - -## [1.21.2] - 2022-12-09 -- Fixed issue where folders in Groups window would display the subObjects of assets without expanding the assets. -- Added the ability to copy a subAsset address to clipboard from right click. -- Fixed bundle naming mode option names being unclear when selecting multiple groups. -- Optimised string usage across package -- Updated the way that the Build Layout calculates efficiency to base it off of the dependent file sizes instead of the dependent file count -- Fixed issue where Addressables inspector would not show until Addressables settings have been initialised -- Fixed issue where editor only assets would be marked as changed in the Check for Content Update restrictions window - -## [1.21.1] - 2022-10-05 -- Fixed issue where CcdManagedData State was not being set correctly -- Added IP ping timeout to the Hosting Services window. -- Fixed issue where loading cached bundles using WaitForCompletion in 2021.2+ results in an error. -- Fixed issue when loading urls with unconverted special url characters such as a space. -- Fixed issue where folders in Groups window would display the subObjects of assets without expanding the assets. -- Added public API to support more detailed Build Layout - -## [1.20.5] - 2022-08-03 -- Fixed issue where object picker for the AssetReferenceDrawer would cut off longer asset names due to only being as wide as the property drawer. -- Improved performance of gathering assets for an AssetReference. -- Fixed issue where settings hash was not included in settings.json for runtime settings. -- Fixed issue where CheckBundleDupeDependencies() would cause a null reference when no addressable assets are in a project. -- Fixed issue where WebRequestQueue would throw a NullReferenceException when given an aborted web request as a parameter. -- Fixed issue where renaming a label does not dirty and save settings and serialise to file. -- Fixed an issue where an updating catalogs operation would return a 'Succeeded' status even if its load operation failed. -- Fixed issue where hosting service roots would not change to correct platform when switching platforms in editor. -- Fixed issue where ProfileDataSourceSettings was generating wrong LoadPath url for CCD integration -- Fixed issue where ClearDependencyCacheAsync could try and clear a bundle that is actively loading. -- Fixed issue where web request is not disposed when downloading a file using TextDataProvider -- Fixed issue where DisableAssetImportOnBuild sample does not disable asset imports -- Fixed issue where retrying a download after a CRC mismatch would not occur. - -## [1.20.3] - 2022-06-14 -- Added documentation to several areas (Build, Settings, Profiles, Catalogs, Runtime loading). -- Fixed issue where GatherAllAssets filter would still return subObjects of filtered Assets. -- Fixed issue where content update entries dependent on modified entries and not found as modified by check for content update restrictions -- Fixed issue where the notification for changed static content wasn't getting cleared for assets inside of folders. -- Fixed issue where Sprites belonging to a Sprite Atlas aren't assignable to an AssetReferenceSprite field. -- Fixed issue where RefreshGlobalProfileVariables is called during script compilation. -- Fixed issue where UnauthorizedAccessException occurs when lacking permissions to cache a remote catalog. -- Fixed stack overflow with SortedDelegate and Addressables OnPostProcessAllAssets occurred during invoke a queued invoke and registering a new delegate. -- Fixed issue where SceneLoadParameters were not used when using LoadSceneAsync using SceneLoadParameters. -- Fixed issue where Schema gui with List members would not save when editing in the Group inspector. -- Fixed issue where Serializable types of structs and class members of MonoBehaviour or ScriptableObjects would be returned as a location with GetResourceLocations but would not be loadable. -- Fixed issue where setting default group does not dirty settings. Causing a reload to reset to previous default group. -- Added updated documentation for the 1.20 Content Update workflows -- Fixed issue where AssetReference subasset popup text is always white regardless of Editor skin. -- Fixed issue where newly created assets would not show the Addressables inspector until after a domain reload. -- Optimised Build pass Post Process Bundles when running on a large number of asset dependency trees. -- A warning now gets printed if caching data fails due to Application.persistentDataPath being an empty string -- Fixed issue where pressing the Reset button on the Hosting window would not assign a new random available port number. -- Fixed bug where WaitForCompletion could hang indefinitely under certain race conditions (primarily on Android) -- Fixed a bug where calling WaitForCompletion on a LoadAssetAsync call that was loading from Resources would freeze the editor. - -## [1.20.0] - 2022-04-20 -- Added ability to get the download size of a given Content Catalog by its resource location -- Add option to save the bundle build layout report as a json or txt file in the Preferences window. -- Added sample for resolving duplicate dependencies to multiple groups. -- AddressableAssetProfileSettings.GetProfileDataById and AddressableAssetProfileSettings.GetProfileDataByName public -- Added ability to load scenes using SceneLoadParameters through Addressables API. -- Made the following API public: - - AsyncOperationHandle.IsWaitingForCompletion - - AssetBundleResource.LoadType - - AssetBundleResource.GetLoadInfo() - - AssetBundleResource.GetAssetPreloadRequest() - - AssetBundleResource.Start() - - AssetBundleResource.Unload() - - WebRequestQueueOperation.Result - - WebRequestQueueOperation.OnComplete - - WebRequestQueueOperation.IsDone - - WebRequestQueueOperation.WebRequest - - WebRequestQueueOperation.ctor() - - WebRequestQueue.SetMaxConcurrentWebRequests() - - WebRequestQueue.QueueRequest() - - WebRequestQueue.WaitForRequestToBeActive() - - ResourceManagerConfig.ExtractKeyAndSubKey() - - UnityWebRequestUtilities.RequestHasErrors() - - UnityWebRequestUtilities.IsAssetBundleDownloaded() - - UnityWebRequestResult.Error.set - - UnityWebRequestResult.ShouldRetryDownloadError -- Made the following API protected: - - AssetBundleProvider.UnloadingBundles.get - - AsyncOperationBase.ReferenceCount - - AsyncOperationBase.IncrementReferenceCount - - AsyncOperationBase.DecrementReferenceCount -- Added functionality to extend groups window build menu with pre and post build methods -- Fixed issue where custom analyze rules that are subclasses cannot be registered. -- Added more tooltips to UI -- Fixed issue where loading assets using a Location without initialising first would not initialise Addressables. -- Content Update workflow has been changed to be more streamlined. New settings have been added to handle Content Update and the previous state .bin file can now be automatically loaded instead of requiring manual selection. -- Set default max concurrent Web requests value to 3. -- Pre-cache delegate list for Completed and CompletedTypeless to reduce GC allocation. -- Fixed issue where Scenes can be incorrectly reported as being in multiple bundles with Bundle Layout Preview analyze rule -- Fixed bug where requests for a ResourceLocation that pointed to a scene in an Addressable folder wasn't returning the location -- Fixed issue where content update could fail to update built-in shaders and monoscript bundles to load from the correct location. -- Cache results of FindEntry to improve performance when no changes are made. -- Fixed an issue where the AddressableAssetEntry returned by GetFolderSubEntry would not include the labels of the entry -- Fixed issue where inherited fast mode scripts would fail to use instance and scene providers set for that build script object. -- Fixed issue where multiple AssetReferences could not be dragged and dropped to a list or array. -- Improved performance when deleting Addressable Asset Groups. - -## [1.19.19] - 2022-03-01 -- Improved message of InvalidKeyException errors. -- Improved exception message of RemoteProviderExceptions -- Fixed issue where Clear Cache Behavior setting was getting reverted when changed while multi-selecting schemas -- Fixed an issue where when building with Missing References in the groups window a NullRefException would occur -- Added documentation explaining why the user might hit a deadlock when calling WaitForCompletion when loading multiple scenes in succession -- Fixed issue where DownloadDependenciesAsync with merge mode did not unload AssetBundles correctly -- Added ComponentReference and Custom Analyze Rule to Samples folder. -- Fixed issue where BundledAssetGroupSchema custom paths reset to default local paths after a domain reload. -- Added assemblyInfo to manage visible internals -- Fixed issue causing InvalidOperationException when loading Addressable Settings from OnPostProcessAllAsset during a project load without a cached AssetDatabase -- Fixed an issue where calling LoadSceneAsync.WaitForCompletion immediately after loading a scene singly would cause a freeze - -## [1.19.18] - 2022-01-31 -- Fixed issue where WaitForCompletion would take too long when used in virtual mode. -- Updated the documentation to include information on methods of waiting on asynchronous operations to complete. -- Fixed issue where IOException occurs when autoCleanBundleCache has value of 'true' in Addressables.UpdateCatalogs. -- Improved Addressables class Inspector headers with documentation links. -- Fixed issue in Editor where a large number of AssetReferences causes performance spikes -- Documentation has been added for shared bundles, HTTP restrictions in 2022 editor versions, Samples, and various cleanup -- Fixed issue with missing trace events in build profile trace log -- Fixed issue where adding a AddressablesGroupTemplate could not be added, throwing an Exception -- Added better logging when built in Editor Hosting Service fails to acquire a port -- Improved ordering of when OnPostprocessAllAssets occurs for Addressables settings and windows to ensure Addressable settings are processed first. -- Fixed issue where "Unable to load assets of type" error occurs when loading asset with classes referenced by value in "Use Asset Database" mode. -- Add more documentation about the "Non-Recursive Dependency Calculation" and "MonoScript Bundle Naming Prefix" options in AddressableAssetSettings. - -## [1.19.17] - 2022-01-06 -- New Projects use hierarchical search mode as the default option for Group search. -- Group referenced by Addressable Schema can now be viewed, but not edited, in the inspector -- Fixed issue where calling Addressables.CleanBundleCache freezes the WebGL player. -- Fixed API inconsistency in CheckForCatalogUpdates. The API wasn't initializing Addressables if it was the first point of contact in the system. -- Fix issue where opening the Analyze window logs null exceptions after running the "Check Duplicate Bundle Dependencies" rule. -- Add platform type to ""Use Existing Build"" display name in the Addressables Groups > Play Mode Script menu." -- Fixed issue where Scene loading after a content update could result in "RemoteProviderException : Invalid path in AssetBundleProvider: ''.". Fix require a new addressables_content_state.bin to be created." -- Tests for the addressables package are no longer included. These can still be accessed upon request. -- Fixed an issue where calling WaitForCompletion on LoadSceneAsync would sometimes cause a freeze -- Mentioned the AssetBundle loading cache in the docs -- Fixed issue where using WaitForCompletion and loading an AssetBundle through a UnityWebRequest freezes the editor when using 2021.2+. -- Fixed issue where using WaitForCompletion and exceeding the max number of concurrent web requests freezes the editor." -- Updated the docs to use the correct name for the Analyze rule "Bundle Layout Preview" -- Fixed issue where Addressable Asset Entry cached data is not cleared during external changes in some editor versions. - -## [1.19.15] - 2021-12-02 -- Fix issue where opening the Analyze window logs null exceptions after running the "Check Duplicate Bundle Dependencies" rule. - -## [1.19.13] - 2021-11-29 -- Removed AddressableAssetEntryCollection upgrade check on opening project. Improving startup performance. -- Fixed issue where GetAllAsset with includeSubObjects did not get subObjects within Assets in an Addressable folder. -- Improved Groups window label dropdown. Adding the ability to search labels and add new labels from the dropdown. -- Added ability Assets from Analyze window, using double click and right click options on the results. -- Improved performance when displaying Addressables header for selected Assets. -- Fixed issue where Groups not marked as "Include in build" was being including in analyse rules. -- Fixed issue where WaitForCompletion will complete Scene operations, where Scenes require further asynchronous loading to complete correctly. -- Fixed issue where AssetDatabaseProvider.LoadAssetAtPath causes a null exception if the asset is not in the AssetDatabase. -- Fixed issue where "Reentering the Update method is not allowed" exception occurs when calling WaitForCompletion during an async method. -- Added FAQ documentation for internal Bundle Id and Asset naming modes. -- Added documentation describing behaviour of WaitForCompletion of Scenes. -- Added documentation for how script changes affect builds. -- Added documentation about Windows file path limit affecting content builds -- Added note about Sprite Atlas options in the documentation. -- Added Sample for custom build and play mode scripts -- Fixed issue where Editor assets were getting included in a build for certain platforms due to path separator character mis-match -- Fix issue with using custom AssetBundleProvider with custom AssetBundleResource. -- Fixed issue where editor hosting profile variables were serialized to AddressableAssetSettings. - -## [1.19.11] - 2021-10-23 -- Fixed issue with missing reference exception when using addressables where content has not been built. -- Added warning that LZMA compression is not available for WebGL AssetBundles. -- Fixed issue were getting a Group Template fails where the project name or parent directory ended in "Assets". -- Fixed issue where option to build Addressables when building a Player where displayed for unsupported editor versions. -- Fixed issue where hosting services filters ip addresses when entering playmode and no services are in use -- Fixed "Editor Hosted" LoadPath, to work with active local Editor hosting service -- Fixed error where creating new groups would lead to errors if the default build and load path variables were not present in one's profile settings. -- Modified the behavior of AssetReference.editorAsset and AssetReference.SetEditorAsset to be more consistent and intuitive -- Fixed issue where upgrading from versions that didn't have ProfileGroupTypes was causing issues during builds. - -## [1.19.9] - 2021-09-30 -- Fixing a compile error on platforms where the Caching API is stripped. -- Updating ScriptableBuildPipeline dependency - -## [1.19.6] - 2021-09-24 -- Fixed issue where built-in shaders and MonoScript Bundles prefix option was not prefixed to Bundle filename. -- Restructured and updated documentation. -- Fixed an issue where graphs in the event viewer would sometimes scroll off the window -- Fixed issue where an AssetReference field cannot be interacted with the tab and enter keys. -- Fixed issue where an AssetReference label is displayed wrong where the AssetReferece is a child of the property being displayed. -- Added documentation for Addressables.CleanBundleCache -- Fixed issue where editing an open Prefab and saving the Prefab will deselect selected Objects. -- Improved performance of displaying Addressables Inspector in a very large Project. -- Fixed issue where buildlayout.txt would contain incorrect bundle names if a group's bundle naming scheme was set to filename -- Fixed an issue where some platforms were caching catalogs that don't support caching -- Fixed an issue where the popup windows for creating new profiles path variables would appear in seemingly random places. -- Fixed an issue where the popup window for creating a Build and Load path variable pair would not properly display its save button -- Added note in Hosting Services docs about modifying firewall settings when testing on other devices. -- Added handling of possible exceptions when caching catalog files. - -## [1.19.4] - 2021-08-24 -- Removing support for 2018.4 -- Added options for building Addressables content as a prebuild step when building Player. -- Optimised StreamingAssets usage to no longer need to be copied into the project (2021.2+). -- Fixed issue where OnDestroy use of Addressables API results in errors when Enter Play Mode Settings are enabled. -- Set AssetEntryCollection is Obsolete, includes auto update process to create Group entries from EntryCollections. -- Updated CheckForCatalogUpdates to properly report any failures that occur while its running. -- Combined BundledAssetGrupSchema CRC settings to a single value. -- BundledAssetGroupSchema Request Timeout will now use time in seconds since last time data wasa downloaded. -- Fixed issue where Exceptions in UnityWebRequest.Send were not caught. -- Updated the way that CompletedOperation events are handled in the Event Viewer to make it easier to associate a given CompletedOperation with its corresponding ChainOperation -- References to Time.deltaTime throughout Addressables are now replaced with Time.unscaledDeltaTime to better match whats described in the API -- Improved the performance of the ProcessAllGroups build step. -- Fixed a bug where having unmatched brackets in a profile's value could lead to a freeze. -- Fixed a bug where certain patterns of values in a profile variable would occasionally lead to an InvalidOperationException while building -- Added check to prevent infinite loop during WaitForCompletion during Asset Database Mode and Simulate Groups Mode -- Users can now supply a callback to receive the UnityWebRequest before being sent by web-based providers -- Added new API to clear the bundle cache for nonreferenced remote asset bundles. UpdateCatalogs has a new optional parameter called autoCleanBundleCache that when enabled will clear the bundle cache for nonreferenced remote asset bundles. -- New public APIs - - BundledAssetGroupSchema.AssetLoadMode - - AssetBundleProvider.AssetBundleRequestOptions.AssetLoadMode - - Addressables.WebRequestOverride - - ResourceManager.WebRequestOverride - - AddressableAssetSettings.DisableVisibleSubAssetRepresentations - - Exposed Auto release parameter added to InitializeAsync - - BundleRuleBase - - GenerateLocationListsTask.ProcessInput (formally RunInteral) - - BuildScriptPackedMode.PrepGroupBundlePacking - - UnloadSceneAsync APIs with exposed UnloadSceneOptions parameter - - Addressables.CleanBundleCache - - New parameter for Addressables.UpdateCatalogs to auto clean the bundle cache - - ProfileGroupType introduces a new workflow of grouping profile variables in the Addressables Profiles window, otherwise known as path pairs. - -## [1.18.15] - 2021-07-26 -- Improved Addressables inspector for Assets. -- Fixed issue where the hosting window would use an exceptionally high (8-20%) amount of CPU while open with a hosting service created -- Added update on profile change, changed to remove preceding slashes and change all to forward slash for hosting service -- Added documentation explaining why we are unable to support WaitForCompletion (sync Addressables) on WebGL - -## [1.18.13] - 2021-07-13 -- Fixed issue where Addressables would not use a custom Asset Bundle Provider if the default group was empty -- InvalidKeyExceptions are now correctly thrown as InvalidKeyExceptions, as opposed to before, where they were thrown as System.Exceptions. Please note that this may break any checks that rely on InvalidKeyExceptions being thrown as System.Exception -- Fixed issue where UnauthorizedAccessException is logged during a build if content_state.bin is locked by version control integration. -- Fixed issue where user defined callbacks can cause unexpected behavior for async operations that are automatically released. -- Fixed issue where Content Update would not include folder entry sub entries. -- Fixed issue where NullReferenceException was logged when multi-selecting with Resource in Groups TreeView. -- Fixed issue where Check for Content Update Restrictions excludes dependencies for folder entries. -- Fixed issue where AddPostCatalogUpdatesInternal would attempt to remove the hash from strings that did not include a hash, occassionally leading to incorrect bundle names in catalog.json -- Load AssetBundles Asynchronously from UnityWebRequest for supported Editor versions -- Fixed issue where hidden files were being flagged in GetDownloadSizeAsync when "Use Asset Database (fastest)" is enabled. -- Added logic for auto releasing completion handle in InitializeAsync -- Fixed issue where AssetBundleProvider would fail to retry on download dailed -- Fixed bug where Fast Mode wasn't returning the correct resource locations or their types, especially for sub-objects. -- Fixed bug where Hosting Service was not saving if enabled between domain reloads -- Fixed bug where Scenes with Group setting Asset Internal Naming Mode of Filename failed to load -- Fixed bug where Hosting window would occassionally be empty on startup. - -## [1.18.11] - 2021-06-15 -- Improved performance of Labels popup in Groups Window. -- Added "Copy Address to Clipboard" Context menu option in Groups Window. -- Added AssetLoadMode option to AddressableAssetsGroup, adds "Requested Asset And Dependencies" and "All Packed - Assets And Dependencies" load methods. -- (2021.2+) Improved performance of copying local buld path Groups built content when building a Player. -- Removed "Export Addressables" button from groups window because it was no longer in use. -- Fixed issue where loading remote catalog from .json fails when Compress Local Catalog is enabled. -- Fixed issue where loading remote catalog from bundle on WebGL fails when Compress Local Catalog is enabled. -- Added multi-project workflow documentation -- Made CacheInitializationData.ExpirationDelay obsolete -- Improve Hierarchical Search performance in Groups Window. -- Build now fails earlier if invalid or unsupported files are included. -- Fixed issue where renaming Group and Profiles would not cancel using Escape key. -- Fixed issue where StripUnityVersionFromBundleBuild and DisableVisibleSubAssetRepresentations were not being serialised to file. -- Updated content update docs to be a little more clear -- Made ExpirationDelay on the CacheInitializationObjects obsolete -- Reduced amount of main thread file I/O performed during AssetBundle loading - -## [1.18.9] - 2021-06-04 -- Added "Select" button for Addressable Asset in Inspector to select the Asset in the Addressables Groups Window. -- Reduced the number of file copies required during building Addressables and moving Addressables content during Player build. -- Fixed issue with AssetReferenceUIRestriction not working with Lists and Arrays. -- Optimised loading AssetBundles to avoid redundent existing file checks. -- Fixed issue with folder asset entries throwing null ref exceptions when doing a Check for Content Update Restriction -- Added documentation about how to implement custom operations with synchronous behavior -- Added option on AddressableAssetSettings to strip the Unity version from the AssetBundle hash during build. -- Added documentation about useful tools you can use when building Addressables content with a CI pipeline -- Added Import Groups tool to Samples folder. -- Updated documentation for setting up and importing addressable assets in packages." -- Fixed issue where multi-group drag and drop places groups in reverse order. -- Fixed issue where an asset entry is no longer selected in the Project window after it is modified on disk. -- Fixed simulated play mode when "Internal Asset Naming Mode" was set to something other than "Full Path" -- Fixed issues with WaitForCompletion getting stuck in infinite loop during failed operations -- Organised AddressableAssetSettings GUI into more distint setting types. -- Fixed issue where the wrong operation would sometimes be returned by the cache when a project contains over 10K addressable assets -- Added path pairs feature -- Fixed issue where AsyncOperationBase.HasExecuted isn't being reset when the operation is reused. -- Added check to ensure that ResourceManager.Update() is never called from within its own callstack. -- Added ability to rename labels from the label window. -- Added the DisableVisibleSubAssetRepresentations option in Settings. - -## [1.18.4] - 2021-05-06 -- EditorOnly tagged GameObjects in Scenes are no longer detected as duplicates for Scene Analyze results. -- Fixed issue when dragging multiple groups around within the groups window to set their display order. -- Reimplemented AsyncOperationBase.Task API to use TaskComppletionSource instead of creating a background thread. -- Fixed issue where remote .hash file was still being requested when Disable Content Catalog Update on Startup was enabled -- Fixed issue where AssetReference variable names weren't consistently formatted in the inspector -- Fixed bug where Completed callback was not called the same frame for some async operations when WaitForCompletion is used. -- Added Samples to the package. These can be added to the project through the Addressables page in Package Manager - -## [1.18.2] - 2021-04-20 -- Where available use synchronous load api's when AsyncOperationHandle.WaitForCompletion is called. -- Fixed issue where loading of Prefabs and ScriptableObjects in "Use Asset Database" and "Simulate Groups" play mode could cause changes to source Assets. Now those play modes will return instanced copies of the Assets. -- Added "Catalog Download Timeout" to AddressableAssetSettings, used for setting a timeout for .hash and .json catalog file downloads. -- Fixed issue where order of data in catalog.json can change. Order is now sorted to be deterministic. -- Added best practice documentation for define dependant compilation during build time. -- CompletedOperation are now returned to the op pool so they can be reused -- Made AddressableAssetSettings.ContentStateBuildPath public api access. -- Add option for building MonoScript bundle. This approach improves multi bundle dependencies to the same MonoScript. -- Added documentation for AddressableAssetSettings options. -- Improved error handling of failed unity web requests and some other operations. -- Users can now look into the InnerException property of an operation's exception for additional details" -- Fixed issue where .json and .asmdef files in the root of a package folder cannot be marked as Addressable. -- Fixed issue where unmodifiable assets cannot be marked as Addressable. -- Exposed more tools for making custom build scripts -- Exposed InvokeWaitForCompletion to be inheritable by custom operations -- Fixed issue where an url was improperly parsed by LoadContentCatalogAsync() if it contained query parameters -- Fixed issue where the post assigned to a hosting service was changing on domain reloads -- Add option for building asset bundles using "Non-Recursive Dependency calculation" methods. This approach helps reduce asset bundle rebuilds and runtime memory consumption. -- Add upload speed option to the http service settings. Downloads will be provided by the rate set in Kbp/s -- Add an option to force using UnityWebRequest even when AssetBundles are local -- Fixed issue with WebRequestQueue where web requests weren't getting queued correctly -- Fixed issue where looking for default group would spam null reference to GUI if Built In data group was deleted/null - -## [1.17.17] - 2021-04-06 -- Add AssetPostprocessor for AddressableSettings after AssetDatabase is Initialised, if not yet initialised on initial project launch. -- Removed serialisation of m_MainAsset and m_TargetAsset from Group entries. -- Fixed a warning "CacheInitialization.CacheInitOp.m_UpdateRequired'' is assigned but its value is never used" when building for platforms that don't have caching enabled -- A message is printed on successful Addressable build -- Properly save profile variables when switching profiles -- Fixed bug where multi-selected Addressable Groups weren't all getting set dirty on an edit. -- Fixed bug where Fast Mode wasn't respecting Log Runtime Exceptions setting -- Implicit assets are now taken into account when using applying a label restriction on an asset reference - -## [1.17.15] - 2021-03-23 -- Fixed FileNotFoundException when using bundle naming mode "Filename" with Unity Cloud Build. -- Fixed a bug where LoadAssetsAsync handle Completed callback is invoked before all individual Asset callbacks. -- Added in Asset validator on Editor startup. This ensures that assets deleted when the editor was closed are removed from Addressables. -- Fixed bug where the current amount of downloaded bytes was not properly updated - -## [1.17.13] - 2021-03-10 -- Fixed issue when loading a Sprite from a SpriteAtlas from an Addressable folder in AssetDatabase mode. -- Fixed bug in AssetReference "Make Addressable" functionality (when referencing an asset no longer addressable) -- Fixed bug with cyclic references in profile variable causing an infinite loop. -- Fixed bug where cached asset type could get stuck with DefaultType, an invalid Editor type -- Fixed issue where AsyncOperationHandle.Completed is called after AsyncOperationHandle.Task returns when the handle is already done. -- Fixed some faulty logic in GetDownloadStatus() when errors occur -- Removed extra dependencies that were being flagged as modified when running Check For Content Update Restrictions. -- Fixed a bug where the result of a Task could be inconsistent and return null given certain race conditions -- Fixed bug where UnloadSceneAsync decreased ref count more than once, and added unload scene to Release if ref count goes to zero -- Fixed issue where a popup appears when an AddressableAsset file is being modified even if the file is checked out locally. -- Fixed bug where fast mode wasn't showing events in the profiler -- Remove check for isUpdating and isCompiling so GetSettings(true) still tries to load the settings when compiling or updating -- Fixed issue where modified local static bundle dependencies fail to load after updating a previous build. Fix is compatible with older shipped content. - -## [1.17.6-preview] - 2021-02-23 -- Fixed issue where OnGlobalModification events would be EntryMoved when adding new Entries instead of EntryAdded. -- Fixed issue where a previously built player fails to load content after running Content Update with missing local bundles -- Fixed bug where ClearDependencyCacheAsync was throwing invalid handle exceptions if auto releasing the handle -- Fixed a bug when SerializeReference entries in link.xml for addressable was causing Unity linker to fail. -- Added results out parameter to AddressableAssetSettings.BuildPlayerContent. - -## [1.17.5-preview] - 2021-02-08 -- Fixed performance issue when disabling "Addressable" for multiple Assets in the Inspector. -- Added option to set the build path of addressables_content_state.bin file. -- The buildlogtep.json file is not generated when building the catalog bundle. -- Fixed invalid handle exception getting thrown when static AssetReferences were used with domain reload turned off -- Fixed catalog using invalid load path for Groups built with "bundle naming mode" "Filename". -- Added option to set custom prefix on the unitybuiltinshader AssetBundle -- Added documentation explaining how dependencies affect Content Update -- Sub-assets with arbitrary main type can now be assigned to an asset reference if types match - -## [1.17.4-preview] - 2021-01-27 -- Removed unnecessary logging when deleting temporary Addressables build data. -- Added WaitForCompletion() on AsyncOperationHandles. This allows async operation to be executed synchronously -- Alphanumeric sorting in the group window can be enabled through a setting in the editor preferences -- Change to set IgnoreFailures with LoadOptions.IgnoreFailures stored in the IResourceLocation.Data if not null -- Fixed issue when loading legacy Resources from Addressables using the guid when playmode is set to AssetDatabase. -- Fixed some compile warnings on 2020.2 -- Change to use full path for name of cached catalog. - -## [1.17.2-preview] - 2021-01-14 -- Add silent fail option to providers to get rid of error when cache not found as expected -- Hierarchy now fully displayed in search results when 'show groups as hierarchy' and 'hierarchical search' options are enabled -- OnValidate is now called when an AssetReference changes -- Fixed bugs in Use Asset Database play mode related to multiple folders with matching addresses -- Made the following APIs public: - - ResourceManager.CreateChainOperation - - AddressablesAnalyzeResultData - - AddressableAssetSettings.OptimizeCatalogSize - - BundledAssetGroupSchema.AssetNamingMode - - BundledAssetGroupSchema.IncludeAddressInCatalog - - BundledAssetGroupSchema.IncludeGUIDInCatalog - - BundledAssetGroupSchema.IncludeLabelsInCatalog - - BundledAssetGroupSchema.InternalIdNamingMode - - BuildScriptBase.Log - - ResourceManagerRuntimeData.AddressablesVersion - - ProjectConfigData - - ProjectConfigData.ShowSubObjectsInGroupView - - ProjectConfigData.GenerateBuildLayout - - ProjectConfigData.ActivePlayModeIndex - - ProjectConfigData.PostProfilerEvents - - ProjectConfigData.LocalLoadSpeed - - ProjectConfigData.RemoteLoadSpeed - - ProjectConfigData.HierarchicalSearch - - ProjectConfigData.ShowGroupsAsHierarchy - - BuildLayoutGenerationTask - - BuildLayoutGenerationTask.BundleNameRemap - - ExtractDataTask.BuildContext - - ContentCatalogData.SetData(IList data, bool optimizeSize) - - ContentCatalogData(string id) constructor - - ContentUpdateContext - - ContentUpdateContext.GuidToPreviousAssetStateMap - - ContentUpdateContext.IdToCatalogDataEntryMap - - ContentUpdateContext.BundleToInternalBundleIdMap - - ContentUpdateContext.WriteData - - ContentUpdateContext.ContentState - - ContentUpdateContext.Registry - - ContentUpdateContext.PreviousAssetStateCarryOver - - RevertUnchangedAssetsToPreviousAssetState - - RevertUnchangedAssetsToPreviousAssetState.Run - - AddressableAssetEntry.GetAssetLoadPath(bool isBundled, HashSet otherLoadPaths) - - AddressableAssetSettings.IgnoreUnsupportedFilesInBuild - -## [1.17.0-preview] - 2020-12-13 -- Added option to clear other cahced versions of asset bundles when a new version has been loaded. -- Added options for internal naming of asset bundles. This will allow for deterministic naming to avoid unintended diffs for content updates. -- The "Ignore Invalid/Unsupported Files" option is now saved in the settings -- Fixed issue where Filename only bundle naming schemas were overwriting old bundles prematurely in content update. - -## [1.16.19] - 2021-04-08 -- Fixed an issue where the group property of the AddressableAssetGroupSchema was not persisted, and could get lost when objects were reloaded - -## [1.16.18] - 2021-03-23 -- Fixed compile warning in Unity 2020.2+ - -## [1.16.17] - 2021-02-25 -- Updated group rename logic to support engine AssetDatabase fix. Change should be transparent to users. - -## [1.16.16] - 2021-01-20 -- Updated dependency versions for testcase fix - -## [1.16.15] - 2020-12-09 -- Addressables link.xml should now have it's own folder. -- Fixed an issue where InvalidKeyException was getting thrown when calling GetDownloadSizeAsync on scenes -- Resources folders inside Unity packages now get added to the Built In Data group -- Fixed issue where getting selected subasset would cause an error if any subassets' type was null - -## [1.16.13] - 2020-11-18 -- Added option to invert the display of CheckBundleDupeDependencies Analyze rule -- Fix GatherEntryLocations for scenes when parameter type is null -- Added some API docs for RuntimeBuildLog and AnalyzeResultData that were missing. -- Updated docs to explain the use of profile variables a little better. -- Added ability to toggle Check Duplicate Bundle Dependencies analyze rule results to be arranged by Group or Asset -- Allow assets that are inside a com.unity* package to be marked as addressable - -## [1.16.10] - 2020-11-04 -- Added internal naming option for the Bundled Asset Group Schema. Instead of using the full path, there are options to use the asset guid or the hashcode of the guid. These values are stable and wont change if the asset path changes, reducing the need to rebuild a bundle if paths change but contents do not. The internal ids stored in the content catalog will generally be shorter than asset paths - 32 bytes for the full guid, 8 bytes for the guid hash. -- Added option to exclude sub catalog entries by file extension -- Added options to exclude catalog entries for address, labels, and guids -- Added option to optimize catalog size by extracting duplicated string in urls and file paths -- Fixed issue where ResourceLocations were returning null for the ResourceType. -- Added warning to build when an Addressable Group doesn't have any AddressableAssetGroupSchemas -- Fixed issue where resource folder search was case sensitive for Mac and Linux -- Fixed issue where warnings were getting logged incorrectly when marking an asset as Addressable using the checkbox in the inspector. -- Fixed issue where an AssetReference's cached asset is not reset when the underlying asset re-imports. -- Fixed issue where we were still checking for CRC when a bundle was cached. -- Fixed bug when using Play Mode Script "Use AssetDatabase (fastest)", and calling Addressables.LoadContentCatalogAsync would fail when it had not been cached. - -## [1.16.7] - 2020-10-21 -- Fixed issue where InvalidHandle errors were getting thrown if an operation failed with releaseDependenciesOnFailure turned on. -- Fixed group build and load paths not being saved when editing multiple groups at once -- Changed Analyze Result data to be cached in the Library. Result data was previously stored in Assets/AddressableAssetsData/AnalyzeData/AnalyzeRuleData.asset. It is now stored in Library/com.unity/addressables/AnalyzeData/AnalyzeRuleData.json. If detected, the Assets - version of the Analyze data will be automatically cleaned up. -- Fixed line in AsyncOperationHandle documentation that told the wrong API for acquiring a handle -- Moved the content update documents to their own page. Expanded and clarified information on the update process - -## [1.16.6] - 2020-09-30 -- Group hierarchy support in groups window by detecting '-' in group name - - This can be turned on & off in the addressable asset settings inspector: Group Hierarchy with Dashes - - This only affects the visual display, groups are still stored in the main settings object in a flat list - - The group name is unaffected. If you name a group "x-y-z" that will be it's name, but, with the option on, it will display as if it was in a folder called "y" that was inside a folder called "x" -- Fixed fast mode resource locator Keys property to expand all possible keys when accessed. For large projects with many addressable entries and folders, this property may be slow when called for the first time. -- Added detailed build layout feature. See documentation for details. -- Fixed issue where assets in Resources weren't show full key in Groups window -- Fixed issue where loading Addressables from a different project was throwing errors. -- Fixed WriteSerializedFiles profile event timings when using the detailed build log -- Selecting multiple Resources and checking "addressable" now display a single popup -- Fixed CreateArrayResult wouldn't work with classes derived from Object, only the base class, so not for ScriptableObject. Also added test -- Fixed exceptions not handled while loading ContentCatalog -- Fixed issue where passing false into releaseDependenciesOnFailure was still releasing dependencies on failure -- Fixed issue where failed operations could over release their dependencies. -- Changes to an AssetReference rendered by AssetReferenceDrawer now register as a GUI change -- Added a checkbox in settings to ignore invalid/unsupported files during build -- empty folders are cleaned-up when moving multiple resources fails -- fixed bug where an error would occur when moving resources for paths without extensions -- Fixed issue where AddressableAsset files locked by version control couldn't be modified. - -## [1.16.1] - 2020-09-15 -- Fixed bug where some files would not be created in the right folder if the user moved its addressables config folder elsewhere -- Fixed determanism issue where bundles could have different names after Editor restart -- Added a blurb to the documentation explaining you have to pack an atlas before the sub objects will show up in the groups window -- Added "addressable" checkbox when viewing package assets in the Inspector. -- Fixed issue where GatherAllAssets would not retrieve assets located in package resources folders. -- Fixed issue where temporary StreamingAssets folder are recreated due to un-deleted meta files during a player build -- added Equals implementation for typeless AsyncOperationHandle -- When AssetReference MainAsset changed, reset SubObject -- resource manager callback leak fixes -- Packed Playmode build logs regarding BuildTargets now show up in PlayMode -- Additional Fast Mode optimizations -- Fixed issue where a released operation was not properly cleaned-up -- Fixed issue where renaming an AssetGroup with a name that contained a period led to unusual renaming behavior. -- Removed Analyze Rule "Check Sprite Atlas To...". This check was not actually valid. See "SpriteAtlas dependencies" section of "Memory Management" page in Addressables documentation for more information. -- UnloadSceneAsync calls that attempt to unload a scene that is still currently loading are now chained with the load operation and will complete after the load is finished. -- The MaxConcurrentWebRequests exposed on the AddressableAssetSettings object now gets set during runtime initialization -- Fix performance issues drawing AssetReferences with subassets caused by earlier changes to AssetReferenceDrawer -- Fixed bug where Addressables.ClearDepenendcyCache wasn't clearing the cache. -- AssetReferenceUILabelRestriction attribute now works properly on references in nested classes - -## [1.15.1] - 2020-08-25 -- Change to not allow the same AssetReference to LoadAssetAsync or LoadSceneAsync twice if current handle is valid, instead log an error with note about how to get the valid handle -- Fixed issue where disabled asset groups data would be included in the addressables_content_state.bin file for the build. -- Add ability to use custom ResourceManager exception handlers by not overwriting it in InitializeAsync if it is not null -- Fixed bug where Content Update would not use asset bundle load options for unchanged static remote bundles. -- Fixed LoadAssetAsync> to return the same set of objects in all play modes. The main asset is always first and hidden objects are ignored. -- Changed keys parameter for many Addressables APIs to be IEnumerable instead of IList. This allows for passing collections of AssetReferences or AssetLabelReferences directly instead of requiring them to be copied into a new List. -- Fix bug where lists of AssetReferenceSprites were not displayed or set right by AssetReferenceDrawer. Also fixed where multiple selected objects in project hierarchy couldn't set all lists of AssetReferences elements. -- Added better error logging when unrecognized file in build. -- Added error log when building asset bundles during player build. -- Added "Hide Events" context menu option in Event Viewer -- Fixed a bug where running the "Check Scene to Addressable Duplicate Dependencies" analyze rule multiple times would cause a duplicate key exception -- The "Check Scene to Addressable Duplicate Dependencies" analyze rule now only considers scenes that are enabled in the build settings. -- Fixed a bug where an error would be thrown when Unity 2019 opens and if the hosting window was previously left open -- Fixed a bug where changes to a service where not applied in the hosting window -- Fixed a bug where profile selection in the inspector was incorrectly reverted to the default one on domain reload -- Added documentation for LoadResourceLocationsAsync -- Added documentation for ResourceManager.ExceptionHandler -- Added documentation for AddressableAssetSettings.BuildPlayerContent -- Added documentation for LoadSceneAsync -- Added ScriptableBuildPipeline Build Callbacks to Addressables Build Scripts -- Temporary files made during bundled catalog creation are now properly cleaned up -- Inspector window now opens if it was closed when inspecting addressable settings -- Fixed bug where AsyncOperation.PercentComplete was returning 100% when IsDone was false before the operation had started. -- Progress bar is no longer updated for every entry while running Analyze rules for performance purposes. -- Fixed loading of scenes from scenes list through Addressables. Clears out an InvalidCastException that occured on init. -- Fixed issue where AssetReference wasn't able to load Addressable assets in folders during AssetDatabase Mode. - -## [1.14.2] - 2020-08-11 -- Addressables now logs the package version on initialization. -- Renamed Build Bundle Layout analyze rule to Bundle Layout Preview -- Marked RawWriteOperation obsolete. -- Marked SceneRawWriteOperation obsolete. -- AsyncOperationHandle ClearDependencyCacheAsync has been added. The new API takes an autoReleaseHandle parameter and returns the AsyncOperationHandle. -- Made the AsyncOperationHandle in AssetReference public. -- Fixed loading of items from Resources and the built in ScenesList. -- Improved the performance of loading local content on Android by using LoadFromFileAsync instead of UnityWebRequest. Please note that the bundle compression mode for all local content (on any platform) should be LZ4 or uncompressed to have optimal load performance. -- Fixed issue where some Addressables settings were not being saved if they were only serialized properties or textfields like 'Build Remote Catalog' -- Fixed a bug where DiagnosticEvents would be created even if 'Send Profiler Events' was set to false. -- Refactored the DebugNames of many of the most common implementations of AsyncOperationHandle to improve readability in the event viewer. -- Events in the Event viewer should now display more accurately in the case of Repeated loads and unloads of the same object. -- AddressableAssetEntry now overrides ToString() to return the address of the entry -- Added support for setting multiple assets and subasset references at a time for field in GameObject script in the AssetReference Inspector -- Improved performance of the GenerateLocationLists task -- Refactored DiagnosticEventCollector.RegisterEventHandler so that events are always handled in frame order. -- Fixed bug where the Event Viewer would not work when connected to a standalone player. -- Added docs describing the process of connecting the Event Viewer to a standalone player. -- Fixed exception that was getting thrown on Editor restart regarding accessing EditorSettings.enterPlayModeOptionsEnabled during serialization. -- Added MaxConcurrentWebRequests option to the AddressableAssetSettings. -- Added GetDownloadStatus method to AsyncOperationHandle. The DownloadStatus struct returned will contain the total number of bytes needed to be downloaded and the current number of bytes already downloaded. Cached AssetBundles will not be included in the count and if everything is cached, the values in the struct will be zero. -- Added Documentation for the following: - - InstantiateAsync - - DownloadDependenciesAsync - - LoadContentCatalogAsync - - UpdateCatalogs - -## [1.13.1] - 2020-07-28 -- Made `AssetReferenceT` be Serializable. This will only matter if using Unity 2020.1 or later. -- Added AddressableAssetSettings.ContiguousBundles option, which when enabled will improve asset loading times. - - In testing, performance improvements varied from 10% improvement over all, with improvements up to 50% for large complex assets such as extensive UI prefabs. -- Add New Build unclickable No Build Script Available option when no valid builder is found and added line in docs to explain what is needed -- Fixed bug where dragging a non addressable asset from an addressable folder in project viewer to AssetReference field would mark the asset as addressable and put it in the default group -- Fixed bug where enumerate exception is being thrown when expanding a group folder containing subfolders in the Addressable Groups window. -- Changed to only ask to convert legacy bundles when AddressableAssetSettings is first created or when selected from the Tools menu -- Fixed bug where clicking on an AssetReference property won't ping the referenced asset in the Project window. -- Fixed bug where GetDownloadSizeAsync was returning non-zero values for cached AssetBundles. -- Removed Event Viewer Record button because it didn't do anything. -- Fixed bug where changes made through the AddressableAssetProfileSettings API would not be immediately represented in the Profiles Window. -- Fixed bug where Instantiation and EventCount events in the Event Viewer would not update as expected. -- Fixed bug where events that occurred immediately after entering play mode would not be properly represented in the Event Viewer. -- Fixed bug where Instantiation and EventCount events would not display their most recent value when inspected in the Event Viewer. -- Added Documentation for the following: - - LoadAssetAsync - - LoadAssetsAsync - - InitializeAsync - - TransformInternalId -- Fixed bug where changing the value of "Optimize Mesh Data" in PlayerSettings doesn't affect bundle building until the old build cache is deleted. -- Expanded bundle dependencies so that loaded bundles maintain a reference to all bundle they references. This fixes various bugs when unloading and reloading a bundle that is being referenced by another bundle. - -## [1.12.0] - 2020-07-14 -- Implemented Undo/Redo capability for the Profiles Window. -- Fixed bug where the Profiles Window would occasionally throw a NullReferenceException when making a new profile. -- Added RenameProfile to the AddressableAssetsProfileSettings API -- Added error messages for failed attempts at renaming a Profile -- Fixed bug where when there are AssetReferences with the same name but in different Addressable groups only one could be selected in field dropdown -- Fixed bug surrounding addressable sprites that were also in a SpriteAtlas -- Fixed bug where loading a scene in a package would only load an empty scene with no contents. -- Fixed bug where Event Viewer window would always be empty. -- LinkXmlGenerator moved to the Scriptable Build Pipeline package in the UnityEditor.Build.Pipeline.Utilities namespace. -- Added documentation to explain how to make packages addressable. -- Fixed bug where ArgumentException errors are thrown when selecting a prefab from a read-only package. -- Fixed bug where setting AssetReference property to null wasn't dirtying the asset -- Fixed a bug where IResourceLocations were returning a false positive on comparison. -- Added error checking to make sure that an address doesn't have '[]'. - -## [1.11.2] - 2020-06-15 -- Refactored Play Mode Script for "Use Asset Database" to pull data directly from the settings. This reduces the time needed to enter play mode. -- Added scrollbar to the Label dropdown -- Fixed misleading dialog box shown to the user when there are unsaved scenes. -- Fixed bug where DownloadDependenciesAsync always returns an AsyncOperationHandle with a null task. -- Fixed bug where AddressableAssetSettings.asset is always being written to disk whenever something is changed in OnPostProcessAllAssets, including asset modified, moved, group created or deleted -- Revamped Profiles window to a two panel layout. -- Fixed issue with Profiles window where changes would occasionally not be serialized to the settings asset. -- Fixed bug where an op with some failed dependencies would never release the ones that had succeeded. -- Added optional parameter "releaseDependenciesOnFailure" to LoadAssetsAsync to handle the scenario of partial success. This is when there are multiple locations being loaded, and not all succeed. In the partial success scenario: - - By default, the new parameter is true, and all successful parts will be released. The .Result on the returned handle will be null and Status will be Failed - - When false, the returned .Result will be a List of size matching the number of matching locations. Any failed location will correlate to null in the List, while successful locations will correlate to valid objects in the List. Status will still be Failed in this scenario. -- Bundles that fail to load from the cache are now removed from the Cache and will be redownloaded. -- Added option to disable CRC checks for cached AssetBundles on BundledAssetGroupSchema under Advanced Options. -- If null is passed into Addressables.UpdateCatalogs(...) for the list of catalogIds, CheckForCatalogUpdates will be called automatically. -- Added null reference check when running InitializationObjectsOperation to take failed RuntimeData operations into account. -- Disabled hitting ENTER on an AssetReference inspector to open popup. The drawer does not know which AssetReference to associate the popup should that MonoBehaviour have more than one. So disabling is unfortunately the only safe option. -- Fixed issue where assets located in subfolders marked as addressable would be added to build content multiple times. -- Fixed bug where Groups window hierarchical search was not filtering the group contents. -- Fixed bug with Groups window flat search not sorting. - -## [1.10.0] - 2020-05-28 -- Fixed hosting service not working for special characters in addressable asset address -- Fixed bug where tracked scene instance operation handles weren't matching the handles returned to the user. -- Fixed bug where Sprite Atlas ResourceProvider wasn't getting added to list of ResourceProviders. -- Fixed bug where pack separately groups were rebuilding all bundles when an asset was added or removed from the group. - -## [1.9.2] - 2020-05-21 -- Improved the performance of GenerateLocationLists. -- Fixed AssetReferenceLabelUIRestriction not working for private fields -- Fixed AssetReferenceDrawer OnGui changing text of static variable GUIContent.none -- Updated documentation to explain what's happening when DontDestroyOnLoad GameObjects are having their dependencies removed when the scene they originate in is unloaded. -- Using a more efficient method of gathering the Addressable entries for the AssetReferenceDropdown UI. -- Fixed bug surrounding how "Use AssetDatabase" build script handles deleted assets. -- Fixed issue where ContentUpdate was throwing an exception if a dependency wasn't in the previous build. -- PercentComplete calcluation updates to correctly take progress callbacks on ProviderOperations into account. -- Added support for Enable Play Mode Options in 2019.3+ -- Fixed issue where diagnostic events are still being sent to the player regardless of the value of "Send Profiler Events". -- Added error checking to make sure that a group doesn't have both a PlayerDataGroupSchema and a BundledAssetGroupSchema. -- Fixed issue where InitializationObjects were causing the InitializationOperation to hang. - -## [1.8.4] - 2020-05-20 -- Taking an updated scriptable build pipeline that reverts a recent hashing change. - -## [1.8.3] - 2020-04-07 -- Option to disable sprites and subobjects has been added to the Groups window Tools menu. This option is persisted per user, not with the project. -- Catalog entries for subobjects and sprites are no longer serialized into the catalog. These are generated at runtime with a custom resource locator. -- Added missing error logs to various failure cases. -- Fixed subobject parsing to treat anything between the first '[' character and the last ']' as the subobject name instead of the last '[' and the last ']'. -- Changed the display of AssetReference types in the inspector from a dropdown to look like an object reference. -- Added the option to compress the local content catalog by packing it in an asset bundle. -- Added method in settings to retrieve all defined labels. -- Fixed PercentComplete in ChainOperation -- Fixed main settings asset getting marked dirty when making builds. -- Fixed issues with Content Update when entry with dependant entries was modified. -- Fixed "Unknown Exception" issue caused by releasing certain operation handles too many times. -- Added link to online documentation in the addressable windows menu. -- Fixed bug where two assets with the same address packed separately was causing an error. -- Fixed issue where loading a content catalog multiple times was throwing exceptions. -- Made it so using the LoadContentCatalogAsync API creates a ResourceLocation that allows those catalogs to be updated properly. -- Fixed bug where the scene in a recycled InstanceOperation wasn't being cleaned. -- Fixed bug where an invalid location would be created for assets that weren't in a Resources folder, but were part of a group with the PlayerDataGroupShema. -- Schema asset file name uses group name instead of GUID. For example: GroupName_SchemaName.asset -- Fixed text that was being cutoff in the CacheIntializationSettings inspector view. -- During init, if a remote catalog is expected but not present, this will fail silently. Fixed a bug where that silent failure showed up later as an "unknown error in async operation". - - if you wish to see a log for the failed catalog retrieval, enable ADDRESSABLES_LOG_ALL as a scripting define symbol. -- Fixed bug where renaming a class referenced by an AddressableAssetEntry causes an InvalidKeyException. -- Fixed performance regression in ContentUpdateScript.SaveContentState -- Fixed performance regression in BuildScriptPackedMode.PostProcessCatalogEntries -- Updated to scriptable build pipeline 1.7.2 which includes many build optimizations - see SBP changelog for details - -## [1.7.5] - 2020-03-23 -- Fixed null key exception when building that happened when an invalid asset type is in a resources folder. - -## [1.7.4] - 2020-03-13 -- Improved building catalog data speed. -- Various minor optimizations related to handling sub objects. -- Added progress bar to the catalog generation part of the build process. -- Gave initialization objects an asynchronous initialization API. -- Made it so a CacheInitializationObject waits for engine side Caching.ready to be true before completing. -- Fixed a bug when accessing AssetReferenceT.editorAsset where the Type does not match the Editor Asset type, Such as a subAsset type. -- Fixed bug where Use Asset Database and Use Existing Build could return a different number of results in LoadAssetAsync> -- Fixed bug where SceneUnload Operations weren't getting properly released in certain circumstances. -- Fixed UI performance regression when opening the Addressables Group Editor window. -- Fixed issue where RuntimeKeyIsValid was give a false negative when checking sub-objects. -- Updating scripting defines to check if caching is enabled. -- Changed the display of AssetReference types in the inspector from a dropdown to look like an object reference. -- Prevent assets from being added to read only Addressable groups through the group editor window. -- Group names can now be searched through the group editor window. -- Added ability to set variables in AddressablesRuntimeProperties more than once. -- Fixed missed null check on drag and drop in Group Editor window. -- Updated Scriptable Build Pipeline dependency to bring in these changes: - - Updated CompatibilityAssetBundleManifest so hash version is properly serializable. - - Renamed "Build Cache" options in the Preferences menu to "Scriptable Build Pipeline" - - Improved performance of the Scriptable Build Pipeline's archiving task. - -## [1.6.2] - 2020-02-08 -- Checking if Profile Events is enabled on the engine side before running the DiagnosticEventCollector Update. -- Fixed issue where RuntimeKeyIsValid was give a false negative when checking sub-objects. -- Fixed Update Previous Build workflow that wasn't re-using previously built Asset Bundle paths when necessary. -- Updated Scriptable Build Pipeline dependency to bring in these changes: - - Fixed an issue where texture sources for sprites were not being stripped from the build. - - Fixed an issue where scene changes weren't getting picked up in a content re-build. - - Fixed an issue where texture sources for non-packed sprites were being stripped incorrectly. -- Fixed issue where hosting service ports were changing on assets re-import. -- Fixed issues with Content Update, including groups that are Packed Separately not updating properly. - -## [1.6.0] - 2020-01-11 -- Fixed bug where unsubscribing to AsyncOperations events could throw if no subscription happened beforehand. -- Fixed NullReferenceException when displaying Groups window displaying entries with Missing Script References on SubAssets. -- Moved AnalyzeWindow.RegisterNewRule to AnalyzeSystem.RegisterNewRule so that the API/logic wouldn't live in GUI code. -- Fixed bug where scenes in a folder containing "Assets" in the folder name not loadable in "Use Asset Database" mode. -- InvalidKeyException's message now include the type of the key that caused it, if applicable. -- Added the ability to select and edit multiple Addressable Groups at the same time. -- Assigning LocationCount during AddressableAssetBuildResult.CreateResult -- Fixed issue where groups and schemas were getting deleted on import. -- Adding dependencies to built in modules to prevent them from being disabled if Addressables is active. -- Adding scripting define to remove Caching API calls when ENABLE_CACHING is false -- Added API to get the scene AsyncOperation from ActivateAsync(). Made the previous API, Activate(), obsolete. -- Fixed bug where the group window wasn't properly refreshed on Analyse fix - -## [1.5.1] - 2020-01-13 -- Fixed issue where groups and schemas were getting deleted on import. -- Adding scripting define to remove Caching API calls when ENABLE_CACHING is false - -## [1.5.0] - 2019-12-09 -- Fixed temporary StreamingAssets files not being removed on a failed player build. -- Added Bundle Naming option for naming as a hash of the full filename string. -- Added a delay before unloaded things are removed from Event Viewer graph. Ideally this would track with dependencies, but for now it's simply time based. -- Fixed ProfileValueReferences not getting set dirty when changed. -- Added ability for Addressables to handle null references in the Addressables groups list. - - Null groups should not affect or influence content builds, updates, or Analyze rules. - - Right clicking on a [Missing Reference] will give you the option to remove all missing references. -- Fixed issue with Analyze reporting multiple duplicate data for one group. -- Fixed issue where unloading a scene was throwing an invalid handle error. -- Added Addressables.ClearDependencyCacheAsync API to clear cached dependent AssetBundles for a given key or list of keys. -- Added type conversion from AnimatorController to RuntimeAnimatorController. - -## [1.4.0] - 2019-11-13 -- Added the ability to disable checking for content catalog updates during initialization. -- Fixed issue where turning off Include in Build in the right circumstances would throw an exception. -- Made internal classes and members public to support custom build scripts. -- Exposed Addressables.InstanceProvider to allow for setting up runtime specific data on custom instance providers. -- Fixed issue with filenames being too long to write to our Temp cache of AssetBundles. -- Changed ProcessGroup in BuildScriptFastMode to directly create catalog entries from Addressable entries. -- Added progress bar to Fast Mode when creating content catalog. - -## [1.3.8] - 2019-11-04 - - Properly suppressing a harmless "Unknown error in AsyncOperation" that has been popping up during init. It had to do with not finding a cached catalog before a catalog had been cached (so error shouldn't happen). - - Fixed issue with asset hash calcluation for internal asset bundle name when building bundles. - - Adding option "Unique Bundle IDs" to the General section of the AddressableAssetSettings Inspector. - - If set, every content build (original or update) will result in asset bundles with more complex internal names. This may result in more bundles being rebuilt, but safer mid-run updates. See docs for more info. - - This complex internal naming was added to 1.3.3 to support safter Content Catalog updating, but was forced on. It is now optional as there are some drawbacks. - -## [1.3.5] - 2019-11-01 - - Added documentation about updating Content Catalog at runtime (outside Init). Uses CheckForCatalogUpdates() and UpdateCatalogs(). - -## [1.3.3] - 2019-10-21 - - UI and naming changes - - "Static true or false" content is now content with an "Update Restriction" of "Cannot Change Post Release" or "Can Change Post Release" - - "Fast Mode" (play mode) has been renamed "Use Asset Database (faster)" - - "Virtual Mode" (play mode) has been renamed "Simulate Groups (advanced)" - - "Packed Mode" (play mode) has been renamed "Use Existing Build (requires built groups)" - - There is no longer a current "Build Script" (Build Script menu in Addressables window). Instead the script is selected when triggering the build. - - Schemas have been given display names to be more clear of their intent BundledAssetGroupSchema. - - BundledAssetGroupSchema displays as "Content Packing & Loading" - - ContentUpdateGroupSchema displays as "Content Update Restriction" - - Bundle and Asset providers within schema settings are named more descriptively - - Profile management is in its own window ("Profiles") - - Label management is in its own window - - "Prepare for Content Update" is now under the "Tools" menu (in Addressables window), and is called "Check for Content Update Restriction" - - "Build for Content Update" is "Update a Previous Build" (still in "Build" menu of Addressables window). - - "Profiler" window has been renamed "Event Viewer". It's more accurate, and avoids confusion with "Profilers" window. - - Added additional parameter to AssetReference.LoadSceneAsync method to match Addressables.LoadSceneAsync API - - Added AssetReference.UnloadScene API - - Fixed issue with WebGL builds where re-loading the page was causing an exception to get thrown. - - Fixed Analyze bug where bundle referenced multiple times was flagged as duplicate. - - Fixed issue with hashing dependencies that led to frequent "INCORRECT HASH: the same hash (hashCode) for different dependency lists:" errors. - - Update AddressableAssetEntry cached path to new modified asset entry paths. - - Storing the KeyData string from ContentCatalogData on disk instead of keeping it in memory as it can get quite large. - - Fixed Custom Hosting Service window so it won't close when focus is lost. - - Fixed issue with AudioMixerGroups not getting the proper runtime type conversion for the build. - - Fixed invalid location load path when using "only hash" bundle naming option in 'content packing and loading' schema. - - Removed content update hash from final AssetBundle filename. - - Removed exception in Analyze that was triggering when "Fix Selected Rules" was bundling in Un-fixable rules. - - (SBP) Fixed an edge case where Optimize Mesh would not apply to all meshes in the build. - - (SBP) Fixed an edge case where Global Usage was not being updated with latest values from Graphics Settings. - - (SBP) Fixed Scene Bundles not rebuilding when included prefab changes. - - Added APIs to update content catalog at runtime: CheckForCatalogUpdates() and UpdateCatalogs(). - -## [1.2.4] - 2019-09-13 - - Further improvement to the % complete calculations. - - Note that this is an average of dependency operations. Meaning a LoadAssetsAsync call will average the download, and the loading progress. DownloadDependenciesAsync currently has one extra op, so the download will crawl to 50%, then jump to done (we will look into removing that). Similarly any op that is called before Addressables init's will jump to 50% once init is done. - -## [1.2.3] - 2019-09-10 - - Actually "Made ContentUpdateScript.GatherModifiedEntries public." - -## [1.2.2] - 2019-09-09 - - Made ContentUpdateScript.GatherModifiedEntries public. - - Added sub-object support to AssetReference. For example, you can now have an AssetReference to a specific sprite within a sprite atlas. - - Added sub-object support to addresses via [] notation. For example, sprite atlas "myAtlas", would support loading that atlas via that address, or a sprite via "myAtlas[mySprite]" - - Fixed issue with Content Update workflow. Assets that don't change groups during Content Update now remain in the same bundle. - - Added funtionality to allow multiple diagnostic callbacks to the ResourceManager. - - Added error and IResourceLocation to the callback. - - Added default parameter to DownloadDependenciesAsync to allow auto releasing of the the operation handle on completion. - - Added memory management documentation. - - Changed OnlyHash naming option to remove folder structure. This is a workaround to Windows long-file-path issues. - - Made AssetReference interfaces virtual - - Fixed hash calculations to avoid collisions - - Added overload for GetDownloadSizeAsync. The overload accepts a list of keys and calculates their total download size. - - Improved percent complete calculations for async opertions. - -## [1.1.10] - 2019-08-28 - - Fix for all files showing "Missing File" in the addressables window. - - Fix for waiting on a successfully done Task - -## [1.1.9] - 2019-08-22 - - Fixed drag and drop NullRef in main addressables window. - - Fixed AudioMixer type assets getting stripped from bundles. - - Fixed issue where failed async operations weren't getting released from the async operation cache. - - Fix unloading of scenes so that the dependencies will wait for the unload operation to complete before unloading. This was causing an occasional 1-frame visual glitch during unload. - - Fixed scenario where AsyncOperation Task fails to complete when AsyncOperation has already completed. - - Fixed a missed init-log that was stuck always-logging. - - Fixed issue around assets losing dependencies when unloaded then reloaded. This would manifest most often as sprites losing their texture or prefabs losing their shader/material/texture. - - Changed checks for determining if a path is remote or not from looking for "://" to looking for starting with "http". "://" is still used to determine if the asset should be loaded via UnityWebRequest or not. - - Added Analyze Rule to show entire Asset Bundle layout - - Added progress bars and some optimizations for calculating analyze rules - -## [1.1.7] - 2019-07-30 - - Fixed chain operation percent complete calculation. - - Fixed scenario where deleting assets would also delete groups that have similar names. - - Fix in bundle caching bug surrounding bundles with '.' in their name - - Significant improvements to the manual pages - - Made the many init-logs not log unless ADDRESSABLES_LOG_ALL is defined in player settings (other logs always worked this way, init didn't). - - Prevented NullReferenceException when attempting to delete entries in the Addressables window. - - Fix for building by label (Bundle Mode = Pack Together By Label) - - Removed ability to mark editor-only assets as addressable in GUI - - Better fix to Editor types being added to the build - - Made BuiltIn Data group read-only by default. - - Fixed NullRef caused by an invalid (BuildIn Data) group being default during a build. - - Fixed path where LoadResourceLocationsAsync could still throw an exception with unknown key. Now it should not, and is a safe way to check for valid keys. - - If Key does not exist but nothing else goes wrong, it will return an empty list and Success state. - - Fixed NullRef caused when there was a deleted scene in the scenes list. - - BuildCompression for Addressables can now be driven from the default group. If necessary WebGL builds will fallback to LZ4Runtime and all other build targets will fallback to LZMA. - - Added options for bundle naming: AppendHash, NoHash, OnlyHash. - - As a temporary workaround for updating issues, we recommend setting all groups with StaticContent=true to be NoHash. This will make sure the updated catalog still refers to the correct unchanged bundle. An actual fix will be out in a few releases. - -## [1.1.5] - 2019-07-15 - - Fixed scenario where scene unload simultaneously destroys objects being instantiated in different scenes. - - Cleaned up SetDirty logic to remove excessive dirtying of assets. - -## [1.1.4-preview] - 2019-06-19 - - Fixed an issue where Editor only types were being added to the build. - -## [1.1.3-preview] - 2019-06-17 - - *BREAKING CODE CHANGES* - - ReleaseInstance will now return a bool saying if it successfully destroyed the instance. If an instance is passed in that Addressables is unaware of, this will return false (as of 0.8 and earlier, it would print a log, and still destroy the instance). It will no longer destroy unknown instances. - - Added PrimaryKey to the IResourceLocation. By default, the PrimaryKey will be the address. This allows you to use LoadResourceLocationsAsync and then map the results back to an address. - - Added ResourceType to IResourceLocation. - - This allows you to know the type of a location before loading it. - - Fixes a problem where calling Load*(key) would load all items that matched the key, then filter based on type. Now it will do the filter before loading (after looking up location matches) - - This also adds a Type input to LoadResourceLocationsAsync. null input will match all types. - - Safety check AssetReference.Asset to return null if nothing loaded. - - New rule added to Analyze window - CheckResourcesDupeDependencies - to check for dependencies between addressables and items in Resources - - Added group rearranging support to the Addressables window. - - Improved logging when doing a Prepare for Content Update. - - Added versions of DownloadDependencies to take a list of IResourceLocations or a list of keys with a MergeMode. - - Fixed scenario where Task completion wouldn't happen if operation was already in a certain state - - Made LoadResourceLocations no longer throw an exception if given unknown keys. This method is the best way to check if an address exists. - - Exposed AnalyzeRule class to support creating custom rules for Addressables analysis. - - Fixed some issues surrounding loading scenes in build scenes list via Addressables - - Removed using alias directives defined in global space. - - Proper disposal of DiagnosticEventCollector and DelayedActionManager when application closes. - - Added support for loading named sub-objects via an "address.name" pattern. So a sprite named "trees" with sub-sprites, could be loaded via LoadAssetAsync("trees.trees_0"). - - Known issue: loading IList from a Texture2D or IList from an fbx will crash the player. The workaround for now is to load items by name as mentioned just above. Engine fix for this is on its way in. - -## [0.8.6-preview] - 2019-05-14 - - Fix to make UnloadSceneAsync(SceneInstance) actually unload the scene. - -## [0.8.3-preview] - 2019-05-08 - - *BREAKING CODE CHANGES* - - Chagned all asynchronous methods to include the word Async in method name. This fits better with Unity's history and convention. They should auto upgrade without actually breaking your game. - - Moved AsyncOperationHandle inside namespace UnityEngine.ResourceManagement - - Addressable Analyze changes: - - Analyze has been moved into it's own window. - - CheckSceneDupeDependencies Analyze rule has been added. - - CheckDupeDependencies has been renamed into CheckBundleDupeDependencies. - - Analyze Rule operations for individuals or specific sets of Analyze Rules has been added via AnalyzeRule selections. - -## [0.7.4-preview] - 2019-04-19 - - Removed support for .NET 3.x as it is deprecated for Unity in general. - - Replaced IAsyncOperation with AsyncOperationHandle. - - Once the asset is no longer needed, the user can call Addressables.Release, passing in either the handle, or the result the handle provided. - - Exposed AsyncOperationBase for creating custom operations - - These operations must be started by ResourceManager.StartOperation - - Replaced IDataBuilderContext and it's inherited classes with simpler AddressablesDataBuilderInput. This class is fed into all IDataBuilder.BuildData calls. - - Fixed Nintendo Switch and PlayStation4 support. - - Simplified the IResourceProvider interface. - - Refactored build script interface. Made BuildScriptBase and the provided concrete versions easier to inherit from. - - Removed DelayedActionManager. - - Removed ISceneProvider. Users can implement custom scene loading using a custom AsyncOperationBase. - - Removed optional LRU caching of Assets and Bundles. - - Addressables Profiler now tracks all active async operations - - AssetBundles targetting StreamingAssets (by using the profile variable [UnityEngine.AddressableAssets.Addressables.BuildPath] now build to the Library instead of StreamingAssets. During the player build, these files are copied into StreamingAssets, then after the build, the copies are deleted. They are also built into platform specific folders (so building for a second platform will not overwrite data from a first build). We recommend deleting anything in Assets/StreamingAssets/aa. - - The addressables_content_state.bin is built into a platform specific folder within Assets/AddressableAssetsData/. We recommend deleting the addressables_content_state.bin in Assets/AddressableAssetsData to avoid future confusion. - - ScriptableBuildPipeline now purges stale data from its cache in the background after each build. - - Disabled Addressables automatic initialization. It will now initialize itself upon the first call into it (such as Load or Instantiate). To Initialize on startup instead of first use, call Addressables.Initialize(). - - Optimized performance around instantiation and general garbage generation. - - Added per-group bundle compression settings. - - Fixes to AssetReference drawers. - - Improved the group template system for creating better defined asset groups. - - Fixed bug in bundle caching that caused GetDownloadSize to report incorrectly - - Cleaned up Load/Release calls to make sure all releases could take either the handle returned by Load, or the handle.Result. - - Added editor-only analytics (nothing added in runtime). If you have Analytics disabled in your project nothing will be reported. Currently only run when you build addressables, it includes data such as Addressables version and Build Script name. - - Fixed null ref issue when cleaning all the data builders - - KNOWN ISSUE: there is still an occasional issue with code stripping on iOS. If you run into iOS issues, try turning stripping off for now. - -## [0.6.8-preview] - 2019-03-25 -- fixed Build For Content Update to no longer delete everything it built. - -## [0.6.7-preview] - 2019-03-07 - - Fix for iOS and Android. Symptom was NullReferenceException dring startup resulting in nothing working. Fix requires re-running Build Player Content - -## [0.6.6-preview] - 2019-03-05 - - *BREAKING CODE CHANGES* - - to ease code navigation, we have added several layers of namespace to the code. - - All Instantiate API calls (Addressables and AssetReference) have been changed to only work with GameObjects. - - any hardcoded profile path to com.unity.addressables (specifically LocalLoadPath, RemoteLoadPath, etc) should use UnityEngine.AddressableAssets.Addressables.RuntimePath instead. - For build paths, replace Assets/StreamingAssets/com.unity.addressables/[BuildTarget] with [UnityEngine.AddressableAssets.Addressables.BuildPath]/[BuildTarget] - For load paths, replace Assets/StreamingAssets/com.unity.addressables/[BuildTarget] with {UnityEngine.AddressableAssets.Addressables.RuntimePath}/[BuildTarget] - - We have removed attribute AssetReferenceTypeRestriction as it is cleaner to enforce type via generics - - Attribute AssetReferenceLabelRestriction is renamed to AssetReferenceUILabelRestriction and must be surrounded by #if UNITY_EDITOR in your game code, to enforce it's editor-only capability - - Modifications to IResourceProvider API. - - Removed PreloadDependencies API. Instead use DownloadDependencies - - Content Update calculation has changed, this will invalide previously generated addressables_content_state.bin files. - - Some types for content update were made private as a result of the above change. - - Minimum Unity version is now 2018.3 to address a build-time bug with progressive lightmapper. - - Moved all of the Resource Manager package to be contained within Addressables (no longer a stand alone package). No code change implications. - - Change to content catalog building: - - Previous model built one catalog per group, wherever that group built it's data. - - New model builds one catalog locally, and optionally one "remote". Remote location is set on the top level AddressableAssetSettings object. - - Loading will now always check if remote has changes (if remote exists), and use local otherwise (or cached version of remote). - - LoadScene API now takes the LoadSceneParameters that were added to the engine in 2018.2 - - Exposed AddressablesBuildDataBuilderContext.BuildScriptContextConstants for use in build scripts. - - Refactored AddressablesBuildDataBuilderContext.GetValue to take default parameter. - - Fixed Scene asset path to be consistent between different play modes in the catalog data. - - Exposed the various IDataBuilder implementations as public classes. - - Exposed asset and bundle provider types for BundledAssetGroupSchema. - - Fixed several bugs when loading catalogs from other projects. - - Added provider suffix to Initialization operation and Addressables.LoadCatalogsFromRuntimeData API to better support overriding providers. - - Exposed CachedProvider options in BundledAssetGroupSchema. Each unique set of parameters will generate a separate provider. There is also an option to force a group to have its own providers. - - Added IEnumerable Keys property to IResourceLocator interface. - - Exposed InitializationOperation as public API. - - Added BuildTarget to ResourceManagerRuntimeData. This is used to check if the generated player content was built with the same build target as the player or the editor when entering play mode. - - Removed warnings generated from not finding the cached catalog hash files, which is not an error. - - Fixed bug where scenes were not unloading. - - Fixed GUI exception thrown in group inspector. - - Fixed error case where an asset (usually a bundle) was loaded multiple times as different types (object and AssetBundle). - - Fixed divide by zero bug when computing load percent of simulated asset bundles. - - AddressableAssetBuildResult.CreateResult now takes the settingsPath as a parameter to pass this to the result. - - Fix AssetReference GUI when the AssetReference is inside an array of classes, part of a SerializedObject, or private. - - Fix AssetReferenceSprite to properly support sprites (as opposed to Texture2D's). - - Fixed bug involving scenes being repeatedly added to the build scenes list. - - Removed deprecated and obsolete code. If you are upgrading from a very old version of Addressables, please update to 0.5.3-preview first. - - Removed the default MergeMode on LoadAssets calls to enforce explicit behavior. - - Added IAsyncOperation GetDownloadSize(object key) API to compute remaining data needed to load an asset - - Fixed assets being stuck in a read-only state in UI - - Unified asset moving API to clean up public interface - - Added PlayerVersion override to AddressableAssetSettings - - Ensure UI cannot show invalide assets (such as .cs files) - - Renamed Addressables.LoadAddtionalCatalogs to Addressables.LoadContentCatalog and now it takes the path of the catalog instead of the settings file - - Moved provider information from ResourceManagerRuntimeDate into ContentCatalogData - - Updating ResourceManager to be a non-static class - - Fixed bugs surrounding assets moving in or out of Resources (outside Addressables UI) - - Fixed the AssetReference dropdown to properly filter valid assets (no Resources and honoring type or label limitations). - - Fixed AssetReferences to handle assets inside folders marked as Addressable. - - Added attribute AssetReferenceUIRestriction to support user-created AssetReference restrictions (they are only enforced in UI, for dropdown and drag&drop) - - Changed addressables_content_state.bin to only build to the folder containing the AddressableAssetSettings object (Assets/AddressableAssetsData/ in most cases) - - Fixed issue where the wrong scene would sometimes be open post-build. - -## [0.5.3-preview] - 2018-12-19 - - fixed upgrade bug from 0.4.x or lower to 0.5.x or higher. During upgrade, the "Packed Mode" option was removed from play mode. Now it's back and upgrades are safe from 0.4.x or from 0.5.x to 0.5.3 - -## [0.5.2-preview] - 2018-12-14 - - *IMPORTANT CHANGE TO BUILDING* - - We have disabled automatic asset bundle building. That used to happen when you built the player, or entered play mode in "packed mode". This is no longer the case. You must now select "Build->Build Player Content" from the Addressables window, or call AddressableAssetSettings.BuildPlayerContent(). We did this because we determined that automatic building did not scale well at all for large projects. - - fixed regression loading local bundles - - Added Addressables.DownloadDependencies() interface - - fixes for Nintendo Switch support - - Fixed issues around referencing Addressables during an Awake() call - - Code refactor and naming convention fixes - - Cleaned up missing docs - - Content update now handles not having and groups marked as Static Content - - Fixed errors when browing for the addressables_content_state.bin and cancelling - - Moved addressables_content_state.bin to be generated into the addressables settings folder - - Changed some exceptions when releasing null bundles to warnings to handle the case of releasing a failed download operation - - Separated hash and crc options to allow them to be used independently in asset bundle loads. - - Use CRC in AssetBundle.LoadFromFileAsync calls if specified - - Always include AssetBundleRequestOptions for asset bundle locations - -## [0.4.8-preview] - 2018-10-22 - - Added all referenced types in asset bundles to link.xml to prevent them from being stripped in IL2CPP builds - -## [0.4.7-preview] - 2018-10-20 - - updated Scriptable Build Pipeline version in dependencies - -## [0.4.6-preview] - 2018-10-16 - - MINIMUM RECOMMENDED VERSION - 2018.2.11+ - - We have re-enabled the addressables checkbox. Versions of 2018.2 older than the .11 release will work unless you attempt to view the Animation Import Settings inspector. If you do have animations you need to inspect, use .11+. If you do not, use any official release version of 2018.2. - - refactored the way IResourceProviders are initialized in the player - serialized data is constructed at runtime to control how the providers are configured - - added readonly custom inspector for AddressableAssetEntryCollection - - AssetReference now stores the loaded asset which can be accessed via the Asset property after LoadAsset completes. ReleaseAsset has been modified to not need the asset passed in (the old version is marked obsolete] - - fixed profiler details view not updating when a mouse drag is completed - - fixed null-ref when moving Resources to Addressables when there are no Resources - - blocked moving EditorSceneList within GUI - - fixed cap on address name length - - fixed workflows of marking Resources as addressable and moving an addressable into Resources. - - fixed issue where AssetReferenceDrawer did not mark scene as dirty when changed. - - added Hosting Services feature; provides extensible framework and implementation for serving packed content to player builds from the Editor - - replaced addressables buildscript with an interface based system. IDataBuilder class is now used to define builders of specific types of data. The Addressables settings object - contains a collection of data builders and uses these to create player and play mode data. Users can implemented custom data builders to control the build process. - - replaced AssetGroupProcessors with a collection of AssetGroupSchema objects. The difference is that the schema objects only contain data and groups can have multiple schemas. The - logic for processing groups now resides in the build script and uses the schemas as data sources and filters for how to build. - - Added Initialization objects that can be created during the build to run during addressables initialization - - Implemented Caching API initialization with initialization objects - - Changed some API and tests to work with 2019.x - - fixed how AssetReference's draw when within lists, arrays, or contained classes - - Fixed the workflow of scenes moving in and out of the Editor Build Settings Scene list. - - Removed "Preview" and added "Analyze". - - The new system runs any rules it knows about. - - Currently this is one rule that is manually set up in code. Future work will have additional rules, and expose the ability to create/add user- or project-specific rules - - This process can be slow, as it runs most of a build to get accurate data. - - Within the Analyze window there is a "fix" button that allows each rule to fix any issues if the rule knows how. - - The current rule is a "check duplicate asset" rule. This looks for assets that are pulled into multiple asset bundles due to dependency calculations. The way it fixes things is to move all of those into a newly created group. - - Added option to toggle logging of all exceptions within the Resource Manager - - Refactored initialization of the addressable asset settings to prevent it getting into a bad state. - -## [0.3.5-preview] - 2018-09-05 - - implemented content update workflow. Added a dropdown to the "Build" button on main window's toolbar. - - "Build/Prepare for Content Update" will detect assets in locked bundles (bundles flagged as static, by default all local bundles). - - "Build/Build for Content Update" will build assets with a catalog that is compatible with a previously released player. - - "Build/Build Packed Data" will build in the same way entering play mode in PackedMode would. - - implemented Clean Build. "Build/Clean/*" will clear out build caches. - - cleaned up streaming assets folder better after build - - moved asset group data into separate assets in order to better support version control - - fixed bug when canceling export of entries to an AssetEntryCollection - - fixed several bugs related to caching packed bundles in play mode - - added option to build settings to control whether streaming assets is cleared after each build - - enabled CreateBuiltInShadersBundle task in build and preview - - fixed bug in AA initialization that was cuasing tests to fail when AA is not being used. - - fixed bug where toggling "send profiler events" would have no effect in some situations - - default the first 2 converted groups to have StaticContent set to true - - UI Redesign - - Moved most data settings onto actual assets. AddressableAssetSettings and AddressableAssetGroup assets. - - AddressableAssetSettings asset has "Send Profile Events", list of groups, labels, and profiles - - AddressableAssetGroup assets have all data associated with that group (such as BuildPath) - - Made "preview" be a sub-section within the Addressables window. - - The "Default" group can now be set with a right-click in the Addressables window. - - Set play mode from "Mode" dropdown on main window's toolbar. - - Moved "Hierarchical Search" option onto magnifying glass of search bar. Removed now empty settings cog button. - - fixed issue when packing groups into seperate bundles generated duplicate asset bundle names, leading to an error being thrown during build - - added support for disabling the automatic initialization of the addressables system at runtime via a script define: ADDRESSABLES_DISABLE_AUTO_INITIALIZATION - - added API to create AssetReference from AddressableAssetSettings object in order to create an entry if it does not exist. - - moving resource profiler from the ResourceManager package to the Addressables package - - fixed bug where UnloadScene operation never entered Done state or called callback. - - fixed loading of additonal catalogs. The API has changed to Addressables.LoadCatalogsFromRuntimeData. - - fixed bug in InitializationOperation where content catalogs were not found. - - changed content update workflow to browse for cachedata.bin file instead of folder - - fixed exception thrown when creating a group and using .NET 4.x - - fixed bugs surrounding a project without addressables data. - - AssetLabelReference inspector rendering - - AssetReference drag and drop - - fixed profiler details view not updating when a mouse drag is completed - - fixes surrounding the stability of interacting with the "default" group. - - Added docs for the Content Update flow. - - Adjusted UI slightly so single-clicking groups shows their inspector. - - removed not-helpful "Build/Build Packed Data" item from menu. - - fixed bug where you could no longer create groups, and group assets were not named correctly - -## [0.2.2-preview] - 2018-08-08 - - disabled asset inspector gui for addressables checkbox due to editor bug - -## [0.2.1-preview] - 2018-07-26 - - smoothed transition from 0.1.x data to 0.2.x data - - added checks for adding duplicate scenes into the EditorBuildSettings.scenes list - - fixed exception when deleting group via delete key, added confirmation to all deletions - -## [0.2.0-preview] - 2018-07-23 - - Fixed bundles being built with default compression instead of compression from settings - - Fixed bug in tracking loaded assets resulting in not being able to release them properly - - Added Key property to IAsyncOperation to allow for retrieval of key that requested the operation - - Added AssetLabelReference to provide inspector UI for selecting the string name of a label - - Fixed dragging from Resources to a group. - - Added ability to re-initialize Addressables with multiple runtime data paths. This is to support split projects. - - Clean up StreamingAssets folder after build/play mode - -## [0.1.2-preview] - 2018-06-11 - - fixed Application.streamingAssetsPath being stripped in IL2CPP platforms - -## [0.1.1-preview] - 2018-06-07 - - MIN VERSION NOW 2018.2.0b6 - - updated dependency - -## [0.1.0-preview] - 2018-06-05 - - MIN VERSION NOW 2018.2.0b6 - - added better checks for detecting modified assets in order to invalidate cache - - fixed preview window showing scenes in wrong bundle - - exclude current processor type from conversion context menu - - fixed exception when right clicking asset groups - - added support for adding extra data to resource locations - - made Addressables.ReleaseInstance destroy even non-addressable assets. - - append hash to all bundle names - - pass crc & hash to bundle provider - - clear catalog cache whenever packed mode content is rebuilt - -## [0.0.27-preview] - 2018-05-31 - - fixed ResourceManager initialization to work as the stand-alone player - -## [0.0.26-preview] - 2018-05-24 - - re-added Instantiate(AssetReference) for the sake of backwards compatability. - -## [0.0.25-preview] - 2018-05-23 - - workaround for engine bug surrounding shader build. Fix to engine is on it's way in. - -## [0.0.24-preview] - 2018-05-21 - - minor bug fix - -## [0.0.23-preview] - 2018-05-21 - - new format for content catalogs - - detects changes in project and invalidates cached runtime data and catalogs - - data is not copied into StreamingAssets folder when running fast or virtual mode - - added external AssetEntry collections for use by packages - - modifying large number of asset entries on the UI is no longer unresponsive - - added an option to search the asset list in a hierarchical fashion. Helps track down which group an asset is in. - - many small bug fixes. - -## [0.0.22-preview] - 2018-05-03 - - dependency update. - -## [0.0.21-preview] - 2018-05-03 - - fixed build-time object deletion bug. - -## [0.0.20-preview] - 2018-05-02 - - Added support for extracting Built-In Shaders to a common bundle - - Added build task for generating extra data for sprite loading edge case - - fix build related bugs introduced in 0.0.19. - -## [0.0.19-preview] - 2018-05-01 - - Complete UI rework. - - Moved all functionality to one tab - - Preview is a toggle to view in-line. - - Profiles are edied from second window (this part is somewhat placeholder pending a better setup) - - Dependency updates - - Minor cleanup to build scripts - -## [0.0.18-preview] - 2018-04-13 - - minor bug fixes - - exposed memory cache parameters to build settings, changed defaults to use LRU and timed releases to make preloading dependencies more effective - -## [0.0.17-preview] - 2018-04-13 - - added tests - - fixed bugs - - major API rewrite - - all API that deals with addresses or keys have been moved to Addressables - - LoadDependencies APIs moved to Addressables - - Async suffix removed from all Load APIs - -## [0.0.16-preview] - 2018-04-04 -- added BuildResult and callback for BuildScript -- added validation of instance to scene and scene to instance maps to help debug instances that change scenes and have not been updated -- added ResourceManager.RecordInstanceSceneChange() method to allow RM to track when an instance is moved to another scene -- moved variable expansion of location data to startup - -## [0.0.15-preview] - 2018-03-28 -- fixed scene unloading -- release all instances when a scene unloads that contains unreleased instances -- fixed overflow error in virtual mode load speeds - -## [0.0.14-preview] - 2018-03-20 -- Updated dependencies - - -## [0.0.12-preview] - 2018-03-20 -- Minor UI updates -- doc updates -- fixed bug involving caching of "all assets" -- improved error checking & logging -- minor bug fixes. - -## [0.0.8-preview] - 2018-02-08 -- Initial submission for package distribution - - +# Changelog +All notable changes to this package will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [1.21.20] - 2024-02-08 +- Fixed an issue where scene InternalId collisions were very likely when using dynamic internal asset naming +- Fixed catalogs to use back slashes rather than forward slashes for android builds. +- Fixed an issue where "Failed to remove scene from Addressables profiler" warning occurs when a scene is unloaded. +- Prevent a KeyNotFoundException from being logged to the console. +- Fix error message to report not found when loading non-Addressable asset by guid +- Fixed issue where a NullReferenceException occurs when using WaitForCompletion and the max number of concurrent requests is set to 1. +- Fixed issue where there is missing asset data in the Addressables Profiler for binary catalogs. +- Added note about the limitations of the Check for Content Update Restrictions tool. +- Add migration upgrade prompt for legacy path pairs (ex. RemoteLoadPath) +- Fixed an issue where a broken script on any Addressable Asset would make it impossible to select Addressable Assets in the AssetReference inspector +- Add logging of catalog and asset bundle http operations. +- Add UI to trigger CCD management API http call logging (requires newer CCD package) +- CCD Automatic Profiles can now be one per-profile, rather than one per AddressableSettings instance +- CCD Manager is built when using the Build to CCD and the standard Build content menu +- Add support for CCD Management SDK 3.0 + +## [1.21.19] - 2023-10-17 +- Fixed an issue where scene InternalId collisions were very likely when using dynamic internal asset naming +- Fixed catalogs to use back slashes rather than forward slashes for android builds. +- Fixed an issue where "Failed to remove scene from Addressables profiler" warning occurs when a scene is unloaded. + +## [1.21.18] - 2023-09-23 +- Fixed an issue where scene InternalId collisions were very likely when using dynamic internal asset naming +- Fixed an issue where Android paths were being delimited with '\' rather than '/' + +## [1.21.17] - 2023-08-16 +- Fixed issue where sprite is missing normal texture when using "Use Existing Build" build mode +- Fixed a bug where a GUI style was misspelled in the Editor and was recently fixed +- Fixed an issue where asset loading would occasionally stop working if domain reload was disabled +- Fixed an issue where Android paths were being delimited with '\' rather than '/' + +## [1.21.15] - 2023-08-03 +- Fixed an issue where using binary catalogs causes a crash on Android with ARM7. +- DownloadDepedenciesAsync no longer loads asset bundles into memory +- Fixed an exception getting thrown in the Addressables Report when drilling into a bundle chain + +## [1.21.14] - 2023-06-14 +- Fixed an issue where CleanBundleCache was giving an invalid handle error when Send Profiler Events was turned on +- Fixed issue where provider data wasn't set for catalog downloads, so web request timeouts would default to 0 instead of the given value +- Added the ability to manage Addressables labels from the asset inspector +- Fixed an issue where the Addressables build cache would get cleared even if you pressed no in the popup window. +- Optimised gc allocations with Addressables profiling module data transfer. +- Fixed issue with binary catalog and asset bundle download redirect limit causing an error when set to -1 (default) +- Fixed issue where player preferences for logging runtime exceptions weren't being compiled out using the Editor scripting define +- Fixed an issue where in some cases sprites would not load properly when using a binary catalog + +## [1.21.12] - 2023-05-04 +- Fixed issue with a potential race conditon when calling GetAssetBundle to load local files using WaitForCompletion +- Fixed compiler error when using the profiler module on a noncaching platform. +- Fixed issue where stack overflow occurs for http requests on Unity 2022.1+ when insecure requests are disallowed. +- Added groups field to Inspector and move assets popup. +- Fixed issue where sprite atlas cannot be assigned to an AssetReferenceAtlasedSprite. + +## [1.21.10] - 2023-04-10 +- Fixed Addressables profiler not correctly displaying loaded Asset subObjects where a Asset was loaded due to a direct reference to one of its subObjects. +- Fixed an issue where bundles built with the Append Hash to FIlename bundle naming option had strange interactions with the Prevent Updates option +- Improved performance of BuildLayoutGenerationTask + +## [1.21.9] - 2023-03-07 +- Removed code within WriteObjectToByteList that would never be reached +- Fixed an issue where SceneOps would have update called on them twice per frame +- Fixed an issue where in some circumstances an Operation would continue to have update called on it even after it finished. +- Fixed an issue with Labels window after a domain reload causing a null reference exception. +- Added Remove all unused labels option to labels popup window. +- Fixed issue when not including the address and guid in catalog using content update workflow, would always indicate the asset as changed +- Fixed Addressables profiler module help links to documentation. +- Fixed issue where scenes unloaded due to another scene loading in single mode, would result in the profiler module still reporting the scene as loaded. +- Groups window will now show labels of entries that are not a part of the settings. +- Fixed 404s when uploading files with incorrect environment ID +- Fixed issue where BuildLayoutGenerationTask would sometimes fail in large projects + +## [1.21.8] - 2023-02-09 +- Optimised PostProcessBundles +- Fixed issue where having a runtime profile variable or property to evaluate web urls on Windows platforms can result in malformed urls. +- Fixed possible `NullRefernceException` when importing new assets and `AddressableAssetUtility+SortedDelegate,Register` was called. +- Fixed an issue where EditorGUI.changed would not be properly set in certain circumstances when updating AssetReferences using the inspector +- Fixed CCD build and release to properly upload static groups +- Fixed CCD build and release to allow both static and managed groups in the same profile +- Include additional object dependency information in build layout report +- Addressables Profiler module compatible with Unity Editor 2022.2+ +- Addressables Build Report window added. Compatible with Unity Editor 2022.2+ + +## [1.21.2] - 2022-12-09 +- Fixed issue where folders in Groups window would display the subObjects of assets without expanding the assets. +- Added the ability to copy a subAsset address to clipboard from right click. +- Fixed bundle naming mode option names being unclear when selecting multiple groups. +- Optimised string usage across package +- Updated the way that the Build Layout calculates efficiency to base it off of the dependent file sizes instead of the dependent file count +- Fixed issue where Addressables inspector would not show until Addressables settings have been initialised +- Fixed issue where editor only assets would be marked as changed in the Check for Content Update restrictions window + +## [1.21.1] - 2022-10-05 +- Fixed issue where CcdManagedData State was not being set correctly +- Added IP ping timeout to the Hosting Services window. +- Fixed issue where loading cached bundles using WaitForCompletion in 2021.2+ results in an error. +- Fixed issue when loading urls with unconverted special url characters such as a space. +- Fixed issue where folders in Groups window would display the subObjects of assets without expanding the assets. +- Added public API to support more detailed Build Layout + +## [1.20.5] - 2022-08-03 +- Fixed issue where object picker for the AssetReferenceDrawer would cut off longer asset names due to only being as wide as the property drawer. +- Improved performance of gathering assets for an AssetReference. +- Fixed issue where settings hash was not included in settings.json for runtime settings. +- Fixed issue where CheckBundleDupeDependencies() would cause a null reference when no addressable assets are in a project. +- Fixed issue where WebRequestQueue would throw a NullReferenceException when given an aborted web request as a parameter. +- Fixed issue where renaming a label does not dirty and save settings and serialise to file. +- Fixed an issue where an updating catalogs operation would return a 'Succeeded' status even if its load operation failed. +- Fixed issue where hosting service roots would not change to correct platform when switching platforms in editor. +- Fixed issue where ProfileDataSourceSettings was generating wrong LoadPath url for CCD integration +- Fixed issue where ClearDependencyCacheAsync could try and clear a bundle that is actively loading. +- Fixed issue where web request is not disposed when downloading a file using TextDataProvider +- Fixed issue where DisableAssetImportOnBuild sample does not disable asset imports +- Fixed issue where retrying a download after a CRC mismatch would not occur. + +## [1.20.3] - 2022-06-14 +- Added documentation to several areas (Build, Settings, Profiles, Catalogs, Runtime loading). +- Fixed issue where GatherAllAssets filter would still return subObjects of filtered Assets. +- Fixed issue where content update entries dependent on modified entries and not found as modified by check for content update restrictions +- Fixed issue where the notification for changed static content wasn't getting cleared for assets inside of folders. +- Fixed issue where Sprites belonging to a Sprite Atlas aren't assignable to an AssetReferenceSprite field. +- Fixed issue where RefreshGlobalProfileVariables is called during script compilation. +- Fixed issue where UnauthorizedAccessException occurs when lacking permissions to cache a remote catalog. +- Fixed stack overflow with SortedDelegate and Addressables OnPostProcessAllAssets occurred during invoke a queued invoke and registering a new delegate. +- Fixed issue where SceneLoadParameters were not used when using LoadSceneAsync using SceneLoadParameters. +- Fixed issue where Schema gui with List members would not save when editing in the Group inspector. +- Fixed issue where Serializable types of structs and class members of MonoBehaviour or ScriptableObjects would be returned as a location with GetResourceLocations but would not be loadable. +- Fixed issue where setting default group does not dirty settings. Causing a reload to reset to previous default group. +- Added updated documentation for the 1.20 Content Update workflows +- Fixed issue where AssetReference subasset popup text is always white regardless of Editor skin. +- Fixed issue where newly created assets would not show the Addressables inspector until after a domain reload. +- Optimised Build pass Post Process Bundles when running on a large number of asset dependency trees. +- A warning now gets printed if caching data fails due to Application.persistentDataPath being an empty string +- Fixed issue where pressing the Reset button on the Hosting window would not assign a new random available port number. +- Fixed bug where WaitForCompletion could hang indefinitely under certain race conditions (primarily on Android) +- Fixed a bug where calling WaitForCompletion on a LoadAssetAsync call that was loading from Resources would freeze the editor. + +## [1.20.0] - 2022-04-20 +- Added ability to get the download size of a given Content Catalog by its resource location +- Add option to save the bundle build layout report as a json or txt file in the Preferences window. +- Added sample for resolving duplicate dependencies to multiple groups. +- AddressableAssetProfileSettings.GetProfileDataById and AddressableAssetProfileSettings.GetProfileDataByName public +- Added ability to load scenes using SceneLoadParameters through Addressables API. +- Made the following API public: + - AsyncOperationHandle.IsWaitingForCompletion + - AssetBundleResource.LoadType + - AssetBundleResource.GetLoadInfo() + - AssetBundleResource.GetAssetPreloadRequest() + - AssetBundleResource.Start() + - AssetBundleResource.Unload() + - WebRequestQueueOperation.Result + - WebRequestQueueOperation.OnComplete + - WebRequestQueueOperation.IsDone + - WebRequestQueueOperation.WebRequest + - WebRequestQueueOperation.ctor() + - WebRequestQueue.SetMaxConcurrentWebRequests() + - WebRequestQueue.QueueRequest() + - WebRequestQueue.WaitForRequestToBeActive() + - ResourceManagerConfig.ExtractKeyAndSubKey() + - UnityWebRequestUtilities.RequestHasErrors() + - UnityWebRequestUtilities.IsAssetBundleDownloaded() + - UnityWebRequestResult.Error.set + - UnityWebRequestResult.ShouldRetryDownloadError +- Made the following API protected: + - AssetBundleProvider.UnloadingBundles.get + - AsyncOperationBase.ReferenceCount + - AsyncOperationBase.IncrementReferenceCount + - AsyncOperationBase.DecrementReferenceCount +- Added functionality to extend groups window build menu with pre and post build methods +- Fixed issue where custom analyze rules that are subclasses cannot be registered. +- Added more tooltips to UI +- Fixed issue where loading assets using a Location without initialising first would not initialise Addressables. +- Content Update workflow has been changed to be more streamlined. New settings have been added to handle Content Update and the previous state .bin file can now be automatically loaded instead of requiring manual selection. +- Set default max concurrent Web requests value to 3. +- Pre-cache delegate list for Completed and CompletedTypeless to reduce GC allocation. +- Fixed issue where Scenes can be incorrectly reported as being in multiple bundles with Bundle Layout Preview analyze rule +- Fixed bug where requests for a ResourceLocation that pointed to a scene in an Addressable folder wasn't returning the location +- Fixed issue where content update could fail to update built-in shaders and monoscript bundles to load from the correct location. +- Cache results of FindEntry to improve performance when no changes are made. +- Fixed an issue where the AddressableAssetEntry returned by GetFolderSubEntry would not include the labels of the entry +- Fixed issue where inherited fast mode scripts would fail to use instance and scene providers set for that build script object. +- Fixed issue where multiple AssetReferences could not be dragged and dropped to a list or array. +- Improved performance when deleting Addressable Asset Groups. + +## [1.19.19] - 2022-03-01 +- Improved message of InvalidKeyException errors. +- Improved exception message of RemoteProviderExceptions +- Fixed issue where Clear Cache Behavior setting was getting reverted when changed while multi-selecting schemas +- Fixed an issue where when building with Missing References in the groups window a NullRefException would occur +- Added documentation explaining why the user might hit a deadlock when calling WaitForCompletion when loading multiple scenes in succession +- Fixed issue where DownloadDependenciesAsync with merge mode did not unload AssetBundles correctly +- Added ComponentReference and Custom Analyze Rule to Samples folder. +- Fixed issue where BundledAssetGroupSchema custom paths reset to default local paths after a domain reload. +- Added assemblyInfo to manage visible internals +- Fixed issue causing InvalidOperationException when loading Addressable Settings from OnPostProcessAllAsset during a project load without a cached AssetDatabase +- Fixed an issue where calling LoadSceneAsync.WaitForCompletion immediately after loading a scene singly would cause a freeze + +## [1.19.18] - 2022-01-31 +- Fixed issue where WaitForCompletion would take too long when used in virtual mode. +- Updated the documentation to include information on methods of waiting on asynchronous operations to complete. +- Fixed issue where IOException occurs when autoCleanBundleCache has value of 'true' in Addressables.UpdateCatalogs. +- Improved Addressables class Inspector headers with documentation links. +- Fixed issue in Editor where a large number of AssetReferences causes performance spikes +- Documentation has been added for shared bundles, HTTP restrictions in 2022 editor versions, Samples, and various cleanup +- Fixed issue with missing trace events in build profile trace log +- Fixed issue where adding a AddressablesGroupTemplate could not be added, throwing an Exception +- Added better logging when built in Editor Hosting Service fails to acquire a port +- Improved ordering of when OnPostprocessAllAssets occurs for Addressables settings and windows to ensure Addressable settings are processed first. +- Fixed issue where "Unable to load assets of type" error occurs when loading asset with classes referenced by value in "Use Asset Database" mode. +- Add more documentation about the "Non-Recursive Dependency Calculation" and "MonoScript Bundle Naming Prefix" options in AddressableAssetSettings. + +## [1.19.17] - 2022-01-06 +- New Projects use hierarchical search mode as the default option for Group search. +- Group referenced by Addressable Schema can now be viewed, but not edited, in the inspector +- Fixed issue where calling Addressables.CleanBundleCache freezes the WebGL player. +- Fixed API inconsistency in CheckForCatalogUpdates. The API wasn't initializing Addressables if it was the first point of contact in the system. +- Fix issue where opening the Analyze window logs null exceptions after running the "Check Duplicate Bundle Dependencies" rule. +- Add platform type to ""Use Existing Build"" display name in the Addressables Groups > Play Mode Script menu." +- Fixed issue where Scene loading after a content update could result in "RemoteProviderException : Invalid path in AssetBundleProvider: ''.". Fix require a new addressables_content_state.bin to be created." +- Tests for the addressables package are no longer included. These can still be accessed upon request. +- Fixed an issue where calling WaitForCompletion on LoadSceneAsync would sometimes cause a freeze +- Mentioned the AssetBundle loading cache in the docs +- Fixed issue where using WaitForCompletion and loading an AssetBundle through a UnityWebRequest freezes the editor when using 2021.2+. +- Fixed issue where using WaitForCompletion and exceeding the max number of concurrent web requests freezes the editor." +- Updated the docs to use the correct name for the Analyze rule "Bundle Layout Preview" +- Fixed issue where Addressable Asset Entry cached data is not cleared during external changes in some editor versions. + +## [1.19.15] - 2021-12-02 +- Fix issue where opening the Analyze window logs null exceptions after running the "Check Duplicate Bundle Dependencies" rule. + +## [1.19.13] - 2021-11-29 +- Removed AddressableAssetEntryCollection upgrade check on opening project. Improving startup performance. +- Fixed issue where GetAllAsset with includeSubObjects did not get subObjects within Assets in an Addressable folder. +- Improved Groups window label dropdown. Adding the ability to search labels and add new labels from the dropdown. +- Added ability Assets from Analyze window, using double click and right click options on the results. +- Improved performance when displaying Addressables header for selected Assets. +- Fixed issue where Groups not marked as "Include in build" was being including in analyse rules. +- Fixed issue where WaitForCompletion will complete Scene operations, where Scenes require further asynchronous loading to complete correctly. +- Fixed issue where AssetDatabaseProvider.LoadAssetAtPath causes a null exception if the asset is not in the AssetDatabase. +- Fixed issue where "Reentering the Update method is not allowed" exception occurs when calling WaitForCompletion during an async method. +- Added FAQ documentation for internal Bundle Id and Asset naming modes. +- Added documentation describing behaviour of WaitForCompletion of Scenes. +- Added documentation for how script changes affect builds. +- Added documentation about Windows file path limit affecting content builds +- Added note about Sprite Atlas options in the documentation. +- Added Sample for custom build and play mode scripts +- Fixed issue where Editor assets were getting included in a build for certain platforms due to path separator character mis-match +- Fix issue with using custom AssetBundleProvider with custom AssetBundleResource. +- Fixed issue where editor hosting profile variables were serialized to AddressableAssetSettings. + +## [1.19.11] - 2021-10-23 +- Fixed issue with missing reference exception when using addressables where content has not been built. +- Added warning that LZMA compression is not available for WebGL AssetBundles. +- Fixed issue were getting a Group Template fails where the project name or parent directory ended in "Assets". +- Fixed issue where option to build Addressables when building a Player where displayed for unsupported editor versions. +- Fixed issue where hosting services filters ip addresses when entering playmode and no services are in use +- Fixed "Editor Hosted" LoadPath, to work with active local Editor hosting service +- Fixed error where creating new groups would lead to errors if the default build and load path variables were not present in one's profile settings. +- Modified the behavior of AssetReference.editorAsset and AssetReference.SetEditorAsset to be more consistent and intuitive +- Fixed issue where upgrading from versions that didn't have ProfileGroupTypes was causing issues during builds. + +## [1.19.9] - 2021-09-30 +- Fixing a compile error on platforms where the Caching API is stripped. +- Updating ScriptableBuildPipeline dependency + +## [1.19.6] - 2021-09-24 +- Fixed issue where built-in shaders and MonoScript Bundles prefix option was not prefixed to Bundle filename. +- Restructured and updated documentation. +- Fixed an issue where graphs in the event viewer would sometimes scroll off the window +- Fixed issue where an AssetReference field cannot be interacted with the tab and enter keys. +- Fixed issue where an AssetReference label is displayed wrong where the AssetReferece is a child of the property being displayed. +- Added documentation for Addressables.CleanBundleCache +- Fixed issue where editing an open Prefab and saving the Prefab will deselect selected Objects. +- Improved performance of displaying Addressables Inspector in a very large Project. +- Fixed issue where buildlayout.txt would contain incorrect bundle names if a group's bundle naming scheme was set to filename +- Fixed an issue where some platforms were caching catalogs that don't support caching +- Fixed an issue where the popup windows for creating new profiles path variables would appear in seemingly random places. +- Fixed an issue where the popup window for creating a Build and Load path variable pair would not properly display its save button +- Added note in Hosting Services docs about modifying firewall settings when testing on other devices. +- Added handling of possible exceptions when caching catalog files. + +## [1.19.4] - 2021-08-24 +- Removing support for 2018.4 +- Added options for building Addressables content as a prebuild step when building Player. +- Optimised StreamingAssets usage to no longer need to be copied into the project (2021.2+). +- Fixed issue where OnDestroy use of Addressables API results in errors when Enter Play Mode Settings are enabled. +- Set AssetEntryCollection is Obsolete, includes auto update process to create Group entries from EntryCollections. +- Updated CheckForCatalogUpdates to properly report any failures that occur while its running. +- Combined BundledAssetGrupSchema CRC settings to a single value. +- BundledAssetGroupSchema Request Timeout will now use time in seconds since last time data wasa downloaded. +- Fixed issue where Exceptions in UnityWebRequest.Send were not caught. +- Updated the way that CompletedOperation events are handled in the Event Viewer to make it easier to associate a given CompletedOperation with its corresponding ChainOperation +- References to Time.deltaTime throughout Addressables are now replaced with Time.unscaledDeltaTime to better match whats described in the API +- Improved the performance of the ProcessAllGroups build step. +- Fixed a bug where having unmatched brackets in a profile's value could lead to a freeze. +- Fixed a bug where certain patterns of values in a profile variable would occasionally lead to an InvalidOperationException while building +- Added check to prevent infinite loop during WaitForCompletion during Asset Database Mode and Simulate Groups Mode +- Users can now supply a callback to receive the UnityWebRequest before being sent by web-based providers +- Added new API to clear the bundle cache for nonreferenced remote asset bundles. UpdateCatalogs has a new optional parameter called autoCleanBundleCache that when enabled will clear the bundle cache for nonreferenced remote asset bundles. +- New public APIs + - BundledAssetGroupSchema.AssetLoadMode + - AssetBundleProvider.AssetBundleRequestOptions.AssetLoadMode + - Addressables.WebRequestOverride + - ResourceManager.WebRequestOverride + - AddressableAssetSettings.DisableVisibleSubAssetRepresentations + - Exposed Auto release parameter added to InitializeAsync + - BundleRuleBase + - GenerateLocationListsTask.ProcessInput (formally RunInteral) + - BuildScriptPackedMode.PrepGroupBundlePacking + - UnloadSceneAsync APIs with exposed UnloadSceneOptions parameter + - Addressables.CleanBundleCache + - New parameter for Addressables.UpdateCatalogs to auto clean the bundle cache + - ProfileGroupType introduces a new workflow of grouping profile variables in the Addressables Profiles window, otherwise known as path pairs. + +## [1.18.15] - 2021-07-26 +- Improved Addressables inspector for Assets. +- Fixed issue where the hosting window would use an exceptionally high (8-20%) amount of CPU while open with a hosting service created +- Added update on profile change, changed to remove preceding slashes and change all to forward slash for hosting service +- Added documentation explaining why we are unable to support WaitForCompletion (sync Addressables) on WebGL + +## [1.18.13] - 2021-07-13 +- Fixed issue where Addressables would not use a custom Asset Bundle Provider if the default group was empty +- InvalidKeyExceptions are now correctly thrown as InvalidKeyExceptions, as opposed to before, where they were thrown as System.Exceptions. Please note that this may break any checks that rely on InvalidKeyExceptions being thrown as System.Exception +- Fixed issue where UnauthorizedAccessException is logged during a build if content_state.bin is locked by version control integration. +- Fixed issue where user defined callbacks can cause unexpected behavior for async operations that are automatically released. +- Fixed issue where Content Update would not include folder entry sub entries. +- Fixed issue where NullReferenceException was logged when multi-selecting with Resource in Groups TreeView. +- Fixed issue where Check for Content Update Restrictions excludes dependencies for folder entries. +- Fixed issue where AddPostCatalogUpdatesInternal would attempt to remove the hash from strings that did not include a hash, occassionally leading to incorrect bundle names in catalog.json +- Load AssetBundles Asynchronously from UnityWebRequest for supported Editor versions +- Fixed issue where hidden files were being flagged in GetDownloadSizeAsync when "Use Asset Database (fastest)" is enabled. +- Added logic for auto releasing completion handle in InitializeAsync +- Fixed issue where AssetBundleProvider would fail to retry on download dailed +- Fixed bug where Fast Mode wasn't returning the correct resource locations or their types, especially for sub-objects. +- Fixed bug where Hosting Service was not saving if enabled between domain reloads +- Fixed bug where Scenes with Group setting Asset Internal Naming Mode of Filename failed to load +- Fixed bug where Hosting window would occassionally be empty on startup. + +## [1.18.11] - 2021-06-15 +- Improved performance of Labels popup in Groups Window. +- Added "Copy Address to Clipboard" Context menu option in Groups Window. +- Added AssetLoadMode option to AddressableAssetsGroup, adds "Requested Asset And Dependencies" and "All Packed - Assets And Dependencies" load methods. +- (2021.2+) Improved performance of copying local buld path Groups built content when building a Player. +- Removed "Export Addressables" button from groups window because it was no longer in use. +- Fixed issue where loading remote catalog from .json fails when Compress Local Catalog is enabled. +- Fixed issue where loading remote catalog from bundle on WebGL fails when Compress Local Catalog is enabled. +- Added multi-project workflow documentation +- Made CacheInitializationData.ExpirationDelay obsolete +- Improve Hierarchical Search performance in Groups Window. +- Build now fails earlier if invalid or unsupported files are included. +- Fixed issue where renaming Group and Profiles would not cancel using Escape key. +- Fixed issue where StripUnityVersionFromBundleBuild and DisableVisibleSubAssetRepresentations were not being serialised to file. +- Updated content update docs to be a little more clear +- Made ExpirationDelay on the CacheInitializationObjects obsolete +- Reduced amount of main thread file I/O performed during AssetBundle loading + +## [1.18.9] - 2021-06-04 +- Added "Select" button for Addressable Asset in Inspector to select the Asset in the Addressables Groups Window. +- Reduced the number of file copies required during building Addressables and moving Addressables content during Player build. +- Fixed issue with AssetReferenceUIRestriction not working with Lists and Arrays. +- Optimised loading AssetBundles to avoid redundent existing file checks. +- Fixed issue with folder asset entries throwing null ref exceptions when doing a Check for Content Update Restriction +- Added documentation about how to implement custom operations with synchronous behavior +- Added option on AddressableAssetSettings to strip the Unity version from the AssetBundle hash during build. +- Added documentation about useful tools you can use when building Addressables content with a CI pipeline +- Added Import Groups tool to Samples folder. +- Updated documentation for setting up and importing addressable assets in packages." +- Fixed issue where multi-group drag and drop places groups in reverse order. +- Fixed issue where an asset entry is no longer selected in the Project window after it is modified on disk. +- Fixed simulated play mode when "Internal Asset Naming Mode" was set to something other than "Full Path" +- Fixed issues with WaitForCompletion getting stuck in infinite loop during failed operations +- Organised AddressableAssetSettings GUI into more distint setting types. +- Fixed issue where the wrong operation would sometimes be returned by the cache when a project contains over 10K addressable assets +- Added path pairs feature +- Fixed issue where AsyncOperationBase.HasExecuted isn't being reset when the operation is reused. +- Added check to ensure that ResourceManager.Update() is never called from within its own callstack. +- Added ability to rename labels from the label window. +- Added the DisableVisibleSubAssetRepresentations option in Settings. + +## [1.18.4] - 2021-05-06 +- EditorOnly tagged GameObjects in Scenes are no longer detected as duplicates for Scene Analyze results. +- Fixed issue when dragging multiple groups around within the groups window to set their display order. +- Reimplemented AsyncOperationBase.Task API to use TaskComppletionSource instead of creating a background thread. +- Fixed issue where remote .hash file was still being requested when Disable Content Catalog Update on Startup was enabled +- Fixed issue where AssetReference variable names weren't consistently formatted in the inspector +- Fixed bug where Completed callback was not called the same frame for some async operations when WaitForCompletion is used. +- Added Samples to the package. These can be added to the project through the Addressables page in Package Manager + +## [1.18.2] - 2021-04-20 +- Where available use synchronous load api's when AsyncOperationHandle.WaitForCompletion is called. +- Fixed issue where loading of Prefabs and ScriptableObjects in "Use Asset Database" and "Simulate Groups" play mode could cause changes to source Assets. Now those play modes will return instanced copies of the Assets. +- Added "Catalog Download Timeout" to AddressableAssetSettings, used for setting a timeout for .hash and .json catalog file downloads. +- Fixed issue where order of data in catalog.json can change. Order is now sorted to be deterministic. +- Added best practice documentation for define dependant compilation during build time. +- CompletedOperation are now returned to the op pool so they can be reused +- Made AddressableAssetSettings.ContentStateBuildPath public api access. +- Add option for building MonoScript bundle. This approach improves multi bundle dependencies to the same MonoScript. +- Added documentation for AddressableAssetSettings options. +- Improved error handling of failed unity web requests and some other operations. +- Users can now look into the InnerException property of an operation's exception for additional details" +- Fixed issue where .json and .asmdef files in the root of a package folder cannot be marked as Addressable. +- Fixed issue where unmodifiable assets cannot be marked as Addressable. +- Exposed more tools for making custom build scripts +- Exposed InvokeWaitForCompletion to be inheritable by custom operations +- Fixed issue where an url was improperly parsed by LoadContentCatalogAsync() if it contained query parameters +- Fixed issue where the post assigned to a hosting service was changing on domain reloads +- Add option for building asset bundles using "Non-Recursive Dependency calculation" methods. This approach helps reduce asset bundle rebuilds and runtime memory consumption. +- Add upload speed option to the http service settings. Downloads will be provided by the rate set in Kbp/s +- Add an option to force using UnityWebRequest even when AssetBundles are local +- Fixed issue with WebRequestQueue where web requests weren't getting queued correctly +- Fixed issue where looking for default group would spam null reference to GUI if Built In data group was deleted/null + +## [1.17.17] - 2021-04-06 +- Add AssetPostprocessor for AddressableSettings after AssetDatabase is Initialised, if not yet initialised on initial project launch. +- Removed serialisation of m_MainAsset and m_TargetAsset from Group entries. +- Fixed a warning "CacheInitialization.CacheInitOp.m_UpdateRequired'' is assigned but its value is never used" when building for platforms that don't have caching enabled +- A message is printed on successful Addressable build +- Properly save profile variables when switching profiles +- Fixed bug where multi-selected Addressable Groups weren't all getting set dirty on an edit. +- Fixed bug where Fast Mode wasn't respecting Log Runtime Exceptions setting +- Implicit assets are now taken into account when using applying a label restriction on an asset reference + +## [1.17.15] - 2021-03-23 +- Fixed FileNotFoundException when using bundle naming mode "Filename" with Unity Cloud Build. +- Fixed a bug where LoadAssetsAsync handle Completed callback is invoked before all individual Asset callbacks. +- Added in Asset validator on Editor startup. This ensures that assets deleted when the editor was closed are removed from Addressables. +- Fixed bug where the current amount of downloaded bytes was not properly updated + +## [1.17.13] - 2021-03-10 +- Fixed issue when loading a Sprite from a SpriteAtlas from an Addressable folder in AssetDatabase mode. +- Fixed bug in AssetReference "Make Addressable" functionality (when referencing an asset no longer addressable) +- Fixed bug with cyclic references in profile variable causing an infinite loop. +- Fixed bug where cached asset type could get stuck with DefaultType, an invalid Editor type +- Fixed issue where AsyncOperationHandle.Completed is called after AsyncOperationHandle.Task returns when the handle is already done. +- Fixed some faulty logic in GetDownloadStatus() when errors occur +- Removed extra dependencies that were being flagged as modified when running Check For Content Update Restrictions. +- Fixed a bug where the result of a Task could be inconsistent and return null given certain race conditions +- Fixed bug where UnloadSceneAsync decreased ref count more than once, and added unload scene to Release if ref count goes to zero +- Fixed issue where a popup appears when an AddressableAsset file is being modified even if the file is checked out locally. +- Fixed bug where fast mode wasn't showing events in the profiler +- Remove check for isUpdating and isCompiling so GetSettings(true) still tries to load the settings when compiling or updating +- Fixed issue where modified local static bundle dependencies fail to load after updating a previous build. Fix is compatible with older shipped content. + +## [1.17.6-preview] - 2021-02-23 +- Fixed issue where OnGlobalModification events would be EntryMoved when adding new Entries instead of EntryAdded. +- Fixed issue where a previously built player fails to load content after running Content Update with missing local bundles +- Fixed bug where ClearDependencyCacheAsync was throwing invalid handle exceptions if auto releasing the handle +- Fixed a bug when SerializeReference entries in link.xml for addressable was causing Unity linker to fail. +- Added results out parameter to AddressableAssetSettings.BuildPlayerContent. + +## [1.17.5-preview] - 2021-02-08 +- Fixed performance issue when disabling "Addressable" for multiple Assets in the Inspector. +- Added option to set the build path of addressables_content_state.bin file. +- The buildlogtep.json file is not generated when building the catalog bundle. +- Fixed invalid handle exception getting thrown when static AssetReferences were used with domain reload turned off +- Fixed catalog using invalid load path for Groups built with "bundle naming mode" "Filename". +- Added option to set custom prefix on the unitybuiltinshader AssetBundle +- Added documentation explaining how dependencies affect Content Update +- Sub-assets with arbitrary main type can now be assigned to an asset reference if types match + +## [1.17.4-preview] - 2021-01-27 +- Removed unnecessary logging when deleting temporary Addressables build data. +- Added WaitForCompletion() on AsyncOperationHandles. This allows async operation to be executed synchronously +- Alphanumeric sorting in the group window can be enabled through a setting in the editor preferences +- Change to set IgnoreFailures with LoadOptions.IgnoreFailures stored in the IResourceLocation.Data if not null +- Fixed issue when loading legacy Resources from Addressables using the guid when playmode is set to AssetDatabase. +- Fixed some compile warnings on 2020.2 +- Change to use full path for name of cached catalog. + +## [1.17.2-preview] - 2021-01-14 +- Add silent fail option to providers to get rid of error when cache not found as expected +- Hierarchy now fully displayed in search results when 'show groups as hierarchy' and 'hierarchical search' options are enabled +- OnValidate is now called when an AssetReference changes +- Fixed bugs in Use Asset Database play mode related to multiple folders with matching addresses +- Made the following APIs public: + - ResourceManager.CreateChainOperation + - AddressablesAnalyzeResultData + - AddressableAssetSettings.OptimizeCatalogSize + - BundledAssetGroupSchema.AssetNamingMode + - BundledAssetGroupSchema.IncludeAddressInCatalog + - BundledAssetGroupSchema.IncludeGUIDInCatalog + - BundledAssetGroupSchema.IncludeLabelsInCatalog + - BundledAssetGroupSchema.InternalIdNamingMode + - BuildScriptBase.Log + - ResourceManagerRuntimeData.AddressablesVersion + - ProjectConfigData + - ProjectConfigData.ShowSubObjectsInGroupView + - ProjectConfigData.GenerateBuildLayout + - ProjectConfigData.ActivePlayModeIndex + - ProjectConfigData.PostProfilerEvents + - ProjectConfigData.LocalLoadSpeed + - ProjectConfigData.RemoteLoadSpeed + - ProjectConfigData.HierarchicalSearch + - ProjectConfigData.ShowGroupsAsHierarchy + - BuildLayoutGenerationTask + - BuildLayoutGenerationTask.BundleNameRemap + - ExtractDataTask.BuildContext + - ContentCatalogData.SetData(IList data, bool optimizeSize) + - ContentCatalogData(string id) constructor + - ContentUpdateContext + - ContentUpdateContext.GuidToPreviousAssetStateMap + - ContentUpdateContext.IdToCatalogDataEntryMap + - ContentUpdateContext.BundleToInternalBundleIdMap + - ContentUpdateContext.WriteData + - ContentUpdateContext.ContentState + - ContentUpdateContext.Registry + - ContentUpdateContext.PreviousAssetStateCarryOver + - RevertUnchangedAssetsToPreviousAssetState + - RevertUnchangedAssetsToPreviousAssetState.Run + - AddressableAssetEntry.GetAssetLoadPath(bool isBundled, HashSet otherLoadPaths) + - AddressableAssetSettings.IgnoreUnsupportedFilesInBuild + +## [1.17.0-preview] - 2020-12-13 +- Added option to clear other cahced versions of asset bundles when a new version has been loaded. +- Added options for internal naming of asset bundles. This will allow for deterministic naming to avoid unintended diffs for content updates. +- The "Ignore Invalid/Unsupported Files" option is now saved in the settings +- Fixed issue where Filename only bundle naming schemas were overwriting old bundles prematurely in content update. + +## [1.16.19] - 2021-04-08 +- Fixed an issue where the group property of the AddressableAssetGroupSchema was not persisted, and could get lost when objects were reloaded + +## [1.16.18] - 2021-03-23 +- Fixed compile warning in Unity 2020.2+ + +## [1.16.17] - 2021-02-25 +- Updated group rename logic to support engine AssetDatabase fix. Change should be transparent to users. + +## [1.16.16] - 2021-01-20 +- Updated dependency versions for testcase fix + +## [1.16.15] - 2020-12-09 +- Addressables link.xml should now have it's own folder. +- Fixed an issue where InvalidKeyException was getting thrown when calling GetDownloadSizeAsync on scenes +- Resources folders inside Unity packages now get added to the Built In Data group +- Fixed issue where getting selected subasset would cause an error if any subassets' type was null + +## [1.16.13] - 2020-11-18 +- Added option to invert the display of CheckBundleDupeDependencies Analyze rule +- Fix GatherEntryLocations for scenes when parameter type is null +- Added some API docs for RuntimeBuildLog and AnalyzeResultData that were missing. +- Updated docs to explain the use of profile variables a little better. +- Added ability to toggle Check Duplicate Bundle Dependencies analyze rule results to be arranged by Group or Asset +- Allow assets that are inside a com.unity* package to be marked as addressable + +## [1.16.10] - 2020-11-04 +- Added internal naming option for the Bundled Asset Group Schema. Instead of using the full path, there are options to use the asset guid or the hashcode of the guid. These values are stable and wont change if the asset path changes, reducing the need to rebuild a bundle if paths change but contents do not. The internal ids stored in the content catalog will generally be shorter than asset paths - 32 bytes for the full guid, 8 bytes for the guid hash. +- Added option to exclude sub catalog entries by file extension +- Added options to exclude catalog entries for address, labels, and guids +- Added option to optimize catalog size by extracting duplicated string in urls and file paths +- Fixed issue where ResourceLocations were returning null for the ResourceType. +- Added warning to build when an Addressable Group doesn't have any AddressableAssetGroupSchemas +- Fixed issue where resource folder search was case sensitive for Mac and Linux +- Fixed issue where warnings were getting logged incorrectly when marking an asset as Addressable using the checkbox in the inspector. +- Fixed issue where an AssetReference's cached asset is not reset when the underlying asset re-imports. +- Fixed issue where we were still checking for CRC when a bundle was cached. +- Fixed bug when using Play Mode Script "Use AssetDatabase (fastest)", and calling Addressables.LoadContentCatalogAsync would fail when it had not been cached. + +## [1.16.7] - 2020-10-21 +- Fixed issue where InvalidHandle errors were getting thrown if an operation failed with releaseDependenciesOnFailure turned on. +- Fixed group build and load paths not being saved when editing multiple groups at once +- Changed Analyze Result data to be cached in the Library. Result data was previously stored in Assets/AddressableAssetsData/AnalyzeData/AnalyzeRuleData.asset. It is now stored in Library/com.unity/addressables/AnalyzeData/AnalyzeRuleData.json. If detected, the Assets - version of the Analyze data will be automatically cleaned up. +- Fixed line in AsyncOperationHandle documentation that told the wrong API for acquiring a handle +- Moved the content update documents to their own page. Expanded and clarified information on the update process + +## [1.16.6] - 2020-09-30 +- Group hierarchy support in groups window by detecting '-' in group name + - This can be turned on & off in the addressable asset settings inspector: Group Hierarchy with Dashes + - This only affects the visual display, groups are still stored in the main settings object in a flat list + - The group name is unaffected. If you name a group "x-y-z" that will be it's name, but, with the option on, it will display as if it was in a folder called "y" that was inside a folder called "x" +- Fixed fast mode resource locator Keys property to expand all possible keys when accessed. For large projects with many addressable entries and folders, this property may be slow when called for the first time. +- Added detailed build layout feature. See documentation for details. +- Fixed issue where assets in Resources weren't show full key in Groups window +- Fixed issue where loading Addressables from a different project was throwing errors. +- Fixed WriteSerializedFiles profile event timings when using the detailed build log +- Selecting multiple Resources and checking "addressable" now display a single popup +- Fixed CreateArrayResult wouldn't work with classes derived from Object, only the base class, so not for ScriptableObject. Also added test +- Fixed exceptions not handled while loading ContentCatalog +- Fixed issue where passing false into releaseDependenciesOnFailure was still releasing dependencies on failure +- Fixed issue where failed operations could over release their dependencies. +- Changes to an AssetReference rendered by AssetReferenceDrawer now register as a GUI change +- Added a checkbox in settings to ignore invalid/unsupported files during build +- empty folders are cleaned-up when moving multiple resources fails +- fixed bug where an error would occur when moving resources for paths without extensions +- Fixed issue where AddressableAsset files locked by version control couldn't be modified. + +## [1.16.1] - 2020-09-15 +- Fixed bug where some files would not be created in the right folder if the user moved its addressables config folder elsewhere +- Fixed determanism issue where bundles could have different names after Editor restart +- Added a blurb to the documentation explaining you have to pack an atlas before the sub objects will show up in the groups window +- Added "addressable" checkbox when viewing package assets in the Inspector. +- Fixed issue where GatherAllAssets would not retrieve assets located in package resources folders. +- Fixed issue where temporary StreamingAssets folder are recreated due to un-deleted meta files during a player build +- added Equals implementation for typeless AsyncOperationHandle +- When AssetReference MainAsset changed, reset SubObject +- resource manager callback leak fixes +- Packed Playmode build logs regarding BuildTargets now show up in PlayMode +- Additional Fast Mode optimizations +- Fixed issue where a released operation was not properly cleaned-up +- Fixed issue where renaming an AssetGroup with a name that contained a period led to unusual renaming behavior. +- Removed Analyze Rule "Check Sprite Atlas To...". This check was not actually valid. See "SpriteAtlas dependencies" section of "Memory Management" page in Addressables documentation for more information. +- UnloadSceneAsync calls that attempt to unload a scene that is still currently loading are now chained with the load operation and will complete after the load is finished. +- The MaxConcurrentWebRequests exposed on the AddressableAssetSettings object now gets set during runtime initialization +- Fix performance issues drawing AssetReferences with subassets caused by earlier changes to AssetReferenceDrawer +- Fixed bug where Addressables.ClearDepenendcyCache wasn't clearing the cache. +- AssetReferenceUILabelRestriction attribute now works properly on references in nested classes + +## [1.15.1] - 2020-08-25 +- Change to not allow the same AssetReference to LoadAssetAsync or LoadSceneAsync twice if current handle is valid, instead log an error with note about how to get the valid handle +- Fixed issue where disabled asset groups data would be included in the addressables_content_state.bin file for the build. +- Add ability to use custom ResourceManager exception handlers by not overwriting it in InitializeAsync if it is not null +- Fixed bug where Content Update would not use asset bundle load options for unchanged static remote bundles. +- Fixed LoadAssetAsync> to return the same set of objects in all play modes. The main asset is always first and hidden objects are ignored. +- Changed keys parameter for many Addressables APIs to be IEnumerable instead of IList. This allows for passing collections of AssetReferences or AssetLabelReferences directly instead of requiring them to be copied into a new List. +- Fix bug where lists of AssetReferenceSprites were not displayed or set right by AssetReferenceDrawer. Also fixed where multiple selected objects in project hierarchy couldn't set all lists of AssetReferences elements. +- Added better error logging when unrecognized file in build. +- Added error log when building asset bundles during player build. +- Added "Hide Events" context menu option in Event Viewer +- Fixed a bug where running the "Check Scene to Addressable Duplicate Dependencies" analyze rule multiple times would cause a duplicate key exception +- The "Check Scene to Addressable Duplicate Dependencies" analyze rule now only considers scenes that are enabled in the build settings. +- Fixed a bug where an error would be thrown when Unity 2019 opens and if the hosting window was previously left open +- Fixed a bug where changes to a service where not applied in the hosting window +- Fixed a bug where profile selection in the inspector was incorrectly reverted to the default one on domain reload +- Added documentation for LoadResourceLocationsAsync +- Added documentation for ResourceManager.ExceptionHandler +- Added documentation for AddressableAssetSettings.BuildPlayerContent +- Added documentation for LoadSceneAsync +- Added ScriptableBuildPipeline Build Callbacks to Addressables Build Scripts +- Temporary files made during bundled catalog creation are now properly cleaned up +- Inspector window now opens if it was closed when inspecting addressable settings +- Fixed bug where AsyncOperation.PercentComplete was returning 100% when IsDone was false before the operation had started. +- Progress bar is no longer updated for every entry while running Analyze rules for performance purposes. +- Fixed loading of scenes from scenes list through Addressables. Clears out an InvalidCastException that occured on init. +- Fixed issue where AssetReference wasn't able to load Addressable assets in folders during AssetDatabase Mode. + +## [1.14.2] - 2020-08-11 +- Addressables now logs the package version on initialization. +- Renamed Build Bundle Layout analyze rule to Bundle Layout Preview +- Marked RawWriteOperation obsolete. +- Marked SceneRawWriteOperation obsolete. +- AsyncOperationHandle ClearDependencyCacheAsync has been added. The new API takes an autoReleaseHandle parameter and returns the AsyncOperationHandle. +- Made the AsyncOperationHandle in AssetReference public. +- Fixed loading of items from Resources and the built in ScenesList. +- Improved the performance of loading local content on Android by using LoadFromFileAsync instead of UnityWebRequest. Please note that the bundle compression mode for all local content (on any platform) should be LZ4 or uncompressed to have optimal load performance. +- Fixed issue where some Addressables settings were not being saved if they were only serialized properties or textfields like 'Build Remote Catalog' +- Fixed a bug where DiagnosticEvents would be created even if 'Send Profiler Events' was set to false. +- Refactored the DebugNames of many of the most common implementations of AsyncOperationHandle to improve readability in the event viewer. +- Events in the Event viewer should now display more accurately in the case of Repeated loads and unloads of the same object. +- AddressableAssetEntry now overrides ToString() to return the address of the entry +- Added support for setting multiple assets and subasset references at a time for field in GameObject script in the AssetReference Inspector +- Improved performance of the GenerateLocationLists task +- Refactored DiagnosticEventCollector.RegisterEventHandler so that events are always handled in frame order. +- Fixed bug where the Event Viewer would not work when connected to a standalone player. +- Added docs describing the process of connecting the Event Viewer to a standalone player. +- Fixed exception that was getting thrown on Editor restart regarding accessing EditorSettings.enterPlayModeOptionsEnabled during serialization. +- Added MaxConcurrentWebRequests option to the AddressableAssetSettings. +- Added GetDownloadStatus method to AsyncOperationHandle. The DownloadStatus struct returned will contain the total number of bytes needed to be downloaded and the current number of bytes already downloaded. Cached AssetBundles will not be included in the count and if everything is cached, the values in the struct will be zero. +- Added Documentation for the following: + - InstantiateAsync + - DownloadDependenciesAsync + - LoadContentCatalogAsync + - UpdateCatalogs + +## [1.13.1] - 2020-07-28 +- Made `AssetReferenceT` be Serializable. This will only matter if using Unity 2020.1 or later. +- Added AddressableAssetSettings.ContiguousBundles option, which when enabled will improve asset loading times. + - In testing, performance improvements varied from 10% improvement over all, with improvements up to 50% for large complex assets such as extensive UI prefabs. +- Add New Build unclickable No Build Script Available option when no valid builder is found and added line in docs to explain what is needed +- Fixed bug where dragging a non addressable asset from an addressable folder in project viewer to AssetReference field would mark the asset as addressable and put it in the default group +- Fixed bug where enumerate exception is being thrown when expanding a group folder containing subfolders in the Addressable Groups window. +- Changed to only ask to convert legacy bundles when AddressableAssetSettings is first created or when selected from the Tools menu +- Fixed bug where clicking on an AssetReference property won't ping the referenced asset in the Project window. +- Fixed bug where GetDownloadSizeAsync was returning non-zero values for cached AssetBundles. +- Removed Event Viewer Record button because it didn't do anything. +- Fixed bug where changes made through the AddressableAssetProfileSettings API would not be immediately represented in the Profiles Window. +- Fixed bug where Instantiation and EventCount events in the Event Viewer would not update as expected. +- Fixed bug where events that occurred immediately after entering play mode would not be properly represented in the Event Viewer. +- Fixed bug where Instantiation and EventCount events would not display their most recent value when inspected in the Event Viewer. +- Added Documentation for the following: + - LoadAssetAsync + - LoadAssetsAsync + - InitializeAsync + - TransformInternalId +- Fixed bug where changing the value of "Optimize Mesh Data" in PlayerSettings doesn't affect bundle building until the old build cache is deleted. +- Expanded bundle dependencies so that loaded bundles maintain a reference to all bundle they references. This fixes various bugs when unloading and reloading a bundle that is being referenced by another bundle. + +## [1.12.0] - 2020-07-14 +- Implemented Undo/Redo capability for the Profiles Window. +- Fixed bug where the Profiles Window would occasionally throw a NullReferenceException when making a new profile. +- Added RenameProfile to the AddressableAssetsProfileSettings API +- Added error messages for failed attempts at renaming a Profile +- Fixed bug where when there are AssetReferences with the same name but in different Addressable groups only one could be selected in field dropdown +- Fixed bug surrounding addressable sprites that were also in a SpriteAtlas +- Fixed bug where loading a scene in a package would only load an empty scene with no contents. +- Fixed bug where Event Viewer window would always be empty. +- LinkXmlGenerator moved to the Scriptable Build Pipeline package in the UnityEditor.Build.Pipeline.Utilities namespace. +- Added documentation to explain how to make packages addressable. +- Fixed bug where ArgumentException errors are thrown when selecting a prefab from a read-only package. +- Fixed bug where setting AssetReference property to null wasn't dirtying the asset +- Fixed a bug where IResourceLocations were returning a false positive on comparison. +- Added error checking to make sure that an address doesn't have '[]'. + +## [1.11.2] - 2020-06-15 +- Refactored Play Mode Script for "Use Asset Database" to pull data directly from the settings. This reduces the time needed to enter play mode. +- Added scrollbar to the Label dropdown +- Fixed misleading dialog box shown to the user when there are unsaved scenes. +- Fixed bug where DownloadDependenciesAsync always returns an AsyncOperationHandle with a null task. +- Fixed bug where AddressableAssetSettings.asset is always being written to disk whenever something is changed in OnPostProcessAllAssets, including asset modified, moved, group created or deleted +- Revamped Profiles window to a two panel layout. +- Fixed issue with Profiles window where changes would occasionally not be serialized to the settings asset. +- Fixed bug where an op with some failed dependencies would never release the ones that had succeeded. +- Added optional parameter "releaseDependenciesOnFailure" to LoadAssetsAsync to handle the scenario of partial success. This is when there are multiple locations being loaded, and not all succeed. In the partial success scenario: + - By default, the new parameter is true, and all successful parts will be released. The .Result on the returned handle will be null and Status will be Failed + - When false, the returned .Result will be a List of size matching the number of matching locations. Any failed location will correlate to null in the List, while successful locations will correlate to valid objects in the List. Status will still be Failed in this scenario. +- Bundles that fail to load from the cache are now removed from the Cache and will be redownloaded. +- Added option to disable CRC checks for cached AssetBundles on BundledAssetGroupSchema under Advanced Options. +- If null is passed into Addressables.UpdateCatalogs(...) for the list of catalogIds, CheckForCatalogUpdates will be called automatically. +- Added null reference check when running InitializationObjectsOperation to take failed RuntimeData operations into account. +- Disabled hitting ENTER on an AssetReference inspector to open popup. The drawer does not know which AssetReference to associate the popup should that MonoBehaviour have more than one. So disabling is unfortunately the only safe option. +- Fixed issue where assets located in subfolders marked as addressable would be added to build content multiple times. +- Fixed bug where Groups window hierarchical search was not filtering the group contents. +- Fixed bug with Groups window flat search not sorting. + +## [1.10.0] - 2020-05-28 +- Fixed hosting service not working for special characters in addressable asset address +- Fixed bug where tracked scene instance operation handles weren't matching the handles returned to the user. +- Fixed bug where Sprite Atlas ResourceProvider wasn't getting added to list of ResourceProviders. +- Fixed bug where pack separately groups were rebuilding all bundles when an asset was added or removed from the group. + +## [1.9.2] - 2020-05-21 +- Improved the performance of GenerateLocationLists. +- Fixed AssetReferenceLabelUIRestriction not working for private fields +- Fixed AssetReferenceDrawer OnGui changing text of static variable GUIContent.none +- Updated documentation to explain what's happening when DontDestroyOnLoad GameObjects are having their dependencies removed when the scene they originate in is unloaded. +- Using a more efficient method of gathering the Addressable entries for the AssetReferenceDropdown UI. +- Fixed bug surrounding how "Use AssetDatabase" build script handles deleted assets. +- Fixed issue where ContentUpdate was throwing an exception if a dependency wasn't in the previous build. +- PercentComplete calcluation updates to correctly take progress callbacks on ProviderOperations into account. +- Added support for Enable Play Mode Options in 2019.3+ +- Fixed issue where diagnostic events are still being sent to the player regardless of the value of "Send Profiler Events". +- Added error checking to make sure that a group doesn't have both a PlayerDataGroupSchema and a BundledAssetGroupSchema. +- Fixed issue where InitializationObjects were causing the InitializationOperation to hang. + +## [1.8.4] - 2020-05-20 +- Taking an updated scriptable build pipeline that reverts a recent hashing change. + +## [1.8.3] - 2020-04-07 +- Option to disable sprites and subobjects has been added to the Groups window Tools menu. This option is persisted per user, not with the project. +- Catalog entries for subobjects and sprites are no longer serialized into the catalog. These are generated at runtime with a custom resource locator. +- Added missing error logs to various failure cases. +- Fixed subobject parsing to treat anything between the first '[' character and the last ']' as the subobject name instead of the last '[' and the last ']'. +- Changed the display of AssetReference types in the inspector from a dropdown to look like an object reference. +- Added the option to compress the local content catalog by packing it in an asset bundle. +- Added method in settings to retrieve all defined labels. +- Fixed PercentComplete in ChainOperation +- Fixed main settings asset getting marked dirty when making builds. +- Fixed issues with Content Update when entry with dependant entries was modified. +- Fixed "Unknown Exception" issue caused by releasing certain operation handles too many times. +- Added link to online documentation in the addressable windows menu. +- Fixed bug where two assets with the same address packed separately was causing an error. +- Fixed issue where loading a content catalog multiple times was throwing exceptions. +- Made it so using the LoadContentCatalogAsync API creates a ResourceLocation that allows those catalogs to be updated properly. +- Fixed bug where the scene in a recycled InstanceOperation wasn't being cleaned. +- Fixed bug where an invalid location would be created for assets that weren't in a Resources folder, but were part of a group with the PlayerDataGroupShema. +- Schema asset file name uses group name instead of GUID. For example: GroupName_SchemaName.asset +- Fixed text that was being cutoff in the CacheIntializationSettings inspector view. +- During init, if a remote catalog is expected but not present, this will fail silently. Fixed a bug where that silent failure showed up later as an "unknown error in async operation". + - if you wish to see a log for the failed catalog retrieval, enable ADDRESSABLES_LOG_ALL as a scripting define symbol. +- Fixed bug where renaming a class referenced by an AddressableAssetEntry causes an InvalidKeyException. +- Fixed performance regression in ContentUpdateScript.SaveContentState +- Fixed performance regression in BuildScriptPackedMode.PostProcessCatalogEntries +- Updated to scriptable build pipeline 1.7.2 which includes many build optimizations - see SBP changelog for details + +## [1.7.5] - 2020-03-23 +- Fixed null key exception when building that happened when an invalid asset type is in a resources folder. + +## [1.7.4] - 2020-03-13 +- Improved building catalog data speed. +- Various minor optimizations related to handling sub objects. +- Added progress bar to the catalog generation part of the build process. +- Gave initialization objects an asynchronous initialization API. +- Made it so a CacheInitializationObject waits for engine side Caching.ready to be true before completing. +- Fixed a bug when accessing AssetReferenceT.editorAsset where the Type does not match the Editor Asset type, Such as a subAsset type. +- Fixed bug where Use Asset Database and Use Existing Build could return a different number of results in LoadAssetAsync> +- Fixed bug where SceneUnload Operations weren't getting properly released in certain circumstances. +- Fixed UI performance regression when opening the Addressables Group Editor window. +- Fixed issue where RuntimeKeyIsValid was give a false negative when checking sub-objects. +- Updating scripting defines to check if caching is enabled. +- Changed the display of AssetReference types in the inspector from a dropdown to look like an object reference. +- Prevent assets from being added to read only Addressable groups through the group editor window. +- Group names can now be searched through the group editor window. +- Added ability to set variables in AddressablesRuntimeProperties more than once. +- Fixed missed null check on drag and drop in Group Editor window. +- Updated Scriptable Build Pipeline dependency to bring in these changes: + - Updated CompatibilityAssetBundleManifest so hash version is properly serializable. + - Renamed "Build Cache" options in the Preferences menu to "Scriptable Build Pipeline" + - Improved performance of the Scriptable Build Pipeline's archiving task. + +## [1.6.2] - 2020-02-08 +- Checking if Profile Events is enabled on the engine side before running the DiagnosticEventCollector Update. +- Fixed issue where RuntimeKeyIsValid was give a false negative when checking sub-objects. +- Fixed Update Previous Build workflow that wasn't re-using previously built Asset Bundle paths when necessary. +- Updated Scriptable Build Pipeline dependency to bring in these changes: + - Fixed an issue where texture sources for sprites were not being stripped from the build. + - Fixed an issue where scene changes weren't getting picked up in a content re-build. + - Fixed an issue where texture sources for non-packed sprites were being stripped incorrectly. +- Fixed issue where hosting service ports were changing on assets re-import. +- Fixed issues with Content Update, including groups that are Packed Separately not updating properly. + +## [1.6.0] - 2020-01-11 +- Fixed bug where unsubscribing to AsyncOperations events could throw if no subscription happened beforehand. +- Fixed NullReferenceException when displaying Groups window displaying entries with Missing Script References on SubAssets. +- Moved AnalyzeWindow.RegisterNewRule to AnalyzeSystem.RegisterNewRule so that the API/logic wouldn't live in GUI code. +- Fixed bug where scenes in a folder containing "Assets" in the folder name not loadable in "Use Asset Database" mode. +- InvalidKeyException's message now include the type of the key that caused it, if applicable. +- Added the ability to select and edit multiple Addressable Groups at the same time. +- Assigning LocationCount during AddressableAssetBuildResult.CreateResult +- Fixed issue where groups and schemas were getting deleted on import. +- Adding dependencies to built in modules to prevent them from being disabled if Addressables is active. +- Adding scripting define to remove Caching API calls when ENABLE_CACHING is false +- Added API to get the scene AsyncOperation from ActivateAsync(). Made the previous API, Activate(), obsolete. +- Fixed bug where the group window wasn't properly refreshed on Analyse fix + +## [1.5.1] - 2020-01-13 +- Fixed issue where groups and schemas were getting deleted on import. +- Adding scripting define to remove Caching API calls when ENABLE_CACHING is false + +## [1.5.0] - 2019-12-09 +- Fixed temporary StreamingAssets files not being removed on a failed player build. +- Added Bundle Naming option for naming as a hash of the full filename string. +- Added a delay before unloaded things are removed from Event Viewer graph. Ideally this would track with dependencies, but for now it's simply time based. +- Fixed ProfileValueReferences not getting set dirty when changed. +- Added ability for Addressables to handle null references in the Addressables groups list. + - Null groups should not affect or influence content builds, updates, or Analyze rules. + - Right clicking on a [Missing Reference] will give you the option to remove all missing references. +- Fixed issue with Analyze reporting multiple duplicate data for one group. +- Fixed issue where unloading a scene was throwing an invalid handle error. +- Added Addressables.ClearDependencyCacheAsync API to clear cached dependent AssetBundles for a given key or list of keys. +- Added type conversion from AnimatorController to RuntimeAnimatorController. + +## [1.4.0] - 2019-11-13 +- Added the ability to disable checking for content catalog updates during initialization. +- Fixed issue where turning off Include in Build in the right circumstances would throw an exception. +- Made internal classes and members public to support custom build scripts. +- Exposed Addressables.InstanceProvider to allow for setting up runtime specific data on custom instance providers. +- Fixed issue with filenames being too long to write to our Temp cache of AssetBundles. +- Changed ProcessGroup in BuildScriptFastMode to directly create catalog entries from Addressable entries. +- Added progress bar to Fast Mode when creating content catalog. + +## [1.3.8] - 2019-11-04 + - Properly suppressing a harmless "Unknown error in AsyncOperation" that has been popping up during init. It had to do with not finding a cached catalog before a catalog had been cached (so error shouldn't happen). + - Fixed issue with asset hash calcluation for internal asset bundle name when building bundles. + - Adding option "Unique Bundle IDs" to the General section of the AddressableAssetSettings Inspector. + - If set, every content build (original or update) will result in asset bundles with more complex internal names. This may result in more bundles being rebuilt, but safer mid-run updates. See docs for more info. + - This complex internal naming was added to 1.3.3 to support safter Content Catalog updating, but was forced on. It is now optional as there are some drawbacks. + +## [1.3.5] - 2019-11-01 + - Added documentation about updating Content Catalog at runtime (outside Init). Uses CheckForCatalogUpdates() and UpdateCatalogs(). + +## [1.3.3] - 2019-10-21 + - UI and naming changes + - "Static true or false" content is now content with an "Update Restriction" of "Cannot Change Post Release" or "Can Change Post Release" + - "Fast Mode" (play mode) has been renamed "Use Asset Database (faster)" + - "Virtual Mode" (play mode) has been renamed "Simulate Groups (advanced)" + - "Packed Mode" (play mode) has been renamed "Use Existing Build (requires built groups)" + - There is no longer a current "Build Script" (Build Script menu in Addressables window). Instead the script is selected when triggering the build. + - Schemas have been given display names to be more clear of their intent BundledAssetGroupSchema. + - BundledAssetGroupSchema displays as "Content Packing & Loading" + - ContentUpdateGroupSchema displays as "Content Update Restriction" + - Bundle and Asset providers within schema settings are named more descriptively + - Profile management is in its own window ("Profiles") + - Label management is in its own window + - "Prepare for Content Update" is now under the "Tools" menu (in Addressables window), and is called "Check for Content Update Restriction" + - "Build for Content Update" is "Update a Previous Build" (still in "Build" menu of Addressables window). + - "Profiler" window has been renamed "Event Viewer". It's more accurate, and avoids confusion with "Profilers" window. + - Added additional parameter to AssetReference.LoadSceneAsync method to match Addressables.LoadSceneAsync API + - Added AssetReference.UnloadScene API + - Fixed issue with WebGL builds where re-loading the page was causing an exception to get thrown. + - Fixed Analyze bug where bundle referenced multiple times was flagged as duplicate. + - Fixed issue with hashing dependencies that led to frequent "INCORRECT HASH: the same hash (hashCode) for different dependency lists:" errors. + - Update AddressableAssetEntry cached path to new modified asset entry paths. + - Storing the KeyData string from ContentCatalogData on disk instead of keeping it in memory as it can get quite large. + - Fixed Custom Hosting Service window so it won't close when focus is lost. + - Fixed issue with AudioMixerGroups not getting the proper runtime type conversion for the build. + - Fixed invalid location load path when using "only hash" bundle naming option in 'content packing and loading' schema. + - Removed content update hash from final AssetBundle filename. + - Removed exception in Analyze that was triggering when "Fix Selected Rules" was bundling in Un-fixable rules. + - (SBP) Fixed an edge case where Optimize Mesh would not apply to all meshes in the build. + - (SBP) Fixed an edge case where Global Usage was not being updated with latest values from Graphics Settings. + - (SBP) Fixed Scene Bundles not rebuilding when included prefab changes. + - Added APIs to update content catalog at runtime: CheckForCatalogUpdates() and UpdateCatalogs(). + +## [1.2.4] - 2019-09-13 + - Further improvement to the % complete calculations. + - Note that this is an average of dependency operations. Meaning a LoadAssetsAsync call will average the download, and the loading progress. DownloadDependenciesAsync currently has one extra op, so the download will crawl to 50%, then jump to done (we will look into removing that). Similarly any op that is called before Addressables init's will jump to 50% once init is done. + +## [1.2.3] - 2019-09-10 + - Actually "Made ContentUpdateScript.GatherModifiedEntries public." + +## [1.2.2] - 2019-09-09 + - Made ContentUpdateScript.GatherModifiedEntries public. + - Added sub-object support to AssetReference. For example, you can now have an AssetReference to a specific sprite within a sprite atlas. + - Added sub-object support to addresses via [] notation. For example, sprite atlas "myAtlas", would support loading that atlas via that address, or a sprite via "myAtlas[mySprite]" + - Fixed issue with Content Update workflow. Assets that don't change groups during Content Update now remain in the same bundle. + - Added funtionality to allow multiple diagnostic callbacks to the ResourceManager. + - Added error and IResourceLocation to the callback. + - Added default parameter to DownloadDependenciesAsync to allow auto releasing of the the operation handle on completion. + - Added memory management documentation. + - Changed OnlyHash naming option to remove folder structure. This is a workaround to Windows long-file-path issues. + - Made AssetReference interfaces virtual + - Fixed hash calculations to avoid collisions + - Added overload for GetDownloadSizeAsync. The overload accepts a list of keys and calculates their total download size. + - Improved percent complete calculations for async opertions. + +## [1.1.10] - 2019-08-28 + - Fix for all files showing "Missing File" in the addressables window. + - Fix for waiting on a successfully done Task + +## [1.1.9] - 2019-08-22 + - Fixed drag and drop NullRef in main addressables window. + - Fixed AudioMixer type assets getting stripped from bundles. + - Fixed issue where failed async operations weren't getting released from the async operation cache. + - Fix unloading of scenes so that the dependencies will wait for the unload operation to complete before unloading. This was causing an occasional 1-frame visual glitch during unload. + - Fixed scenario where AsyncOperation Task fails to complete when AsyncOperation has already completed. + - Fixed a missed init-log that was stuck always-logging. + - Fixed issue around assets losing dependencies when unloaded then reloaded. This would manifest most often as sprites losing their texture or prefabs losing their shader/material/texture. + - Changed checks for determining if a path is remote or not from looking for "://" to looking for starting with "http". "://" is still used to determine if the asset should be loaded via UnityWebRequest or not. + - Added Analyze Rule to show entire Asset Bundle layout + - Added progress bars and some optimizations for calculating analyze rules + +## [1.1.7] - 2019-07-30 + - Fixed chain operation percent complete calculation. + - Fixed scenario where deleting assets would also delete groups that have similar names. + - Fix in bundle caching bug surrounding bundles with '.' in their name + - Significant improvements to the manual pages + - Made the many init-logs not log unless ADDRESSABLES_LOG_ALL is defined in player settings (other logs always worked this way, init didn't). + - Prevented NullReferenceException when attempting to delete entries in the Addressables window. + - Fix for building by label (Bundle Mode = Pack Together By Label) + - Removed ability to mark editor-only assets as addressable in GUI + - Better fix to Editor types being added to the build + - Made BuiltIn Data group read-only by default. + - Fixed NullRef caused by an invalid (BuildIn Data) group being default during a build. + - Fixed path where LoadResourceLocationsAsync could still throw an exception with unknown key. Now it should not, and is a safe way to check for valid keys. + - If Key does not exist but nothing else goes wrong, it will return an empty list and Success state. + - Fixed NullRef caused when there was a deleted scene in the scenes list. + - BuildCompression for Addressables can now be driven from the default group. If necessary WebGL builds will fallback to LZ4Runtime and all other build targets will fallback to LZMA. + - Added options for bundle naming: AppendHash, NoHash, OnlyHash. + - As a temporary workaround for updating issues, we recommend setting all groups with StaticContent=true to be NoHash. This will make sure the updated catalog still refers to the correct unchanged bundle. An actual fix will be out in a few releases. + +## [1.1.5] - 2019-07-15 + - Fixed scenario where scene unload simultaneously destroys objects being instantiated in different scenes. + - Cleaned up SetDirty logic to remove excessive dirtying of assets. + +## [1.1.4-preview] - 2019-06-19 + - Fixed an issue where Editor only types were being added to the build. + +## [1.1.3-preview] - 2019-06-17 + - *BREAKING CODE CHANGES* + - ReleaseInstance will now return a bool saying if it successfully destroyed the instance. If an instance is passed in that Addressables is unaware of, this will return false (as of 0.8 and earlier, it would print a log, and still destroy the instance). It will no longer destroy unknown instances. + - Added PrimaryKey to the IResourceLocation. By default, the PrimaryKey will be the address. This allows you to use LoadResourceLocationsAsync and then map the results back to an address. + - Added ResourceType to IResourceLocation. + - This allows you to know the type of a location before loading it. + - Fixes a problem where calling Load*(key) would load all items that matched the key, then filter based on type. Now it will do the filter before loading (after looking up location matches) + - This also adds a Type input to LoadResourceLocationsAsync. null input will match all types. + - Safety check AssetReference.Asset to return null if nothing loaded. + - New rule added to Analyze window - CheckResourcesDupeDependencies - to check for dependencies between addressables and items in Resources + - Added group rearranging support to the Addressables window. + - Improved logging when doing a Prepare for Content Update. + - Added versions of DownloadDependencies to take a list of IResourceLocations or a list of keys with a MergeMode. + - Fixed scenario where Task completion wouldn't happen if operation was already in a certain state + - Made LoadResourceLocations no longer throw an exception if given unknown keys. This method is the best way to check if an address exists. + - Exposed AnalyzeRule class to support creating custom rules for Addressables analysis. + - Fixed some issues surrounding loading scenes in build scenes list via Addressables + - Removed using alias directives defined in global space. + - Proper disposal of DiagnosticEventCollector and DelayedActionManager when application closes. + - Added support for loading named sub-objects via an "address.name" pattern. So a sprite named "trees" with sub-sprites, could be loaded via LoadAssetAsync("trees.trees_0"). + - Known issue: loading IList from a Texture2D or IList from an fbx will crash the player. The workaround for now is to load items by name as mentioned just above. Engine fix for this is on its way in. + +## [0.8.6-preview] - 2019-05-14 + - Fix to make UnloadSceneAsync(SceneInstance) actually unload the scene. + +## [0.8.3-preview] - 2019-05-08 + - *BREAKING CODE CHANGES* + - Chagned all asynchronous methods to include the word Async in method name. This fits better with Unity's history and convention. They should auto upgrade without actually breaking your game. + - Moved AsyncOperationHandle inside namespace UnityEngine.ResourceManagement + - Addressable Analyze changes: + - Analyze has been moved into it's own window. + - CheckSceneDupeDependencies Analyze rule has been added. + - CheckDupeDependencies has been renamed into CheckBundleDupeDependencies. + - Analyze Rule operations for individuals or specific sets of Analyze Rules has been added via AnalyzeRule selections. + +## [0.7.4-preview] - 2019-04-19 + - Removed support for .NET 3.x as it is deprecated for Unity in general. + - Replaced IAsyncOperation with AsyncOperationHandle. + - Once the asset is no longer needed, the user can call Addressables.Release, passing in either the handle, or the result the handle provided. + - Exposed AsyncOperationBase for creating custom operations + - These operations must be started by ResourceManager.StartOperation + - Replaced IDataBuilderContext and it's inherited classes with simpler AddressablesDataBuilderInput. This class is fed into all IDataBuilder.BuildData calls. + - Fixed Nintendo Switch and PlayStation4 support. + - Simplified the IResourceProvider interface. + - Refactored build script interface. Made BuildScriptBase and the provided concrete versions easier to inherit from. + - Removed DelayedActionManager. + - Removed ISceneProvider. Users can implement custom scene loading using a custom AsyncOperationBase. + - Removed optional LRU caching of Assets and Bundles. + - Addressables Profiler now tracks all active async operations + - AssetBundles targetting StreamingAssets (by using the profile variable [UnityEngine.AddressableAssets.Addressables.BuildPath] now build to the Library instead of StreamingAssets. During the player build, these files are copied into StreamingAssets, then after the build, the copies are deleted. They are also built into platform specific folders (so building for a second platform will not overwrite data from a first build). We recommend deleting anything in Assets/StreamingAssets/aa. + - The addressables_content_state.bin is built into a platform specific folder within Assets/AddressableAssetsData/. We recommend deleting the addressables_content_state.bin in Assets/AddressableAssetsData to avoid future confusion. + - ScriptableBuildPipeline now purges stale data from its cache in the background after each build. + - Disabled Addressables automatic initialization. It will now initialize itself upon the first call into it (such as Load or Instantiate). To Initialize on startup instead of first use, call Addressables.Initialize(). + - Optimized performance around instantiation and general garbage generation. + - Added per-group bundle compression settings. + - Fixes to AssetReference drawers. + - Improved the group template system for creating better defined asset groups. + - Fixed bug in bundle caching that caused GetDownloadSize to report incorrectly + - Cleaned up Load/Release calls to make sure all releases could take either the handle returned by Load, or the handle.Result. + - Added editor-only analytics (nothing added in runtime). If you have Analytics disabled in your project nothing will be reported. Currently only run when you build addressables, it includes data such as Addressables version and Build Script name. + - Fixed null ref issue when cleaning all the data builders + - KNOWN ISSUE: there is still an occasional issue with code stripping on iOS. If you run into iOS issues, try turning stripping off for now. + +## [0.6.8-preview] - 2019-03-25 +- fixed Build For Content Update to no longer delete everything it built. + +## [0.6.7-preview] - 2019-03-07 + - Fix for iOS and Android. Symptom was NullReferenceException dring startup resulting in nothing working. Fix requires re-running Build Player Content + +## [0.6.6-preview] - 2019-03-05 + - *BREAKING CODE CHANGES* + - to ease code navigation, we have added several layers of namespace to the code. + - All Instantiate API calls (Addressables and AssetReference) have been changed to only work with GameObjects. + - any hardcoded profile path to com.unity.addressables (specifically LocalLoadPath, RemoteLoadPath, etc) should use UnityEngine.AddressableAssets.Addressables.RuntimePath instead. + For build paths, replace Assets/StreamingAssets/com.unity.addressables/[BuildTarget] with [UnityEngine.AddressableAssets.Addressables.BuildPath]/[BuildTarget] + For load paths, replace Assets/StreamingAssets/com.unity.addressables/[BuildTarget] with {UnityEngine.AddressableAssets.Addressables.RuntimePath}/[BuildTarget] + - We have removed attribute AssetReferenceTypeRestriction as it is cleaner to enforce type via generics + - Attribute AssetReferenceLabelRestriction is renamed to AssetReferenceUILabelRestriction and must be surrounded by #if UNITY_EDITOR in your game code, to enforce it's editor-only capability + - Modifications to IResourceProvider API. + - Removed PreloadDependencies API. Instead use DownloadDependencies + - Content Update calculation has changed, this will invalide previously generated addressables_content_state.bin files. + - Some types for content update were made private as a result of the above change. + - Minimum Unity version is now 2018.3 to address a build-time bug with progressive lightmapper. + - Moved all of the Resource Manager package to be contained within Addressables (no longer a stand alone package). No code change implications. + - Change to content catalog building: + - Previous model built one catalog per group, wherever that group built it's data. + - New model builds one catalog locally, and optionally one "remote". Remote location is set on the top level AddressableAssetSettings object. + - Loading will now always check if remote has changes (if remote exists), and use local otherwise (or cached version of remote). + - LoadScene API now takes the LoadSceneParameters that were added to the engine in 2018.2 + - Exposed AddressablesBuildDataBuilderContext.BuildScriptContextConstants for use in build scripts. + - Refactored AddressablesBuildDataBuilderContext.GetValue to take default parameter. + - Fixed Scene asset path to be consistent between different play modes in the catalog data. + - Exposed the various IDataBuilder implementations as public classes. + - Exposed asset and bundle provider types for BundledAssetGroupSchema. + - Fixed several bugs when loading catalogs from other projects. + - Added provider suffix to Initialization operation and Addressables.LoadCatalogsFromRuntimeData API to better support overriding providers. + - Exposed CachedProvider options in BundledAssetGroupSchema. Each unique set of parameters will generate a separate provider. There is also an option to force a group to have its own providers. + - Added IEnumerable Keys property to IResourceLocator interface. + - Exposed InitializationOperation as public API. + - Added BuildTarget to ResourceManagerRuntimeData. This is used to check if the generated player content was built with the same build target as the player or the editor when entering play mode. + - Removed warnings generated from not finding the cached catalog hash files, which is not an error. + - Fixed bug where scenes were not unloading. + - Fixed GUI exception thrown in group inspector. + - Fixed error case where an asset (usually a bundle) was loaded multiple times as different types (object and AssetBundle). + - Fixed divide by zero bug when computing load percent of simulated asset bundles. + - AddressableAssetBuildResult.CreateResult now takes the settingsPath as a parameter to pass this to the result. + - Fix AssetReference GUI when the AssetReference is inside an array of classes, part of a SerializedObject, or private. + - Fix AssetReferenceSprite to properly support sprites (as opposed to Texture2D's). + - Fixed bug involving scenes being repeatedly added to the build scenes list. + - Removed deprecated and obsolete code. If you are upgrading from a very old version of Addressables, please update to 0.5.3-preview first. + - Removed the default MergeMode on LoadAssets calls to enforce explicit behavior. + - Added IAsyncOperation GetDownloadSize(object key) API to compute remaining data needed to load an asset + - Fixed assets being stuck in a read-only state in UI + - Unified asset moving API to clean up public interface + - Added PlayerVersion override to AddressableAssetSettings + - Ensure UI cannot show invalide assets (such as .cs files) + - Renamed Addressables.LoadAddtionalCatalogs to Addressables.LoadContentCatalog and now it takes the path of the catalog instead of the settings file + - Moved provider information from ResourceManagerRuntimeDate into ContentCatalogData + - Updating ResourceManager to be a non-static class + - Fixed bugs surrounding assets moving in or out of Resources (outside Addressables UI) + - Fixed the AssetReference dropdown to properly filter valid assets (no Resources and honoring type or label limitations). + - Fixed AssetReferences to handle assets inside folders marked as Addressable. + - Added attribute AssetReferenceUIRestriction to support user-created AssetReference restrictions (they are only enforced in UI, for dropdown and drag&drop) + - Changed addressables_content_state.bin to only build to the folder containing the AddressableAssetSettings object (Assets/AddressableAssetsData/ in most cases) + - Fixed issue where the wrong scene would sometimes be open post-build. + +## [0.5.3-preview] - 2018-12-19 + - fixed upgrade bug from 0.4.x or lower to 0.5.x or higher. During upgrade, the "Packed Mode" option was removed from play mode. Now it's back and upgrades are safe from 0.4.x or from 0.5.x to 0.5.3 + +## [0.5.2-preview] - 2018-12-14 + - *IMPORTANT CHANGE TO BUILDING* + - We have disabled automatic asset bundle building. That used to happen when you built the player, or entered play mode in "packed mode". This is no longer the case. You must now select "Build->Build Player Content" from the Addressables window, or call AddressableAssetSettings.BuildPlayerContent(). We did this because we determined that automatic building did not scale well at all for large projects. + - fixed regression loading local bundles + - Added Addressables.DownloadDependencies() interface + - fixes for Nintendo Switch support + - Fixed issues around referencing Addressables during an Awake() call + - Code refactor and naming convention fixes + - Cleaned up missing docs + - Content update now handles not having and groups marked as Static Content + - Fixed errors when browing for the addressables_content_state.bin and cancelling + - Moved addressables_content_state.bin to be generated into the addressables settings folder + - Changed some exceptions when releasing null bundles to warnings to handle the case of releasing a failed download operation + - Separated hash and crc options to allow them to be used independently in asset bundle loads. + - Use CRC in AssetBundle.LoadFromFileAsync calls if specified + - Always include AssetBundleRequestOptions for asset bundle locations + +## [0.4.8-preview] - 2018-10-22 + - Added all referenced types in asset bundles to link.xml to prevent them from being stripped in IL2CPP builds + +## [0.4.7-preview] - 2018-10-20 + - updated Scriptable Build Pipeline version in dependencies + +## [0.4.6-preview] - 2018-10-16 + - MINIMUM RECOMMENDED VERSION - 2018.2.11+ + - We have re-enabled the addressables checkbox. Versions of 2018.2 older than the .11 release will work unless you attempt to view the Animation Import Settings inspector. If you do have animations you need to inspect, use .11+. If you do not, use any official release version of 2018.2. + - refactored the way IResourceProviders are initialized in the player - serialized data is constructed at runtime to control how the providers are configured + - added readonly custom inspector for AddressableAssetEntryCollection + - AssetReference now stores the loaded asset which can be accessed via the Asset property after LoadAsset completes. ReleaseAsset has been modified to not need the asset passed in (the old version is marked obsolete] + - fixed profiler details view not updating when a mouse drag is completed + - fixed null-ref when moving Resources to Addressables when there are no Resources + - blocked moving EditorSceneList within GUI + - fixed cap on address name length + - fixed workflows of marking Resources as addressable and moving an addressable into Resources. + - fixed issue where AssetReferenceDrawer did not mark scene as dirty when changed. + - added Hosting Services feature; provides extensible framework and implementation for serving packed content to player builds from the Editor + - replaced addressables buildscript with an interface based system. IDataBuilder class is now used to define builders of specific types of data. The Addressables settings object + contains a collection of data builders and uses these to create player and play mode data. Users can implemented custom data builders to control the build process. + - replaced AssetGroupProcessors with a collection of AssetGroupSchema objects. The difference is that the schema objects only contain data and groups can have multiple schemas. The + logic for processing groups now resides in the build script and uses the schemas as data sources and filters for how to build. + - Added Initialization objects that can be created during the build to run during addressables initialization + - Implemented Caching API initialization with initialization objects + - Changed some API and tests to work with 2019.x + - fixed how AssetReference's draw when within lists, arrays, or contained classes + - Fixed the workflow of scenes moving in and out of the Editor Build Settings Scene list. + - Removed "Preview" and added "Analyze". + - The new system runs any rules it knows about. + - Currently this is one rule that is manually set up in code. Future work will have additional rules, and expose the ability to create/add user- or project-specific rules + - This process can be slow, as it runs most of a build to get accurate data. + - Within the Analyze window there is a "fix" button that allows each rule to fix any issues if the rule knows how. + - The current rule is a "check duplicate asset" rule. This looks for assets that are pulled into multiple asset bundles due to dependency calculations. The way it fixes things is to move all of those into a newly created group. + - Added option to toggle logging of all exceptions within the Resource Manager + - Refactored initialization of the addressable asset settings to prevent it getting into a bad state. + +## [0.3.5-preview] - 2018-09-05 + - implemented content update workflow. Added a dropdown to the "Build" button on main window's toolbar. + - "Build/Prepare for Content Update" will detect assets in locked bundles (bundles flagged as static, by default all local bundles). + - "Build/Build for Content Update" will build assets with a catalog that is compatible with a previously released player. + - "Build/Build Packed Data" will build in the same way entering play mode in PackedMode would. + - implemented Clean Build. "Build/Clean/*" will clear out build caches. + - cleaned up streaming assets folder better after build + - moved asset group data into separate assets in order to better support version control + - fixed bug when canceling export of entries to an AssetEntryCollection + - fixed several bugs related to caching packed bundles in play mode + - added option to build settings to control whether streaming assets is cleared after each build + - enabled CreateBuiltInShadersBundle task in build and preview + - fixed bug in AA initialization that was cuasing tests to fail when AA is not being used. + - fixed bug where toggling "send profiler events" would have no effect in some situations + - default the first 2 converted groups to have StaticContent set to true + - UI Redesign + - Moved most data settings onto actual assets. AddressableAssetSettings and AddressableAssetGroup assets. + - AddressableAssetSettings asset has "Send Profile Events", list of groups, labels, and profiles + - AddressableAssetGroup assets have all data associated with that group (such as BuildPath) + - Made "preview" be a sub-section within the Addressables window. + - The "Default" group can now be set with a right-click in the Addressables window. + - Set play mode from "Mode" dropdown on main window's toolbar. + - Moved "Hierarchical Search" option onto magnifying glass of search bar. Removed now empty settings cog button. + - fixed issue when packing groups into seperate bundles generated duplicate asset bundle names, leading to an error being thrown during build + - added support for disabling the automatic initialization of the addressables system at runtime via a script define: ADDRESSABLES_DISABLE_AUTO_INITIALIZATION + - added API to create AssetReference from AddressableAssetSettings object in order to create an entry if it does not exist. + - moving resource profiler from the ResourceManager package to the Addressables package + - fixed bug where UnloadScene operation never entered Done state or called callback. + - fixed loading of additonal catalogs. The API has changed to Addressables.LoadCatalogsFromRuntimeData. + - fixed bug in InitializationOperation where content catalogs were not found. + - changed content update workflow to browse for cachedata.bin file instead of folder + - fixed exception thrown when creating a group and using .NET 4.x + - fixed bugs surrounding a project without addressables data. + - AssetLabelReference inspector rendering + - AssetReference drag and drop + - fixed profiler details view not updating when a mouse drag is completed + - fixes surrounding the stability of interacting with the "default" group. + - Added docs for the Content Update flow. + - Adjusted UI slightly so single-clicking groups shows their inspector. + - removed not-helpful "Build/Build Packed Data" item from menu. + - fixed bug where you could no longer create groups, and group assets were not named correctly + +## [0.2.2-preview] - 2018-08-08 + - disabled asset inspector gui for addressables checkbox due to editor bug + +## [0.2.1-preview] - 2018-07-26 + - smoothed transition from 0.1.x data to 0.2.x data + - added checks for adding duplicate scenes into the EditorBuildSettings.scenes list + - fixed exception when deleting group via delete key, added confirmation to all deletions + +## [0.2.0-preview] - 2018-07-23 + - Fixed bundles being built with default compression instead of compression from settings + - Fixed bug in tracking loaded assets resulting in not being able to release them properly + - Added Key property to IAsyncOperation to allow for retrieval of key that requested the operation + - Added AssetLabelReference to provide inspector UI for selecting the string name of a label + - Fixed dragging from Resources to a group. + - Added ability to re-initialize Addressables with multiple runtime data paths. This is to support split projects. + - Clean up StreamingAssets folder after build/play mode + +## [0.1.2-preview] - 2018-06-11 + - fixed Application.streamingAssetsPath being stripped in IL2CPP platforms + +## [0.1.1-preview] - 2018-06-07 + - MIN VERSION NOW 2018.2.0b6 + - updated dependency + +## [0.1.0-preview] - 2018-06-05 + - MIN VERSION NOW 2018.2.0b6 + - added better checks for detecting modified assets in order to invalidate cache + - fixed preview window showing scenes in wrong bundle + - exclude current processor type from conversion context menu + - fixed exception when right clicking asset groups + - added support for adding extra data to resource locations + - made Addressables.ReleaseInstance destroy even non-addressable assets. + - append hash to all bundle names + - pass crc & hash to bundle provider + - clear catalog cache whenever packed mode content is rebuilt + +## [0.0.27-preview] - 2018-05-31 + - fixed ResourceManager initialization to work as the stand-alone player + +## [0.0.26-preview] - 2018-05-24 + - re-added Instantiate(AssetReference) for the sake of backwards compatability. + +## [0.0.25-preview] - 2018-05-23 + - workaround for engine bug surrounding shader build. Fix to engine is on it's way in. + +## [0.0.24-preview] - 2018-05-21 + - minor bug fix + +## [0.0.23-preview] - 2018-05-21 + - new format for content catalogs + - detects changes in project and invalidates cached runtime data and catalogs + - data is not copied into StreamingAssets folder when running fast or virtual mode + - added external AssetEntry collections for use by packages + - modifying large number of asset entries on the UI is no longer unresponsive + - added an option to search the asset list in a hierarchical fashion. Helps track down which group an asset is in. + - many small bug fixes. + +## [0.0.22-preview] - 2018-05-03 + - dependency update. + +## [0.0.21-preview] - 2018-05-03 + - fixed build-time object deletion bug. + +## [0.0.20-preview] - 2018-05-02 + - Added support for extracting Built-In Shaders to a common bundle + - Added build task for generating extra data for sprite loading edge case + - fix build related bugs introduced in 0.0.19. + +## [0.0.19-preview] - 2018-05-01 + - Complete UI rework. + - Moved all functionality to one tab + - Preview is a toggle to view in-line. + - Profiles are edied from second window (this part is somewhat placeholder pending a better setup) + - Dependency updates + - Minor cleanup to build scripts + +## [0.0.18-preview] - 2018-04-13 + - minor bug fixes + - exposed memory cache parameters to build settings, changed defaults to use LRU and timed releases to make preloading dependencies more effective + +## [0.0.17-preview] - 2018-04-13 + - added tests + - fixed bugs + - major API rewrite + - all API that deals with addresses or keys have been moved to Addressables + - LoadDependencies APIs moved to Addressables + - Async suffix removed from all Load APIs + +## [0.0.16-preview] - 2018-04-04 +- added BuildResult and callback for BuildScript +- added validation of instance to scene and scene to instance maps to help debug instances that change scenes and have not been updated +- added ResourceManager.RecordInstanceSceneChange() method to allow RM to track when an instance is moved to another scene +- moved variable expansion of location data to startup + +## [0.0.15-preview] - 2018-03-28 +- fixed scene unloading +- release all instances when a scene unloads that contains unreleased instances +- fixed overflow error in virtual mode load speeds + +## [0.0.14-preview] - 2018-03-20 +- Updated dependencies + + +## [0.0.12-preview] - 2018-03-20 +- Minor UI updates +- doc updates +- fixed bug involving caching of "all assets" +- improved error checking & logging +- minor bug fixes. + +## [0.0.8-preview] - 2018-02-08 +- Initial submission for package distribution + + diff --git a/CHANGELOG.md.meta b/CHANGELOG.md.meta index d3e2a8c2..25f479f7 100644 --- a/CHANGELOG.md.meta +++ b/CHANGELOG.md.meta @@ -1,7 +1,7 @@ -fileFormatVersion: 2 -guid: 6f6c277bb5d2a164e8c95a7f0754c0f6 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 6f6c277bb5d2a164e8c95a7f0754c0f6 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Documentation~/AddressableAssetSettings.md b/Documentation~/AddressableAssetSettings.md index f972c4fa..1237683e 100644 --- a/Documentation~/AddressableAssetSettings.md +++ b/Documentation~/AddressableAssetSettings.md @@ -1,130 +1,132 @@ ---- -uid: addressables-asset-settings ---- - -# Addressable Asset Settings reference - -To manage how Addressable assets work in your project, use the **Addressable Asset Settings** Inspector. To open this Inspector, go to **Window** > **Asset Management** > **Addressables** > **Settings**. - -The Addressables system stores the settings asset in the `AddressableSettingsData` folder in the project's `Assets` folder. If this folder doesn't exist yet, you must initialize the Addressables system from the [Groups window](xref:addressables-groups-window) (menu: **Window** > **Asset Management** > **Addressables** > **Groups**). - -![](images/addressable-assets-settings.png)
*The Addressable Asset Settings Inspector* - -The Inspector contains the following sections: - -* [Profile](#profile) -* [Diagnostics](#diagnostics) -* [Catalog](#catalog) -* [Update a Previous Build](#update-a-previous-build) -* [Downloads](#downloads) -* [Build](#build) -* [Build and Play Mode Scripts](#build-and-play-mode-scripts) -* [Asset Group Templates](#asset-group-templates) -* [Initialization object list](#initialization-object-list) -* [Cloud Content Delivery](#cloud-content-delivery) - -To open the [Groups window](xref:addressables-groups-window), select __Manage Groups__. - -## Profile - -|**Property**|**Description**| -|---|---| -|**Profile In Use**|Choose the active profile, which determines the value of the variables that the Addressables build scripts use. For more information, refer to the [Profiles](xref:addressables-profiles) documentation.| -|**Manage Profiles**|Opens the [Profiles](xref:addressables-profiles) window| - -## Diagnostics - -|**Property**|**Description**| -|---|---| -| __Log Runtime Exceptions__| Enable this property to log runtime exceptions for asset loading operations and record the error to the [`AsyncOperationHandle.OperationException`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.OperationException) property. | - -By default, Addressable Assets only logs warnings and errors. To enable detailed logging, open the **Player** settings window (menu: **Edit** > **Project Settings** > **Player**), go to **Other Settings** > **Configuration** section, and add `ADDRESSABLES_LOG_ALL` to the **Scripting Define Symbols** field. - -## Catalog - -|**Property**||**Description**| -|---|---|---| -| __Player Version Override__|| Overrides the timestamp used to create the remote catalog name. If set, the remote catalog is named, `Catalog_.json`. If left blank, then Unity uses the timestamp.

If you use a unique remote catalog name for every new build, you can host multiple versions of your content at the same base URL. If you use the same override string for every build, then all players load the new catalog. Player update builds also always use the same remote catalog name as the build they're updating. For more information, refer to [Content update builds](xref:addressables-content-update-builds). | -| __Compress Local Catalog__|| Enable this property to build the catalog in a compressed AssetBundle file. This property reduces the storage size of the catalog, but increases the time to build and to load the catalog. | -| __Build Remote Catalog__|| Enable this property to create a copy of the content catalog for storage on a remote server. to build a remote catalog. When you enable this property the following options are available: | -| | __Build & Load Paths__| Set where to build and load the remote catalog. Choose a Profile path pair from the list or select `` if you want to set the build and load paths separately.| -| | __Build Path__| Only displayed if you set __Build & Load Paths__ to ``. Set where to build the remote catalog. Typically, you should use the __RemoteBuildPath__ Profile variable.| -| | __Load Path__| Only displayed if you set __Build & Load Paths__ to ``. Set the URL at which to access the remote catalog. Typically, you should use the __RemoteLoadPath__ Profile variable.| -|__Only update catalogs manually__|| Enable this property to disable the automatic check for an updated remote catalog when the Addressables system initializes at runtime. You can manually [check for an updated catalog](xref:addressables-api-load-content-catalog-async).| - -## Update a Previous Build - -To use the properties in the **Update a Previous Build** section, you must enable the __Build Remote Catalog__ property. - -|**Property**|**Description**| -|---|---| -|**Check for Update Issues**|Choose whether to perform a [content update restriction](ContentUpdateWorkflow.md) as part of the update, and how to handle the result.| -|__Content State Build Path__|Set where to build the content state file that the default build script builds.| - -## Downloads - -|**Property**|**Description**| -|---|---| -| __Custom certificate handler__| Set the class to use for custom certificate handling. The list has all classes in the project that extend [`UnityEngine.Networking.CertificateHandler`](xref:UnityEngine.Networking.CertificateHandler). | -| __Max Concurrent Web Requests__| Set the maximum amount of concurrent web requests. The system queues any requests beyond this limit. 2 to 4 concurrent downloads are recommended to reach the best download speeds. | -| __Catalog Download Timeout__ | Set how many seconds to wait for a catalog file to download. If you set this to 0 there will be no timeout.| - -## Build - -|**Property**||**Description**| -|---|---|---| -| **Build Addressables on Player Build** || Select how Unity builds Addressables content as part of the Player build.

The __Build Addressables content on Player Build__ and __Do not Build Addressables content on Player Build__ properties override the global Preference for the current project and affect all contributors who build the Project. Otherwise, the global Preferences value applies to all Unity projects. Refer to [Building content](BuildingContent.md) for more information.| -|| __Build Addressables content on Player Build__| Always build Addressables content when building the Player.| -||__Do not Build Addressables content on Player Build__| Never build Addressables content when building the Player. If you modify Addressables content, you must rebuild it manually before building the Player.| -|| __Use global Settings (stored in preferences)__| Use the value specified in the [Unity Editor Preferences](addressables-preferences.md) under __Addressables__.| -| __Ignore Invalid/Unsupported Files in Build__|| Enable this property to exclude invalid or unsupported files from the build script rather than aborting the build. | -| __Unique Bundle IDs__|| Enable this property to make a unique name for a bundle in every build. Refer to [Unique Bundle IDs](xref:addressables-content-update-builds) for more information. | -| __Contiguous Bundles__|| Enable this property to produce a more efficient bundle layout. If you have bundles produced by Addressables 1.12.1 or earlier, disable this property to minimize bundle changes. | -| __Non-Recursive Dependency Calculation__ || Enable this property to improve build times and reduce runtime memory overhead when assets have circular dependencies.

For example, A prefab assigned to Bundle A references a material assigned to Bundle B. If this property is disabled, Unity needs to calculate the material's dependencies twice, once for each bundle. If this option is enabled, Unity only needs to calculate the material's dependencies once, for Bundle B.

In an example where many scenes reference the same material, if this property is disabled, Unity opens each scene to calculate shader usage, which is a costly operation. If this property is enabled, Unity only loads the material and doesn't need to open any scenes for dependency calculation.

This option is enabled by default when using Unity version 2021.2 or later. Disabling this option invalidates previously built bundles because the rebuilt bundles have a different build layout. Therefore, leave this property enabled unless you've shipped a build.

Some circular dependencies might fail to load when the option is enabled because the referenced asset is always assigned to the same bundle location, even when more content is added to the build. This issue often occurs for Monoscripts. Building the MonoScript bundle can help resolve these load failures. | -| __Shader Bundle Naming Prefix__ || Choose how to name the bundle produced for Unity shaders. | -| __MonoScript Bundle Naming Prefix__ || Choose how to name the bundle that contains all MonoScripts. The bundle ensures that Unity loads all Monoscripts before any MonoBehaviours can reference them. It also decreases the number of duplicated or complex Monoscript dependencies and so, reduces runtime memory overhead. | -| __Strip Unity Version From AssetBundles__ || Enable this property to remove the Unity version from the bundle header. | -| __Disable Visible Sub Asset Representations__ || Enable this property to improve build times if you don't use sub-objects directly (such as sprites, or sub-meshes). | - -## Build and Play Mode Scripts - -Configures the [`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder) scripts available in the project. If you create a custom Build or Play mode script, you must add it to this list before you can use it. - -The Addressables packages has some default build scripts that handle the default build processes and offer different ways to access data in Play mode. You can find these scripts in the `AddressableAssetData/DataBuilders` folder. - -> [!NOTE] -> Build and Play mode scripts are `ScriptableObject` assets. To create a ScriptableObject asset for a Build or Play mode script, follow the instructions in the [ScriptableObject manual page](xref:class-ScriptableObject). - -To add a custom script, select the __+__ button and choose the ScriptableObject asset which represents the desired script from the file panel. - -Refer to [Custom Build Scripting](xref:addressables-api-build-player-content) for more information about custom scripts. - -## Asset Group Templates - -Defines the list of templates that you can use to create new groups. When you create a new template, you must add it to this list before you can use it. - -The Addressables package has one template that includes the schemas that the default build scripts uses. You can find the template in the `AddressableAssetData/AssetGroupTemplates` folder. - -> [!NOTE] -> Group templates are ScriptableObject assets. To create a ScriptableObject asset for a group template, follow the instructions in the [ScriptableObject manual page](xref:class-ScriptableObject). - -To add a custom template, select the __+__ button and choose the ScriptableObject asset which represents the desired template from the file panel. - -Refer to [Group templates](xref:group-templates) for information on creating custom templates. - -## Initialization object list - -Configures the initialization objects for the project. Initialization objects are ScriptableObject classes that implement the [`IObjectInitializationDataProvider`](xref:UnityEngine.ResourceManagement.Util.IObjectInitializationDataProvider) interface. You can create these objects to pass data to the Addressables initialization process at runtime. - -> [!NOTE] -> Initialization objects are ScriptableObject assets. To create a ScriptableObject asset for an initialization object, follow the instructions in the [ScriptableObject manual page](xref:class-ScriptableObject). - -To add an initialization object, select the __+__ button and choose the ScriptableObject asset which represents the desired object from the file panel. - -Refer to [Customizing initialization](xref:addressables-api-initialize-async) for more information. - -## Cloud Content Delivery - -|**Property**|**Description**| -|---|---| -|**Enable Experimental CCD Features**|Enable this property to enable experimental [CCD features](AddressablesCCD.md).| \ No newline at end of file +--- +uid: addressables-asset-settings +--- + +# Addressable Asset Settings reference + +To manage how Addressable assets work in your project, use the **Addressable Asset Settings** Inspector. To open this Inspector, go to **Window** > **Asset Management** > **Addressables** > **Settings**. + +The Addressables system stores the settings asset in the `AddressableSettingsData` folder in the project's `Assets` folder. If this folder doesn't exist yet, you must initialize the Addressables system from the [Groups window](xref:addressables-groups-window) (menu: **Window** > **Asset Management** > **Addressables** > **Groups**). + +![](images/addressable-assets-settings.png)
*The Addressable Asset Settings Inspector* + +The Inspector contains the following sections: + +* [Profile](#profile) +* [Diagnostics](#diagnostics) +* [Catalog](#catalog) +* [Update a Previous Build](#update-a-previous-build) +* [Downloads](#downloads) +* [Build](#build) +* [Build and Play Mode Scripts](#build-and-play-mode-scripts) +* [Asset Group Templates](#asset-group-templates) +* [Initialization object list](#initialization-object-list) +* [Cloud Content Delivery](#cloud-content-delivery) + +To open the [Groups window](xref:addressables-groups-window), select __Manage Groups__. + +## Profile + +|**Property**|**Description**| +|---|---| +|**Profile In Use**|Choose the active profile, which determines the value of the variables that the Addressables build scripts use. For more information, refer to the [Profiles](xref:addressables-profiles) documentation.| +|**Manage Profiles**|Opens the [Profiles](xref:addressables-profiles) window| + +## Diagnostics + +|**Property**|**Description**| +|---|---| +| __Log Runtime Exceptions__| Enable this property to log runtime exceptions for asset loading operations and record the error to the [`AsyncOperationHandle.OperationException`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.OperationException) property. | + +By default, Addressable Assets only logs warnings and errors. To enable detailed logging, open the **Player** settings window (menu: **Edit** > **Project Settings** > **Player**), go to **Other Settings** > **Configuration** section, and add `ADDRESSABLES_LOG_ALL` to the **Scripting Define Symbols** field. + +## Catalog + +|**Property**||**Description**| +|---|---|---| +| __Player Version Override__|| Overrides the timestamp used to create the remote catalog name. If set, the remote catalog is named, `Catalog_.json`. If left blank, then Unity uses the timestamp.

If you use a unique remote catalog name for every new build, you can host multiple versions of your content at the same base URL. If you use the same override string for every build, then all players load the new catalog. Player update builds also always use the same remote catalog name as the build they're updating. For more information, refer to [Content update builds](xref:addressables-content-update-builds). | +| __Compress Local Catalog__|| Enable this property to build the catalog in a compressed AssetBundle file. This property reduces the storage size of the catalog, but increases the time to build and to load the catalog. | +| __Build Remote Catalog__|| Enable this property to create a copy of the content catalog for storage on a remote server. to build a remote catalog. When you enable this property the following options are available: | +| | __Build & Load Paths__| Set where to build and load the remote catalog. Choose a Profile path pair from the list or select `` if you want to set the build and load paths separately.| +| | __Build Path__| Only displayed if you set __Build & Load Paths__ to ``. Set where to build the remote catalog. Typically, you should use the __RemoteBuildPath__ Profile variable.| +| | __Load Path__| Only displayed if you set __Build & Load Paths__ to ``. Set the URL at which to access the remote catalog. Typically, you should use the __RemoteLoadPath__ Profile variable.| +|__Only update catalogs manually__|| Enable this property to disable the automatic check for an updated remote catalog when the Addressables system initializes at runtime. You can manually [check for an updated catalog](xref:addressables-api-load-content-catalog-async).| + +## Update a Previous Build + +To use the properties in the **Update a Previous Build** section, you must enable the __Build Remote Catalog__ property. + +|**Property**|**Description**| +|---|---| +|**Check for Update Issues**|Choose whether to perform a [content update restriction](ContentUpdateWorkflow.md) as part of the update, and how to handle the result.| +|__Content State Build Path__|Set where to build the content state file that the default build script builds.| + +## Downloads + +|**Property**|**Description**| +|---|---| +| __Custom certificate handler__| Set the class to use for custom certificate handling. The list has all classes in the project that extend [`UnityEngine.Networking.CertificateHandler`](xref:UnityEngine.Networking.CertificateHandler). | +| __Max Concurrent Web Requests__| Set the maximum amount of concurrent web requests. The system queues any requests beyond this limit. 2 to 4 concurrent downloads are recommended to reach the best download speeds. | +| __Catalog Download Timeout__ | Set how many seconds to wait for a catalog file to download. If you set this to 0 there will be no timeout.| + +## Build + +|**Property**||**Description**| +|---|---|---| +| **Build Addressables on Player Build** || Select how Unity builds Addressables content as part of the Player build.

The __Build Addressables content on Player Build__ and __Do not Build Addressables content on Player Build__ properties override the global Preference for the current project and affect all contributors who build the Project. Otherwise, the global Preferences value applies to all Unity projects. Refer to [Building content](BuildingContent.md) for more information.| +|| __Build Addressables content on Player Build__| Always build Addressables content when building the Player.| +||__Do not Build Addressables content on Player Build__| Never build Addressables content when building the Player. If you modify Addressables content, you must rebuild it manually before building the Player.| +|| __Use global Settings (stored in preferences)__| Use the value specified in the [Unity Editor Preferences](addressables-preferences.md) under __Addressables__.| +| __Ignore Invalid/Unsupported Files in Build__|| Enable this property to exclude invalid or unsupported files from the build script rather than aborting the build. | +| __Unique Bundle IDs__|| Enable this property to make a unique name for a bundle in every build. Refer to [Unique Bundle IDs](xref:addressables-content-update-builds) for more information. | +| __Contiguous Bundles__|| Enable this property to produce a more efficient bundle layout. If you have bundles produced by Addressables 1.12.1 or earlier, disable this property to minimize bundle changes. | +| __Non-Recursive Dependency Calculation__ || Enable this property to improve build times and reduce runtime memory overhead when assets have circular dependencies.

For example, A prefab assigned to Bundle A references a material assigned to Bundle B. If this property is disabled, Unity needs to calculate the material's dependencies twice, once for each bundle. If this option is enabled, Unity only needs to calculate the material's dependencies once, for Bundle B.

In an example where many scenes reference the same material, if this property is disabled, Unity opens each scene to calculate shader usage, which is a costly operation. If this property is enabled, Unity only loads the material and doesn't need to open any scenes for dependency calculation.

This option is enabled by default when using Unity version 2021.2 or later. Disabling this option invalidates previously built bundles because the rebuilt bundles have a different build layout. Therefore, leave this property enabled unless you've shipped a build.

Some circular dependencies might fail to load when the option is enabled because the referenced asset is always assigned to the same bundle location, even when more content is added to the build. This issue often occurs for Monoscripts. Building the MonoScript bundle can help resolve these load failures. | +| __Shader Bundle Naming Prefix__ || Choose how to name the bundle produced for Unity shaders. | +| __MonoScript Bundle Naming Prefix__ || Choose how to name the bundle that contains all MonoScripts. The bundle ensures that Unity loads all Monoscripts before any MonoBehaviours can reference them. It also decreases the number of duplicated or complex Monoscript dependencies and so, reduces runtime memory overhead. | +| __Strip Unity Version From AssetBundles__ || Enable this property to remove the Unity version from the bundle header. | +| __Disable Visible Sub Asset Representations__ || Enable this property to improve build times if you don't use sub-objects directly (such as sprites, or sub-meshes). | + +## Build and Play Mode Scripts + +Configures the [`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder) scripts available in the project. If you create a custom Build or Play mode script, you must add it to this list before you can use it. + +The Addressables packages has some default build scripts that handle the default build processes and offer different ways to access data in Play mode. You can find these scripts in the `AddressableAssetData/DataBuilders` folder. + +> [!NOTE] +> Build and Play mode scripts are `ScriptableObject` assets. To create a ScriptableObject asset for a Build or Play mode script, follow the instructions in the [ScriptableObject manual page](xref:class-ScriptableObject). + +To add a custom script, select the __+__ button and choose the ScriptableObject asset which represents the desired script from the file panel. + +Refer to [Custom Build Scripting](xref:addressables-api-build-player-content) for more information about custom scripts. + +## Asset Group Templates + +Defines the list of templates that you can use to create new groups. When you create a new template, you must add it to this list before you can use it. + +The Addressables package has one template that includes the schemas that the default build scripts uses. You can find the template in the `AddressableAssetData/AssetGroupTemplates` folder. + +> [!NOTE] +> Group templates are ScriptableObject assets. To create a ScriptableObject asset for a group template, follow the instructions in the [ScriptableObject manual page](xref:class-ScriptableObject). + +To add a custom template, select the __+__ button and choose the ScriptableObject asset which represents the desired template from the file panel. + +Refer to [Group templates](xref:group-templates) for information on creating custom templates. + +## Initialization object list + +Configures the initialization objects for the project. Initialization objects are ScriptableObject classes that implement the [`IObjectInitializationDataProvider`](xref:UnityEngine.ResourceManagement.Util.IObjectInitializationDataProvider) interface. You can create these objects to pass data to the Addressables initialization process at runtime. + +> [!NOTE] +> Initialization objects are ScriptableObject assets. To create a ScriptableObject asset for an initialization object, follow the instructions in the [ScriptableObject manual page](xref:class-ScriptableObject). + +To add an initialization object, select the __+__ button and choose the ScriptableObject asset which represents the desired object from the file panel. + +Refer to [Customizing initialization](xref:addressables-api-initialize-async) for more information. + +## Cloud Content Delivery + +| **Property** | **Description** | +|------------------------------|-----------------------------------------------------------------------------------------------------------| +| **Enable CCD Features** | Enable this property to enable [CCD features](AddressablesCCD.md). | +| **Log HTTP Requests** | Enable this property to log http requests to the CCD Management API. | +| **Log HTTP Request Headers** | Enable this property to additionally log request headers when logging requests to the CCD Management API. | diff --git a/Documentation~/AddressableAssetsAsyncOperationHandle.md b/Documentation~/AddressableAssetsAsyncOperationHandle.md index a21a53bf..48c58391 100644 --- a/Documentation~/AddressableAssetsAsyncOperationHandle.md +++ b/Documentation~/AddressableAssetsAsyncOperationHandle.md @@ -1,126 +1,126 @@ ---- -uid: addressables-async-operation-handling ---- -# Asynchronous operation handles - -Many tasks in the Addressables need to load or download information before they can return a result. To avoid blocking program execution, Addressables implements such tasks as asynchronous operations. - -In contrast to a [synchronous operation](SynchronousAddressables.md), which doesn’t return control until the result is available, an asynchronous operation returns control to the calling method almost immediately. However, the results might not be available until some time in the future. - -When you call a method, such as [`LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetAsync*), it doesn't return the loaded assets directly. Instead, it returns an [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) object, which you can use to access the loaded assets when they become available. - -You can use the following techniques to wait for the results of an asynchronous operation while allowing other scripts to continue processing: - -* [Coroutines and `IEnumerator` loops](#coroutine-and-ienumerator-operation-handling) -* [Event based operation handling](#event-based-operation-handling) -* [Task based operation handling](#task-based-operation-handling) - -> [!NOTE] -> You can block the current thread to wait for the completion of an asynchronous operation. Doing so can introduce performance problems and frame rate hitches. Refer to [Using operations synchronously](#use-operations-synchronously) for more information. - -## Release AsyncOperationHandle instances - -Methods like [`LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*) return [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) instances that give the results of the operation and a way to release both the results and the operation object itself. - -You must keep the handle object for as long as you want to use the results. Depending on the situation, that might be one frame, until the end of a level, or even the lifetime of the application. Use the [`Addressables.Release`](xref:UnityEngine.AddressableAssets.Addressables.Release*) method to release operation handles and any associated Addressable assets. - -Releasing an operation handle decrements the reference count of any assets loaded by the operation and invalidates the operation handle object itself. Refer to [Memory management](MemoryManagement.md) for more information about reference counting in the Addressables system. - -If you don’t need to use the results of an operation beyond a limited scope, you can release the handles immediately. Some Addressables methods, such as [`UnloadSceneAsync`](xref:UnityEngine.AddressableAssets.Addressables.UnloadSceneAsync*) allow you to automatically release the operation handle when it's complete. - -If an operation is unsuccessful, you should still release the operation handle. Addressables releases any assets that it loaded during a failed operation, but releasing the handle still clears the handle’s instance data. Some methods which load multiple assets, like [`LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*), give you the option to either keep any assets that it loaded, or to fail and release everything if any part of the load operation failed. - -## Coroutine and IEnumerator operation handling - -[`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) implements the [`IEnumerator`](xref:System.Collections.IEnumerator) interface and continues iteration until the operation is complete. - -In a coroutine, you can yield the operation handle to wait for the next iteration. When complete, the execution flow continues to the following statements. You can implement the [MonoBehaviour `Start`](https://docs.unity3d.com/ScriptReference/MonoBehaviour.Start.html) method as a coroutine, which is a good way to have a GameObject load and instantiate the assets it needs. - -The following script loads a prefab as a child of its GameObject using a `Start` method in a coroutine. It yields the `AsyncOperationHandle` until the operation finishes and then uses the same handle to instantiate the prefab. - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithIEnumerator.cs#doc_LoadWithIEnumerator)] - -You can't cancel [`Addressables.LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*) once started. However, releasing the handle before it has finished decrements the handle reference count and automatically releases it when the load is complete. - -Refer to the Unity User Manual documentation on [Coroutines](xref:Coroutines) for more information. - -### Group operations in a coroutine - -To perform several operations before moving on to the next step in your game logic, such as to load prefabs and other assets before you start a level, you can combine them with a single call to the [`Addressables.LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*) method, if all the operations load assets. - -The `AsyncOperationHandle` for this method works the same as [`LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetAsync*). You can yield the handle in a coroutine to wait until all the assets in the operation load. You can also pass a callback method to `LoadAssetsAsync` and the operation calls that method when it finishes loading a specific asset. Refer to [Loading multiple assets](load-assets.md#load-multiple-assets) for an example. - -You can also use the [`ResourceManager.CreateGenericGroupOperation`](xref:UnityEngine.ResourceManagement.ResourceManager.CreateGenericGroupOperation*) to create a group operation that completes when all its members finish. - -## Event based operation handling - -You can add a delegate function to the [`Completed`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) event of an [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle). The operation calls the delegate function when it's finished. - -The following script performs the same function as the example in [coroutine and IEnumerator operation handling](#coroutine-and-ienumerator-operation-handling), but uses an event delegate instead of a coroutine: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithEvent.cs#doc_LoadWithEvent)] - -The handle instance passed to the event delegate is the same as that returned by the original method call. You can use either to access the results and status of the operation and to release the operation handle and loaded assets. - -## Task-based operation handling - -[`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) provides a [`Task`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Task) object that you can use with the C# `async` and `await` keywords to sequence code that calls asynchronous methods and handles the results. - -The following example loads Addressable assets using a list of keys. The differences between this task-based approach and the coroutine or event-based approaches are in the signature of the calling method. This method must include the `async` keyword and use of the `await` keyword with the operation handle’s `Task` property. The calling method, `Start` in this case, suspends operation while the task finishes. Execution then resumes and the example instantiates all the loaded prefabs in a grid pattern. - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithTask.cs#doc_LoadWithTask)] - -> [!IMPORTANT] -> The [`AsyncOperationHandle.Task`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Task) property isn't available on the WebGL platform, which doesn't support multitasking. - -When you use `Task`-based operation handling, you can use the C# `Task` class methods such as [`WhenAll`](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.whenall) to control which operations you run in parallel and which you want to run in sequence. The following example illustrates how to wait for more than one operation to finish before moving onto the next task: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithTask.cs#doc_useWhenAll)] - -## Use operations synchronously - -You can wait for an operation to finish without yielding, waiting for an event, or using `async await` by calling an operation’s [`WaitForCompletion`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.WaitForCompletion*) method. This method blocks the current program execution thread while it waits for the operation to finish before continuing in the current scope. - -Avoid calling `WaitForCompletion` on operations that can take a significant amount of time, such as those that must download data. Calling `WaitForCompletion` can cause frame hitches and interrupt UI responsiveness. - -The following example loads a prefab asset by address, waits for the operation to complete, and then instantiates the prefab: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadSynchronously.cs#doc_LoadSynchronously)] - -## Custom operations - -To create a custom operation, extend the [`AsyncOperationBase`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1) class and override its virtual methods. - -You can pass the derived operation to the [`ResourceManager.StartOperation`](xref:UnityEngine.ResourceManagement.ResourceManager.StartOperation*) method to start the operation and receive an [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) struct. The [`ResourceManager`](xref:UnityEngine.ResourceManagement.ResourceManager) registers operations started this way. - -### Execute a custom operation - -The [`ResourceManager`](xref:UnityEngine.ResourceManagement.ResourceManager) invokes the [`AsyncOperationBase.Execute`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1.Execute*) method for the custom operation once the optional dependent operation completes. - -### Completion handling - -When the custom operation completes, call [`AsyncOperationBase.Complete`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1.Complete*) on the custom operation object. You can call this in the [`Execute`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1.Execute*) method or defer it to outside the call. `AsyncOperationBase.Complete` notifies the `ResourceManager` that the operation has finished. `The ResourceManager` invokes the associated [`AsyncOperationHandle.Completed`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) events for the relevant instances of the custom operation. - -### Terminate the custom operation - -`ResourceManager` invokes the [`AsyncOperationBase.Destroy`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1.Destroy*) method for your custom operation when the operation [`AsyncOperationBase.ReferenceCount`]( xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1.DecrementReferenceCount*) reaches zero. `AsyncOperationBase.ReferenceCount` is decreased when the [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) that references it is released using [`Addressables.Release`](xref:UnityEngine.AddressableAssets.Addressables.Release*) or when [`AsyncOperationBase.DecrementReferenceCount`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1.DecrementReferenceCount*) is called by a custom operation internally. `AsyncOperationBase.Destroy` is where you should release any memory or resources associated with your custom operation. - - -## Typed and typeless operation handles - -Most `Addressables` methods that start an operation return a generic [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle`1) struct, allowing type safety for the [`AsyncOperationHandle.Completed`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) event and for the [`AsyncOperationHandle.Result`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Result) object. You can also use a non-generic [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) struct and convert between the two handle types as desired. - -A runtime exception happens if you try to cast a non-generic handle to a generic handle of a wrong type. For example: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/OperationHandleTypes.cs#doc_ConvertTypes)] - -## Report operation progress - -`AsyncOperationHandle` has the following methods that you can use to monitor and report the progress of the operation: - -* [`GetDownloadStatus`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.GetDownloadStatus*): Returns a [`DownloadStatus`](xref:UnityEngine.ResourceManagement.AsyncOperations.DownloadStatus) struct. This struct contains information about how many bytes have been downloaded and how many bytes still need to be downloaded. [`DownloadStatus.Percent`](xref:UnityEngine.ResourceManagement.AsyncOperations.DownloadStatus.Percent) reports the percentage of bytes downloaded. -* [`AsyncOperationHandle.PercentComplete`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.PercentComplete): Returns an equally weighted total percentage of all the sub-operations that are complete. For example, if an operation has five sub-operations, each of them represents 20% of the total. The value doesn't factor in the amount of data that must be downloaded by the individual sub-operations. - -For example, if you call [`Addressables.DownloadDependenciesAsync`](xref:UnityEngine.AddressableAssets.Addressables.DownloadDependenciesAsync*) and five AssetBundles need to be downloaded, `GetDownloadStatus` tells you what percentage of the total number of bytes for all sub-operations has been downloaded. `PercentComplete` tells you what percentage of the number of operations had finished, regardless of their size. - +--- +uid: addressables-async-operation-handling +--- +# Asynchronous operation handles + +Many tasks in the Addressables need to load or download information before they can return a result. To avoid blocking program execution, Addressables implements such tasks as asynchronous operations. + +In contrast to a [synchronous operation](SynchronousAddressables.md), which doesn’t return control until the result is available, an asynchronous operation returns control to the calling method almost immediately. However, the results might not be available until some time in the future. + +When you call a method, such as [`LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetAsync*), it doesn't return the loaded assets directly. Instead, it returns an [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) object, which you can use to access the loaded assets when they become available. + +You can use the following techniques to wait for the results of an asynchronous operation while allowing other scripts to continue processing: + +* [Coroutines and `IEnumerator` loops](#coroutine-and-ienumerator-operation-handling) +* [Event based operation handling](#event-based-operation-handling) +* [Task based operation handling](#task-based-operation-handling) + +> [!NOTE] +> You can block the current thread to wait for the completion of an asynchronous operation. Doing so can introduce performance problems and frame rate hitches. Refer to [Using operations synchronously](#use-operations-synchronously) for more information. + +## Release AsyncOperationHandle instances + +Methods like [`LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*) return [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) instances that give the results of the operation and a way to release both the results and the operation object itself. + +You must keep the handle object for as long as you want to use the results. Depending on the situation, that might be one frame, until the end of a level, or even the lifetime of the application. Use the [`Addressables.Release`](xref:UnityEngine.AddressableAssets.Addressables.Release*) method to release operation handles and any associated Addressable assets. + +Releasing an operation handle decrements the reference count of any assets loaded by the operation and invalidates the operation handle object itself. Refer to [Memory management](MemoryManagement.md) for more information about reference counting in the Addressables system. + +If you don’t need to use the results of an operation beyond a limited scope, you can release the handles immediately. Some Addressables methods, such as [`UnloadSceneAsync`](xref:UnityEngine.AddressableAssets.Addressables.UnloadSceneAsync*) allow you to automatically release the operation handle when it's complete. + +If an operation is unsuccessful, you should still release the operation handle. Addressables releases any assets that it loaded during a failed operation, but releasing the handle still clears the handle’s instance data. Some methods which load multiple assets, like [`LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*), give you the option to either keep any assets that it loaded, or to fail and release everything if any part of the load operation failed. + +## Coroutine and IEnumerator operation handling + +[`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) implements the [`IEnumerator`](xref:System.Collections.IEnumerator) interface and continues iteration until the operation is complete. + +In a coroutine, you can yield the operation handle to wait for the next iteration. When complete, the execution flow continues to the following statements. You can implement the [MonoBehaviour `Start`](https://docs.unity3d.com/ScriptReference/MonoBehaviour.Start.html) method as a coroutine, which is a good way to have a GameObject load and instantiate the assets it needs. + +The following script loads a prefab as a child of its GameObject using a `Start` method in a coroutine. It yields the `AsyncOperationHandle` until the operation finishes and then uses the same handle to instantiate the prefab. + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithIEnumerator.cs#doc_LoadWithIEnumerator)] + +You can't cancel [`Addressables.LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*) once started. However, releasing the handle before it has finished decrements the handle reference count and automatically releases it when the load is complete. + +Refer to the Unity User Manual documentation on [Coroutines](xref:Coroutines) for more information. + +### Group operations in a coroutine + +To perform several operations before moving on to the next step in your game logic, such as to load prefabs and other assets before you start a level, you can combine them with a single call to the [`Addressables.LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*) method, if all the operations load assets. + +The `AsyncOperationHandle` for this method works the same as [`LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetAsync*). You can yield the handle in a coroutine to wait until all the assets in the operation load. You can also pass a callback method to `LoadAssetsAsync` and the operation calls that method when it finishes loading a specific asset. Refer to [Loading multiple assets](load-assets.md#load-multiple-assets) for an example. + +You can also use the [`ResourceManager.CreateGenericGroupOperation`](xref:UnityEngine.ResourceManagement.ResourceManager.CreateGenericGroupOperation*) to create a group operation that completes when all its members finish. + +## Event based operation handling + +You can add a delegate function to the [`Completed`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) event of an [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle). The operation calls the delegate function when it's finished. + +The following script performs the same function as the example in [coroutine and IEnumerator operation handling](#coroutine-and-ienumerator-operation-handling), but uses an event delegate instead of a coroutine: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithEvent.cs#doc_LoadWithEvent)] + +The handle instance passed to the event delegate is the same as that returned by the original method call. You can use either to access the results and status of the operation and to release the operation handle and loaded assets. + +## Task-based operation handling + +[`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) provides a [`Task`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Task) object that you can use with the C# `async` and `await` keywords to sequence code that calls asynchronous methods and handles the results. + +The following example loads Addressable assets using a list of keys. The differences between this task-based approach and the coroutine or event-based approaches are in the signature of the calling method. This method must include the `async` keyword and use of the `await` keyword with the operation handle’s `Task` property. The calling method, `Start` in this case, suspends operation while the task finishes. Execution then resumes and the example instantiates all the loaded prefabs in a grid pattern. + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithTask.cs#doc_LoadWithTask)] + +> [!IMPORTANT] +> The [`AsyncOperationHandle.Task`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Task) property isn't available on the WebGL platform, which doesn't support multitasking. + +When you use `Task`-based operation handling, you can use the C# `Task` class methods such as [`WhenAll`](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.whenall) to control which operations you run in parallel and which you want to run in sequence. The following example illustrates how to wait for more than one operation to finish before moving onto the next task: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithTask.cs#doc_useWhenAll)] + +## Use operations synchronously + +You can wait for an operation to finish without yielding, waiting for an event, or using `async await` by calling an operation’s [`WaitForCompletion`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.WaitForCompletion*) method. This method blocks the current program execution thread while it waits for the operation to finish before continuing in the current scope. + +Avoid calling `WaitForCompletion` on operations that can take a significant amount of time, such as those that must download data. Calling `WaitForCompletion` can cause frame hitches and interrupt UI responsiveness. + +The following example loads a prefab asset by address, waits for the operation to complete, and then instantiates the prefab: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadSynchronously.cs#doc_LoadSynchronously)] + +## Custom operations + +To create a custom operation, extend the [`AsyncOperationBase`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1) class and override its virtual methods. + +You can pass the derived operation to the [`ResourceManager.StartOperation`](xref:UnityEngine.ResourceManagement.ResourceManager.StartOperation*) method to start the operation and receive an [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) struct. The [`ResourceManager`](xref:UnityEngine.ResourceManagement.ResourceManager) registers operations started this way. + +### Execute a custom operation + +The [`ResourceManager`](xref:UnityEngine.ResourceManagement.ResourceManager) invokes the [`AsyncOperationBase.Execute`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1.Execute*) method for the custom operation once the optional dependent operation completes. + +### Completion handling + +When the custom operation completes, call [`AsyncOperationBase.Complete`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1.Complete*) on the custom operation object. You can call this in the [`Execute`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1.Execute*) method or defer it to outside the call. `AsyncOperationBase.Complete` notifies the `ResourceManager` that the operation has finished. `The ResourceManager` invokes the associated [`AsyncOperationHandle.Completed`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) events for the relevant instances of the custom operation. + +### Terminate the custom operation + +`ResourceManager` invokes the [`AsyncOperationBase.Destroy`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1.Destroy*) method for your custom operation when the operation [`AsyncOperationBase.ReferenceCount`]( xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1.DecrementReferenceCount*) reaches zero. `AsyncOperationBase.ReferenceCount` is decreased when the [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) that references it is released using [`Addressables.Release`](xref:UnityEngine.AddressableAssets.Addressables.Release*) or when [`AsyncOperationBase.DecrementReferenceCount`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1.DecrementReferenceCount*) is called by a custom operation internally. `AsyncOperationBase.Destroy` is where you should release any memory or resources associated with your custom operation. + + +## Typed and typeless operation handles + +Most `Addressables` methods that start an operation return a generic [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle`1) struct, allowing type safety for the [`AsyncOperationHandle.Completed`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) event and for the [`AsyncOperationHandle.Result`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Result) object. You can also use a non-generic [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) struct and convert between the two handle types as desired. + +A runtime exception happens if you try to cast a non-generic handle to a generic handle of a wrong type. For example: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/OperationHandleTypes.cs#doc_ConvertTypes)] + +## Report operation progress + +`AsyncOperationHandle` has the following methods that you can use to monitor and report the progress of the operation: + +* [`GetDownloadStatus`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.GetDownloadStatus*): Returns a [`DownloadStatus`](xref:UnityEngine.ResourceManagement.AsyncOperations.DownloadStatus) struct. This struct contains information about how many bytes have been downloaded and how many bytes still need to be downloaded. [`DownloadStatus.Percent`](xref:UnityEngine.ResourceManagement.AsyncOperations.DownloadStatus.Percent) reports the percentage of bytes downloaded. +* [`AsyncOperationHandle.PercentComplete`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.PercentComplete): Returns an equally weighted total percentage of all the sub-operations that are complete. For example, if an operation has five sub-operations, each of them represents 20% of the total. The value doesn't factor in the amount of data that must be downloaded by the individual sub-operations. + +For example, if you call [`Addressables.DownloadDependenciesAsync`](xref:UnityEngine.AddressableAssets.Addressables.DownloadDependenciesAsync*) and five AssetBundles need to be downloaded, `GetDownloadStatus` tells you what percentage of the total number of bytes for all sub-operations has been downloaded. `PercentComplete` tells you what percentage of the number of operations had finished, regardless of their size. + If you call [`LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetAsync*), and one bundle has to be downloaded before an asset can be loaded from it, the download percentage might be misleading. The values obtained from `GetDownloadStatus` reach 100% before the operation finishes, because the operation has additional sub-operations to conduct. The value of `PercentComplete` is 50% when the download sub-operation is finished and 100% when the actual load into memory is complete. \ No newline at end of file diff --git a/Documentation~/AddressableAssetsDevelopmentCycle.md b/Documentation~/AddressableAssetsDevelopmentCycle.md index 8d611978..33370d57 100644 --- a/Documentation~/AddressableAssetsDevelopmentCycle.md +++ b/Documentation~/AddressableAssetsDevelopmentCycle.md @@ -1,22 +1,22 @@ ---- -uid: addressables-assets-development-cycle ---- - -# Manage Addressables - -The main way to organize and manage addressables is to use [groups](Groups.md) and [profiles](profiles-introduction.md). This section outlines how to use these to effectively manage addressables. - - -|**Topic**|**Description**| -|---|---| -|[Manage Addressables introduction](manage-addressables-intro.md)|Understand the different ways to manage addressables in your project.| -|[Organize Addressable assets](organize-addressable-assets.md)|Understand the different approaches to organize addressable assets.| -|[Groups overview](Groups.md)|Use groups to organize the different assets in your project.| -|[Profiles overview](AddressableAssetsProfiles.md)|Use profiles to manage how to build addressable assets.| -|[Asset references overview](AssetReferences.md)| Use asset references to customize `MonoBehaviour` and `ScriptableObject` scripts.| -|[Addressables Asset Settings reference](AddressableAssetSettings.md)|Reference information for Addressable Asset Settings| -|[Addressables Preferences reference](addressables-preferences.md)|Reference information for the Addressables Preferences window.| - -## Further resources - +--- +uid: addressables-assets-development-cycle +--- + +# Manage Addressables + +The main way to organize and manage addressables is to use [groups](Groups.md) and [profiles](profiles-introduction.md). This section outlines how to use these to effectively manage addressables. + + +|**Topic**|**Description**| +|---|---| +|[Manage Addressables introduction](manage-addressables-intro.md)|Understand the different ways to manage addressables in your project.| +|[Organize Addressable assets](organize-addressable-assets.md)|Understand the different approaches to organize addressable assets.| +|[Groups overview](Groups.md)|Use groups to organize the different assets in your project.| +|[Profiles overview](AddressableAssetsProfiles.md)|Use profiles to manage how to build addressable assets.| +|[Asset references overview](AssetReferences.md)| Use asset references to customize `MonoBehaviour` and `ScriptableObject` scripts.| +|[Addressables Asset Settings reference](AddressableAssetSettings.md)|Reference information for Addressable Asset Settings| +|[Addressables Preferences reference](addressables-preferences.md)|Reference information for the Addressables Preferences window.| + +## Further resources + * [Organize Addressable assets](organize-addressable-assets.md) \ No newline at end of file diff --git a/Documentation~/AddressableAssetsGettingStarted.md b/Documentation~/AddressableAssetsGettingStarted.md index a5c1db87..fdbfdc4f 100644 --- a/Documentation~/AddressableAssetsGettingStarted.md +++ b/Documentation~/AddressableAssetsGettingStarted.md @@ -1,16 +1,16 @@ ---- -uid: addressables-getting-started ---- - -# Get started - -This section information how to set up and use Addressables for the first time. - -|**Topic**|**Description**| -|---|---| -|[Addressables overview](AddressableAssetsOverview.md)|Understand the uses of the Addressables package.| -|[Install Addressables](installation-guide.md)|Install the Addressables package.| -|[Make an asset Addressable](get-started-make-addressable.md)|Mark your assets for use by the Addressables system.| -|[Convert an existing project to use Addressables](convert-project-to-addressables.md)|Upgrade an existing project to use Addressables.| -|[Use an Addressable asset](use-addresssables-introduction.md)|Understand how to load and use Addressable assets.| +--- +uid: addressables-getting-started +--- + +# Get started + +This section information how to set up and use Addressables for the first time. + +|**Topic**|**Description**| +|---|---| +|[Addressables overview](AddressableAssetsOverview.md)|Understand the uses of the Addressables package.| +|[Install Addressables](installation-guide.md)|Install the Addressables package.| +|[Make an asset Addressable](get-started-make-addressable.md)|Mark your assets for use by the Addressables system.| +|[Convert an existing project to use Addressables](convert-project-to-addressables.md)|Upgrade an existing project to use Addressables.| +|[Use an Addressable asset](use-addresssables-introduction.md)|Understand how to load and use Addressable assets.| |[Addressables samples](SamplesOverview.md)|Information about the samples contained in the Addressables package.| \ No newline at end of file diff --git a/Documentation~/AddressableAssetsOverview.md b/Documentation~/AddressableAssetsOverview.md index e189f93f..800d34f1 100644 --- a/Documentation~/AddressableAssetsOverview.md +++ b/Documentation~/AddressableAssetsOverview.md @@ -1,130 +1,130 @@ ---- -uid: addressables-overview ---- - -# Addressables overview - -Addressables provides a system that can scale with your project. You can start with a simple setup and then reorganize as your project grows in complexity with minimal code changes. - -For example, you can start with a single group of Addressable assets, which Unity loads as a set. Then, as you add more content, you can split your assets into multiple groups so that you can load only the ones you need at a given time. As your team grows in size, you can make separate Unity projects to develop different types of assets. These auxiliary projects can produce their own Addressables content builds that you load from the main project. - -The Addressables system provides automatic dependency and memory management, efficient AssetBundle packaging and the ability to host assets either remotely or locally. Use this package to control how your applications manages, loads, and unloads assets. - -## Concepts - -This overview discusses the following concepts to help you understand how to manage and use your assets with the Addressables system: - -|**Concept**|**Description**| -|---|---| -|[Addressables tools](#addressables-tools)| The Addressables package has several windows and tools that you can use to organize, build, and optimize your content.| -|[Asset address](#asset-addresses)| A string ID that identifies an Addressable asset. You can use an address as a key to load the asset.| -|[Asset loading and unloading](#asset-loading-and-unloading)| The `Addressables` API provides its own functions to load and release assets at runtime.| -|__Asset location__| A runtime object that describes how to load an asset and its dependencies. You can use a location object as a key to load the asset.| -|[AssetReferences](#assetreference)| A type you can use to support the assignment of Addressable assets to fields in an Inspector window. You can use an AssetReference instance as a key to load the asset. The [`AssetReference`](xref:addressables-asset-references) class also provides its own loading methods.| -|[Content builds](#content-builds)| Use a content build to collate and package your assets as a separate step before you make a player build.| -|[Content catalogs](#content-catalogs)| Addressables uses catalogs to map your assets to the resources that contain them.| -|[Dependencies](#dependency-and-resource-management)| An asset dependency is one asset used by another, such as a prefab used in a scene asset or a material used in a prefab asset.| -|[Dependency and resource management](#dependency-and-resource-management)| The Addressables system uses reference counting to track which assets and AssetBundles are in use, including whether the system loads or unloads dependencies (other referenced assets).| -|[Group](#addressables-groups-and-labels)| You assign assets to groups in the Editor. The group settings configure how Addressables packages the group assets into AssetBundles and how it loads them at runtime.| -|__Key__| An object that identifies one or more Addressables. Keys include addresses, labels, AssetReference instances and location objects.| -|[Label](#addressables-groups-and-labels)| A tag that you can assign to multiple assets and use to load related assets together as a group. You can use a label as a key to load the asset.| -|__Multiple platform support__| The build system separates content built by platform and resolves the correct path at runtime.| - -By default, Addressables uses AssetBundles to package your assets. You can also implement your own [`IResourceProvider`](xref:UnityEngine.ResourceManagement.ResourceProviders.IResourceProvider) class to support other ways to access assets. - -## Asset addresses - -A key feature of the Addressables system is that you assign addresses to your assets and use those addresses to load them at runtime. The Addressables resource manager looks up the address in the content catalog to find out where the asset is stored. Assets can be built-in to your application, cached locally, or hosted remotely. The resource manager loads the asset and any dependencies, downloading the content first, if necessary. - -![](images/addressables-overview-addresses.png)
*Addressables loads Assets by address no matter where they're located* - -Because an address isn't tied to the physical location of the asset, you have several options to manage and optimize your assets, both in the Unity Editor and at runtime. [Catalogs](#content-catalogs) map addresses to physical locations. - -Although it's best practice to assign unique addresses to your assets, an asset address doesn't have to be unique. You can assign the same address string to more than one asset when useful. For example, if you have variants of an asset, you can assign the same address to all the variants and use labels to distinguish between the variants: - -* Asset 1: address: `"plate_armor_rusty"`, label: `"hd"` -* Asset 2: address: `"plate_armor_rusty"`, label: `"sd"` - -The `Addressables` API methods that only load a single asset, such as [`LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetAsync*), load the first instance found if you call them with an address assigned to multiple assets. Other methods, like [`LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*), load multiple assets in one operation and load all the assets with the specified address. - -> [!TIP] -> You can use the [`MergeMode`](xref:UnityEngine.AddressableAssets.Addressables.MergeMode) parameter of `LoadAssetsAsync` to load the intersection of two keys. -> ->In the earlier example, you can specify the address, `"plate_armor_rusty"`, and the label, `"hd"`, as keys and intersection as the merge mode to load Asset 1. You can then change the label value to `"sd"` to load Asset 2. - -For more information on how to assign addresses to assets, refer to [Making an asset Addressable](xref:addressables-getting-started). For information on how to load assets by keys, including addresses, refer to [Loading assets](xref:addressables-api-load-asset-async). - -## AssetReference - -An [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) is a type that you can set to any kind of Addressable asset. Unity doesn't automatically load the asset assigned to the reference, so you have more control over when to load and unload it. - -Use fields of type `AssetReference` in a `MonoBehaviour` or `ScriptableObject` to specify which Addressable asset to use for that field (instead of using the string that specifies the address). `AssetReferences` support drag-and-drop and object picker assignment, which makes them more convenient to use in an Editor Inspector. - -Addressables also provides a few more specialized types, such as `AssetReferenceGameObject` and `AssetReferenceTexture`. You can use these specialized subclasses to prevent the possibility of assigning the wrong asset type to an `AssetReference` field. You can also use the `AssetReferenceUILabelRestriction` attribute to limit assignment to assets with specific labels. - -Refer to [Using AssetReferences](xref:addressables-asset-references) for more information. - -## Asset loading and unloading - -To load an Addressable asset, you can use its address or other key such as a label or `AssetReference`. Refer to [Loading Addressable Assets](xref:addressables-api-load-asset-async) for more information. You only need to load the main asset and Addressables loads any dependent assets automatically. - -When your application no longer needs access to an Addressable asset at runtime, you must release it so that Addressables can free the associated memory. The Addressables system keeps a reference count of loaded assets, and doesn't unload an asset until the reference count returns to zero. As such, you don't need to keep track of whether an asset or its dependencies are still in use. You only need to make sure that any time you explicitly load an asset, you release it when your application no longer needs that instance. Refer to [Releasing Addressable assets](xref:addressables-unloading) for more information. - -## Dependency and resource management - -One asset in Unity can depend on another. A scene might reference one or more prefabs, or a prefab might use one or more materials. One or more prefabs can use the same material, and those prefabs can exist in different AssetBundles. When you load an Addressable asset, the system automatically finds and loads any dependent assets that it references. When the system unloads an asset, it also unloads its dependencies, unless a different asset is still using them. - -As you load and release assets, the Addressables system keeps a reference count for each item. When an asset is no longer referenced, Addressables unloads it. If the asset was in a bundle that no longer has any assets that are in use, Addressables also unloads the bundle. - -Refer to [Memory management](xref:addressables-memory-management) for more information. - -## Addressables groups and labels - -Use Addressables groups to organize your content. All Addressable assets belong to a group. If you don't explicitly assign an asset to a group, Addressables adds it to the default group. - -You can set the group settings to specify how the Addressables build system packages the assets in a group into bundles. For example, you can choose whether to pack all the assets in a group together in a single AssetBundle file. - -Use labels to tag content that you want to treat together in some way. For example, if you had labels defined for `red`, `hat`, and `feather`, you can load all red hats with feathers in a single operation, whether they're part of the same AssetBundle or not. You can also use labels to decide how assets in a group are packed into bundles. - -Add an asset to a group and move assets between groups using the [Addressables Groups](xref:addressables-groups-window) window. You can also assign labels to your assets in the Groups window. - -### Group schemas - -The schemas assigned to a group define the settings used to build the assets in a group. Different schemas can define different groups of settings. For example, one standard schema defines the settings for how to pack and compress your assets into AssetBundles (among other options). Another standard schema defines which of the categories, **Can Change Post Release** and **Cannot Change Post Release** the assets in the group belong to. - -You can define your own schemas to use with custom build scripts. - -Refer to [Schemas](xref:addressables-group-schemas) for more information about group schemas. - -## Content catalogs - -The Addressables system produces a content catalog file that maps the addresses of your assets to their physical locations. It can also create a hash file containing the hash of the catalog. If you're hosting your Addressable assets remotely, the system uses this hash file to decide if the content catalog has changed and needs to download it. Refer to [Content catalogs](xref:addressables-build-artifacts) for more information. - -The Profile selected when you perform a content build determines how the addresses in the content catalog map to resource loading paths. Refer to [Profiles](xref:addressables-profiles) for more information. - -For information about hosting content remotely, refer to [Distributing content remotely](xref:addressables-remote-content-distribution). - -## Content builds - -The Addressables system separates the building of Addressable content from the build of your player. A content build produces the content catalog, catalog hash, and the AssetBundles containing your assets. - -Because asset formats are platform-specific, you must make a content build for each platform before building a player. - -Refer to [Building Addressable content](xref:addressables-builds) for more information. - -## Play mode scripts - -When you run your game or application in Play mode, it can be inconvenient and slow to always perform a content build before pressing the Play button. At the same time, you want to be able to run your game in a state as close to a built player as possible. Addressables provides three options that decide how the Addressables system locates and loads assets in Play mode: - -* __Use the Asset Database__: Addressables loads assets directly from the Asset Database. This option typically provides the fastest iteration speed if you're making both code and Asset changes, but also least resembles a production build. -* __Use existing build__: Addressables loads content from your last content build. This option most resembles a production build and provides fast iteration turnaround if you aren't changing assets. - -Refer to [Play mode scripts](xref:addressables-groups-window) for more information. - -## Addressables tools - -The Addressables system provides the following tools and windows to help you manage your Addressable assets: - -* [Addressable Groups window](xref:addressables-groups-window): The main interface for managing assets, group settings, and making builds. -* [Profiles window](xref:addressables-profiles): Helps set up paths used by your builds. -* [Build layout report](xref:addressables-build-layout-report): Describes the AssetBundles produced by a content build. +--- +uid: addressables-overview +--- + +# Addressables overview + +Addressables provides a system that can scale with your project. You can start with a simple setup and then reorganize as your project grows in complexity with minimal code changes. + +For example, you can start with a single group of Addressable assets, which Unity loads as a set. Then, as you add more content, you can split your assets into multiple groups so that you can load only the ones you need at a given time. As your team grows in size, you can make separate Unity projects to develop different types of assets. These auxiliary projects can produce their own Addressables content builds that you load from the main project. + +The Addressables system provides automatic dependency and memory management, efficient AssetBundle packaging and the ability to host assets either remotely or locally. Use this package to control how your applications manages, loads, and unloads assets. + +## Concepts + +This overview discusses the following concepts to help you understand how to manage and use your assets with the Addressables system: + +|**Concept**|**Description**| +|---|---| +|[Addressables tools](#addressables-tools)| The Addressables package has several windows and tools that you can use to organize, build, and optimize your content.| +|[Asset address](#asset-addresses)| A string ID that identifies an Addressable asset. You can use an address as a key to load the asset.| +|[Asset loading and unloading](#asset-loading-and-unloading)| The `Addressables` API provides its own functions to load and release assets at runtime.| +|__Asset location__| A runtime object that describes how to load an asset and its dependencies. You can use a location object as a key to load the asset.| +|[AssetReferences](#assetreference)| A type you can use to support the assignment of Addressable assets to fields in an Inspector window. You can use an AssetReference instance as a key to load the asset. The [`AssetReference`](xref:addressables-asset-references) class also provides its own loading methods.| +|[Content builds](#content-builds)| Use a content build to collate and package your assets as a separate step before you make a player build.| +|[Content catalogs](#content-catalogs)| Addressables uses catalogs to map your assets to the resources that contain them.| +|[Dependencies](#dependency-and-resource-management)| An asset dependency is one asset used by another, such as a prefab used in a scene asset or a material used in a prefab asset.| +|[Dependency and resource management](#dependency-and-resource-management)| The Addressables system uses reference counting to track which assets and AssetBundles are in use, including whether the system loads or unloads dependencies (other referenced assets).| +|[Group](#addressables-groups-and-labels)| You assign assets to groups in the Editor. The group settings configure how Addressables packages the group assets into AssetBundles and how it loads them at runtime.| +|__Key__| An object that identifies one or more Addressables. Keys include addresses, labels, AssetReference instances and location objects.| +|[Label](#addressables-groups-and-labels)| A tag that you can assign to multiple assets and use to load related assets together as a group. You can use a label as a key to load the asset.| +|__Multiple platform support__| The build system separates content built by platform and resolves the correct path at runtime.| + +By default, Addressables uses AssetBundles to package your assets. You can also implement your own [`IResourceProvider`](xref:UnityEngine.ResourceManagement.ResourceProviders.IResourceProvider) class to support other ways to access assets. + +## Asset addresses + +A key feature of the Addressables system is that you assign addresses to your assets and use those addresses to load them at runtime. The Addressables resource manager looks up the address in the content catalog to find out where the asset is stored. Assets can be built-in to your application, cached locally, or hosted remotely. The resource manager loads the asset and any dependencies, downloading the content first, if necessary. + +![](images/addressables-overview-addresses.png)
*Addressables loads Assets by address no matter where they're located* + +Because an address isn't tied to the physical location of the asset, you have several options to manage and optimize your assets, both in the Unity Editor and at runtime. [Catalogs](#content-catalogs) map addresses to physical locations. + +Although it's best practice to assign unique addresses to your assets, an asset address doesn't have to be unique. You can assign the same address string to more than one asset when useful. For example, if you have variants of an asset, you can assign the same address to all the variants and use labels to distinguish between the variants: + +* Asset 1: address: `"plate_armor_rusty"`, label: `"hd"` +* Asset 2: address: `"plate_armor_rusty"`, label: `"sd"` + +The `Addressables` API methods that only load a single asset, such as [`LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetAsync*), load the first instance found if you call them with an address assigned to multiple assets. Other methods, like [`LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*), load multiple assets in one operation and load all the assets with the specified address. + +> [!TIP] +> You can use the [`MergeMode`](xref:UnityEngine.AddressableAssets.Addressables.MergeMode) parameter of `LoadAssetsAsync` to load the intersection of two keys. +> +>In the earlier example, you can specify the address, `"plate_armor_rusty"`, and the label, `"hd"`, as keys and intersection as the merge mode to load Asset 1. You can then change the label value to `"sd"` to load Asset 2. + +For more information on how to assign addresses to assets, refer to [Making an asset Addressable](xref:addressables-getting-started). For information on how to load assets by keys, including addresses, refer to [Loading assets](xref:addressables-api-load-asset-async). + +## AssetReference + +An [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) is a type that you can set to any kind of Addressable asset. Unity doesn't automatically load the asset assigned to the reference, so you have more control over when to load and unload it. + +Use fields of type `AssetReference` in a `MonoBehaviour` or `ScriptableObject` to specify which Addressable asset to use for that field (instead of using the string that specifies the address). `AssetReferences` support drag-and-drop and object picker assignment, which makes them more convenient to use in an Editor Inspector. + +Addressables also provides a few more specialized types, such as `AssetReferenceGameObject` and `AssetReferenceTexture`. You can use these specialized subclasses to prevent the possibility of assigning the wrong asset type to an `AssetReference` field. You can also use the `AssetReferenceUILabelRestriction` attribute to limit assignment to assets with specific labels. + +Refer to [Using AssetReferences](xref:addressables-asset-references) for more information. + +## Asset loading and unloading + +To load an Addressable asset, you can use its address or other key such as a label or `AssetReference`. Refer to [Loading Addressable Assets](xref:addressables-api-load-asset-async) for more information. You only need to load the main asset and Addressables loads any dependent assets automatically. + +When your application no longer needs access to an Addressable asset at runtime, you must release it so that Addressables can free the associated memory. The Addressables system keeps a reference count of loaded assets, and doesn't unload an asset until the reference count returns to zero. As such, you don't need to keep track of whether an asset or its dependencies are still in use. You only need to make sure that any time you explicitly load an asset, you release it when your application no longer needs that instance. Refer to [Releasing Addressable assets](xref:addressables-unloading) for more information. + +## Dependency and resource management + +One asset in Unity can depend on another. A scene might reference one or more prefabs, or a prefab might use one or more materials. One or more prefabs can use the same material, and those prefabs can exist in different AssetBundles. When you load an Addressable asset, the system automatically finds and loads any dependent assets that it references. When the system unloads an asset, it also unloads its dependencies, unless a different asset is still using them. + +As you load and release assets, the Addressables system keeps a reference count for each item. When an asset is no longer referenced, Addressables unloads it. If the asset was in a bundle that no longer has any assets that are in use, Addressables also unloads the bundle. + +Refer to [Memory management](xref:addressables-memory-management) for more information. + +## Addressables groups and labels + +Use Addressables groups to organize your content. All Addressable assets belong to a group. If you don't explicitly assign an asset to a group, Addressables adds it to the default group. + +You can set the group settings to specify how the Addressables build system packages the assets in a group into bundles. For example, you can choose whether to pack all the assets in a group together in a single AssetBundle file. + +Use labels to tag content that you want to treat together in some way. For example, if you had labels defined for `red`, `hat`, and `feather`, you can load all red hats with feathers in a single operation, whether they're part of the same AssetBundle or not. You can also use labels to decide how assets in a group are packed into bundles. + +Add an asset to a group and move assets between groups using the [Addressables Groups](xref:addressables-groups-window) window. You can also assign labels to your assets in the Groups window. + +### Group schemas + +The schemas assigned to a group define the settings used to build the assets in a group. Different schemas can define different groups of settings. For example, one standard schema defines the settings for how to pack and compress your assets into AssetBundles (among other options). Another standard schema defines which of the categories, **Can Change Post Release** and **Cannot Change Post Release** the assets in the group belong to. + +You can define your own schemas to use with custom build scripts. + +Refer to [Schemas](xref:addressables-group-schemas) for more information about group schemas. + +## Content catalogs + +The Addressables system produces a content catalog file that maps the addresses of your assets to their physical locations. It can also create a hash file containing the hash of the catalog. If you're hosting your Addressable assets remotely, the system uses this hash file to decide if the content catalog has changed and needs to download it. Refer to [Content catalogs](xref:addressables-build-artifacts) for more information. + +The Profile selected when you perform a content build determines how the addresses in the content catalog map to resource loading paths. Refer to [Profiles](xref:addressables-profiles) for more information. + +For information about hosting content remotely, refer to [Distributing content remotely](xref:addressables-remote-content-distribution). + +## Content builds + +The Addressables system separates the building of Addressable content from the build of your player. A content build produces the content catalog, catalog hash, and the AssetBundles containing your assets. + +Because asset formats are platform-specific, you must make a content build for each platform before building a player. + +Refer to [Building Addressable content](xref:addressables-builds) for more information. + +## Play mode scripts + +When you run your game or application in Play mode, it can be inconvenient and slow to always perform a content build before pressing the Play button. At the same time, you want to be able to run your game in a state as close to a built player as possible. Addressables provides three options that decide how the Addressables system locates and loads assets in Play mode: + +* __Use the Asset Database__: Addressables loads assets directly from the Asset Database. This option typically provides the fastest iteration speed if you're making both code and Asset changes, but also least resembles a production build. +* __Use existing build__: Addressables loads content from your last content build. This option most resembles a production build and provides fast iteration turnaround if you aren't changing assets. + +Refer to [Play mode scripts](xref:addressables-groups-window) for more information. + +## Addressables tools + +The Addressables system provides the following tools and windows to help you manage your Addressable assets: + +* [Addressable Groups window](xref:addressables-groups-window): The main interface for managing assets, group settings, and making builds. +* [Profiles window](xref:addressables-profiles): Helps set up paths used by your builds. +* [Build layout report](xref:addressables-build-layout-report): Describes the AssetBundles produced by a content build. diff --git a/Documentation~/AddressableAssetsProfiles.md b/Documentation~/AddressableAssetsProfiles.md index 33bcfbd2..1628534b 100644 --- a/Documentation~/AddressableAssetsProfiles.md +++ b/Documentation~/AddressableAssetsProfiles.md @@ -1,15 +1,15 @@ ---- -uid: addressables-profiles ---- - -# Profiles overview - -A profile contains a set of variables that the Addressables build scripts uses. You can manage profiles with the Addressables Profiles window. - -|**Topic**|**Description**| -|---|---| -|[Profiles introduction](profiles-introduction.md)|Understand profiles and how to work with them.| -|[Create a profile](profiles-create.md)|Create profiles in the Unity Editor.| -|[Profile variables overview](ProfileVariables.md)|Understand and work with profile variables.| -|[Set a build and load path](profiles-build-load-paths.md)|Select the build and load paths for an asset group based on a profile variable.| -|[Addressables Profiles window reference](addressables-profiles-window.md)| Reference information for the Addressables Profiles window.| +--- +uid: addressables-profiles +--- + +# Profiles overview + +A profile contains a set of variables that the Addressables build scripts uses. You can manage profiles with the Addressables Profiles window. + +|**Topic**|**Description**| +|---|---| +|[Profiles introduction](profiles-introduction.md)|Understand profiles and how to work with them.| +|[Create a profile](profiles-create.md)|Create profiles in the Unity Editor.| +|[Profile variables overview](ProfileVariables.md)|Understand and work with profile variables.| +|[Set a build and load path](profiles-build-load-paths.md)|Select the build and load paths for an asset group based on a profile variable.| +|[Addressables Profiles window reference](addressables-profiles-window.md)| Reference information for the Addressables Profiles window.| diff --git a/Documentation~/AddressablesAndSpriteAtlases.md b/Documentation~/AddressablesAndSpriteAtlases.md index 5eea0d7b..97298cc4 100644 --- a/Documentation~/AddressablesAndSpriteAtlases.md +++ b/Documentation~/AddressablesAndSpriteAtlases.md @@ -1,39 +1,39 @@ ---- -uid: addressables-and-sprite-atlases ---- - -# Build sprite atlases - -Some `SpriteAtlas` options can change how Unity loads sprites. This is important to consider if you want to use the **Use Asset Database** [Play mode Script](xref:addressables-groups-window). - -The following examples explain how Addressables handles a `SpriteAtlas` differently than other assets: - -## Addressable sprites - -### Sprites in separate groups - -You have three Addressable textures in three separate groups, where each texture builds to around 500KB. Because they exist in separate groups, Unity builds them into three separate AssetBundles. Each AssetBundle uses around 500KB and only contains the sprite texture and associated metadata, with no dependencies. - -### Sprites in a non-Addressable SpriteAtlas - -The three textures in the previous example are put into a non-Addressable `SpriteAtlas`. In this case, Unity still generates three AssetBundles, but they're not the same size. One of the AssetBundles contains the atlas texture and uses about 1500KB. The other two AssetBundles only contain sprite metadata and list the atlas AssetBundle as a dependency. - -Although you can't control which AssetBundle contains the texture, the process is deterministic, so the same AssetBundle contains the texture through different rebuilds. This is the main difference from the standard duplication of dependencies. The sprites are dependent on the SpriteAtlas texture to load, and yet that texture is not built into all three AssetBundles, but is instead built only into one. - -### Sprites in a SpriteAtlas AssetBundle - -This time, the `SpriteAtlas` from the previous example is marked as Addressable in its own AssetBundle. Unity now creates four AssetBundles. The three AssetBundles with the sprites are each only a few KB and have a dependency on the fourth AssetBundle, which contains the `SpriteAtlas` and is about 1500KB. If you are using 2019.4 or older, the texture itself might end up elsewhere. The three sprite AssetBundles still depend on the `SpriteAtlas` AssetBundle. However, the `SpriteAtlas` AssetBundle can only contain metadata, and the texture can be in one of the other sprite AssetBundles. - -## Addressable prefabs with sprite dependencies - -### Sprite prefabs - -You have three Addressable sprite prefabs and each prefab has a dependency on its own sprite (about 500KB). Building the three prefabs separately results in three AssetBundles of about 500KB each. - -### Sprite prefabs in a non-Addressable SpriteAtlas - -The three textures from the previous example are added to a `SpriteAtlas`, and that atlas is not marked as Addressable. In this scenario, the `SpriteAtlas` texture is duplicated. All three AssetBundles are approximately 1500KB. This is expected based on the general rules about duplication of dependencies, but goes against the behavior seen in the previous section. - -### Sprite prefabs in a SpriteAtlas AssetBundle - -The `SpriteAtlas` from the previous example is now also marked as Addressable. Conforming to the rules of explicit inclusion, the `SpriteAtlas` texture is included only in the AssetBundle containing the `SpriteAtlas`. The AssetBundles with prefabs reference this fourth AssetBundle as a dependency. This will lead to three AssetBundles of about 500KB and one of approximately 1500KB. +--- +uid: addressables-and-sprite-atlases +--- + +# Build sprite atlases + +Some `SpriteAtlas` options can change how Unity loads sprites. This is important to consider if you want to use the **Use Asset Database** [Play mode Script](xref:addressables-groups-window). + +The following examples explain how Addressables handles a `SpriteAtlas` differently than other assets: + +## Addressable sprites + +### Sprites in separate groups + +You have three Addressable textures in three separate groups, where each texture builds to around 500KB. Because they exist in separate groups, Unity builds them into three separate AssetBundles. Each AssetBundle uses around 500KB and only contains the sprite texture and associated metadata, with no dependencies. + +### Sprites in a non-Addressable SpriteAtlas + +The three textures in the previous example are put into a non-Addressable `SpriteAtlas`. In this case, Unity still generates three AssetBundles, but they're not the same size. One of the AssetBundles contains the atlas texture and uses about 1500KB. The other two AssetBundles only contain sprite metadata and list the atlas AssetBundle as a dependency. + +Although you can't control which AssetBundle contains the texture, the process is deterministic, so the same AssetBundle contains the texture through different rebuilds. This is the main difference from the standard duplication of dependencies. The sprites are dependent on the SpriteAtlas texture to load, and yet that texture is not built into all three AssetBundles, but is instead built only into one. + +### Sprites in a SpriteAtlas AssetBundle + +This time, the `SpriteAtlas` from the previous example is marked as Addressable in its own AssetBundle. Unity now creates four AssetBundles. The three AssetBundles with the sprites are each only a few KB and have a dependency on the fourth AssetBundle, which contains the `SpriteAtlas` and is about 1500KB. If you are using 2019.4 or older, the texture itself might end up elsewhere. The three sprite AssetBundles still depend on the `SpriteAtlas` AssetBundle. However, the `SpriteAtlas` AssetBundle can only contain metadata, and the texture can be in one of the other sprite AssetBundles. + +## Addressable prefabs with sprite dependencies + +### Sprite prefabs + +You have three Addressable sprite prefabs and each prefab has a dependency on its own sprite (about 500KB). Building the three prefabs separately results in three AssetBundles of about 500KB each. + +### Sprite prefabs in a non-Addressable SpriteAtlas + +The three textures from the previous example are added to a `SpriteAtlas`, and that atlas is not marked as Addressable. In this scenario, the `SpriteAtlas` texture is duplicated. All three AssetBundles are approximately 1500KB. This is expected based on the general rules about duplication of dependencies, but goes against the behavior seen in the previous section. + +### Sprite prefabs in a SpriteAtlas AssetBundle + +The `SpriteAtlas` from the previous example is now also marked as Addressable. Conforming to the rules of explicit inclusion, the `SpriteAtlas` texture is included only in the AssetBundle containing the `SpriteAtlas`. The AssetBundles with prefabs reference this fourth AssetBundle as a dependency. This will lead to three AssetBundles of about 500KB and one of approximately 1500KB. diff --git a/Documentation~/AddressablesCCD.md b/Documentation~/AddressablesCCD.md index f7faca17..f4603f88 100644 --- a/Documentation~/AddressablesCCD.md +++ b/Documentation~/AddressablesCCD.md @@ -1,131 +1,131 @@ ---- -uid: addressables-ccd ---- - -# Use Addressables with Cloud Content Delivery - -You can use Addressables in conjunction with [Unity Cloud Content Delivery](https://docs.unity.com/ccd/UnityCCD.html) (CCD) to distribute your remote Addressables content. - -To set up Addressable assets to work with CCD: -1. Configure a profile to include your CCD URL -2. Build your AssetBundles, then upload them to CCD - -## Configure a profile with CCD URL - -The `BuildPath` and `LoadPath` variables stored in [Profiles](profiles-create.md) specify where the Addressables system creates your build artifacts and where it looks for your assets at runtime. Configure the remote paths to work with CCD. Leave the local paths with their standard, default values, unless you have a specific reason to change them. - -If necessary, create a new profile for publishing builds to CCD on the [Profiles window](addressables-profiles-window.md). Configure the remote path variables in this profile to access your content at the correct URL. - -You can set the remote `BuildPath` to a convenient value. If you have multiple profiles, consider using a unique build path for each of them so that the build artifacts don't get mixed together, especially if you're hosting them from a different remote URL. - -Set the remote `LoadPath` to one of the following two paths: - -* If you publish content using a badge: - -``` - https://(ProjectID).client-api.unity3dusercontent.com/client_api/v1/environments/(EnvironmentName)/buckets/(BucketID)/release_by_badge/(BadgeName)/entry_by_path/content/?path= - -``` - -* If you publish using a release: - -``` - https://(ProjectID).client-api.unity3dusercontent.com/client_api/v1/environments/(EnvironmentName)/buckets/(BucketID)/releases/(ReleaseID)/entry_by_path/content/?path= - -``` - -* `(ProjectID)` is your CCD project's ID string -* `(EnvironmentName)` is the name of the Environment of your project -* `(BucketID)` is the Bucket ID string for a CCD bucket within your project -* `(ReleaseID)` is the ID of a specific release within a bucket -* `(BadgeName)` is the name of the specific CCD badge - -Refer to [Profiles](profiles-introduction.md) for information about how to create and edit profiles. - -> [!IMPORTANT] -> You must perform a full rebuild your Addressables content when you change the remote load path. - -### Use the Cloud Content Delivery Bundle Location option - -If your project is set up to use the CCD service, you can set the profile's remote path pair to publish content to a designated bucket and badge. - -This feature requires the Content Delivery Management API package. - -To set up a Profile variable to use the CCD bundle location: - -1. Open the Profile window (menu: __Window > Asset Management > Addressables > Profiles__). -2. Select the profile to change. -3. Change the __Remote__ variable to use the __Cloud Content Delivery__ __Bundle Location__. -4. Choose `Automatic (set using CcdManager)` or `Specify the Environment, Bucket, and Badge` option. The `CcdManager` is a static class that is used to notify Addressables which Environment, Bucket, and Badge to load from at Runtime. . - * If choosing Automatic, select the environment you wish to use. - * If choosing to specify, select the environment you wish to use -5. Choose the Bucket to use. If no buckets are present, you will be presented with a window where you can create one. -6. Choose the Badge. - -Make this the active profile when building content for delivery with CCD. - -Refer to [Profiles](profiles-introduction.md) for information about how to modify profiles. - -## Configure groups with CCD URL - -Configure groups to use __Remote__ as their __Build & Load Path__ in the Inspector window. - -Refer to [Groups](Groups.md) for information about how to modify groups. - -## Build, upload and release Addressable content - -### Use CCD Dashboard/CLI - -To generate and upload Addressable content to your CCD project: - -1. Set the profile you have set up for CCD as the active profile. -2. Build your Addressables content. - * If you are making a full content build, refer to [Building your Addressable content](builds-full-build.md). - * If your are updating an existing build with modified remote content, refer to [Building for content updates](content-update-build-create.md). -3. Upload the files created at the remote build path using the [CCD dashboard](https://docs.unity.com/ccd/Content/UnityCCDDashboard.htm) or [command-line interface](https://docs.unity.com/ccd/Content/UnityCCDCLI.htm). -4. Create a release and update the badge using the CCD dashboard or command-line interface. - -Building your Addressable content generates a content catalog (.json), a hash file (.hash), and one or more AssetBundle (.bundle) files. Upload these files to the bucket corresponding to the URL used in your profile load path. - -If you have made changes to local content, you must create a new Player build. - -### Use CCD Management package - -To generate, upload, and release Addressable content to your CCD project: - -1. Open the Groups window (menu: __Window > Asset Management > Addressables > Groups__). -2. Use the __Build & Release__ option. - -The CCD Management package will use the default build script behavior to generate the Addressable bundles. - -Then, all groups associated with a path pair that is connected to a CCD bucket and badge via the drop-down window will have their generated bundles uploaded by the management package to those remote target. - -Finally, the management package will a create release for those remote target and update their badge. - -#### CcdManager - -When setting up the project profile path pairs and utilizing CCD, there is an option to use `Automatic`. This option utilizes the `CcdManager` to set static properties at Runtime to tell Addressables which Environment, Bucket, and Badge to reach out to for loading assets. The `CcdManager` has the following properties: `EnvironmentName`, `BucketId`, and `Badge`. Setting these properties at runtime before Addressables initializes will tell Addressables to look at these locations within CCD. To learn more about environments, buckets, and badges, refer to [CCD organization](https://docs.unity.com/ccd/UnityCCD.html#CCD_organization). - -Example Snippet of setting CcdManager Properties: -```c# - CcdManager.EnvironmentName = ENV_NAME; - CcdManager.BucketId = BUCKET_ID; - CcdManager.Badge = BADGE; - - // Addressables call to load or instantiate asset -``` ->[!Note] -> ANY Addressables call initializes the system so be sure to set the `CcdManager` prior to any Addressables call to ensure that there are no race conditions or unexpected behaviors. - -## Use build events -CCD provides a means of wrapping the build and upload service to provide additional functionality. - -### Add a build event -You can add additional events to PreUpdate and PreBuild event chains. - -[!code-cs[sample](../Tests/Editor/DocExampleCode/PrintBucketInformation.cs#SAMPLE)] - -### Disable version override warnings -If you are getting warnings about overriding the player version and would like to keep your current setup, you can disable the warnings by removing the corresponding build events. - -[!code-cs[sample](../Tests/Editor/DocExampleCode/DisableBuildWarnings.cs#SAMPLE)] +--- +uid: addressables-ccd +--- + +# Use Addressables with Cloud Content Delivery + +You can use Addressables in conjunction with [Unity Cloud Content Delivery](https://docs.unity.com/ccd/UnityCCD.html) (CCD) to distribute your remote Addressables content. + +To set up Addressable assets to work with CCD: +1. Configure a profile to include your CCD URL +2. Build your AssetBundles, then upload them to CCD + +## Configure a profile with CCD URL + +The `BuildPath` and `LoadPath` variables stored in [Profiles](profiles-create.md) specify where the Addressables system creates your build artifacts and where it looks for your assets at runtime. Configure the remote paths to work with CCD. Leave the local paths with their standard, default values, unless you have a specific reason to change them. + +If necessary, create a new profile for publishing builds to CCD on the [Profiles window](addressables-profiles-window.md). Configure the remote path variables in this profile to access your content at the correct URL. + +You can set the remote `BuildPath` to a convenient value. If you have multiple profiles, consider using a unique build path for each of them so that the build artifacts don't get mixed together, especially if you're hosting them from a different remote URL. + +Set the remote `LoadPath` to one of the following two paths: + +* If you publish content using a badge: + +``` + https://(ProjectID).client-api.unity3dusercontent.com/client_api/v1/environments/(EnvironmentName)/buckets/(BucketID)/release_by_badge/(BadgeName)/entry_by_path/content/?path= + +``` + +* If you publish using a release: + +``` + https://(ProjectID).client-api.unity3dusercontent.com/client_api/v1/environments/(EnvironmentName)/buckets/(BucketID)/releases/(ReleaseID)/entry_by_path/content/?path= + +``` + +* `(ProjectID)` is your CCD project's ID string +* `(EnvironmentName)` is the name of the Environment of your project +* `(BucketID)` is the Bucket ID string for a CCD bucket within your project +* `(ReleaseID)` is the ID of a specific release within a bucket +* `(BadgeName)` is the name of the specific CCD badge + +Refer to [Profiles](profiles-introduction.md) for information about how to create and edit profiles. + +> [!IMPORTANT] +> You must perform a full rebuild your Addressables content when you change the remote load path. + +### Use the Cloud Content Delivery Bundle Location option + +If your project is set up to use the CCD service, you can set the profile's remote path pair to publish content to a designated bucket and badge. + +This feature requires the Content Delivery Management API package. + +To set up a Profile variable to use the CCD bundle location: + +1. Open the Profile window (menu: __Window > Asset Management > Addressables > Profiles__). +2. Select the profile to change. +3. Change the __Remote__ variable to use the __Cloud Content Delivery__ __Bundle Location__. +4. Choose `Automatic (set using CcdManager)` or `Specify the Environment, Bucket, and Badge` option. The `CcdManager` is a static class that is used to notify Addressables which Environment, Bucket, and Badge to load from at Runtime. . + * If choosing Automatic, select the environment you wish to use. + * If choosing to specify, select the environment you wish to use +5. Choose the Bucket to use. If no buckets are present, you will be presented with a window where you can create one. +6. Choose the Badge. + +Make this the active profile when building content for delivery with CCD. + +Refer to [Profiles](profiles-introduction.md) for information about how to modify profiles. + +## Configure groups with CCD URL + +Configure groups to use __Remote__ as their __Build & Load Path__ in the Inspector window. + +Refer to [Groups](Groups.md) for information about how to modify groups. + +## Build, upload and release Addressable content + +### Use CCD Dashboard/CLI + +To generate and upload Addressable content to your CCD project: + +1. Set the profile you have set up for CCD as the active profile. +2. Build your Addressables content. + * If you are making a full content build, refer to [Building your Addressable content](builds-full-build.md). + * If your are updating an existing build with modified remote content, refer to [Building for content updates](content-update-build-create.md). +3. Upload the files created at the remote build path using the [CCD dashboard](https://docs.unity.com/ccd/Content/UnityCCDDashboard.htm) or [command-line interface](https://docs.unity.com/ccd/Content/UnityCCDCLI.htm). +4. Create a release and update the badge using the CCD dashboard or command-line interface. + +Building your Addressable content generates a content catalog (.json), a hash file (.hash), and one or more AssetBundle (.bundle) files. Upload these files to the bucket corresponding to the URL used in your profile load path. + +If you have made changes to local content, you must create a new Player build. + +### Use CCD Management package + +To generate, upload, and release Addressable content to your CCD project: + +1. Open the Groups window (menu: __Window > Asset Management > Addressables > Groups__). +2. Use the __Build & Release__ option. + +The CCD Management package will use the default build script behavior to generate the Addressable bundles. + +Then, all groups associated with a path pair that is connected to a CCD bucket and badge via the drop-down window will have their generated bundles uploaded by the management package to those remote target. + +Finally, the management package will a create release for those remote target and update their badge. + +#### CcdManager + +When setting up the project profile path pairs and utilizing CCD, there is an option to use `Automatic`. This option utilizes the `CcdManager` to set static properties at Runtime to tell Addressables which Environment, Bucket, and Badge to reach out to for loading assets. The `CcdManager` has the following properties: `EnvironmentName`, `BucketId`, and `Badge`. Setting these properties at runtime before Addressables initializes will tell Addressables to look at these locations within CCD. To learn more about environments, buckets, and badges, refer to [CCD organization](https://docs.unity.com/ccd/UnityCCD.html#CCD_organization). + +Example Snippet of setting CcdManager Properties: +```c# + CcdManager.EnvironmentName = ENV_NAME; + CcdManager.BucketId = BUCKET_ID; + CcdManager.Badge = BADGE; + + // Addressables call to load or instantiate asset +``` +>[!Note] +> ANY Addressables call initializes the system so be sure to set the `CcdManager` prior to any Addressables call to ensure that there are no race conditions or unexpected behaviors. + +## Use build events +CCD provides a means of wrapping the build and upload service to provide additional functionality. + +### Add a build event +You can add additional events to PreUpdate and PreBuild event chains. + +[!code-cs[sample](../Tests/Editor/DocExampleCode/PrintBucketInformation.cs#SAMPLE)] + +### Disable version override warnings +If you are getting warnings about overriding the player version and would like to keep your current setup, you can disable the warnings by removing the corresponding build events. + +[!code-cs[sample](../Tests/Editor/DocExampleCode/DisableBuildWarnings.cs#SAMPLE)] diff --git a/Documentation~/AddressablesReportExploreTab.md b/Documentation~/AddressablesReportExploreTab.md index 42078ae6..ac3a84bc 100644 --- a/Documentation~/AddressablesReportExploreTab.md +++ b/Documentation~/AddressablesReportExploreTab.md @@ -1,19 +1,19 @@ ---- -uid: addressables-report-explore ---- - -# The Explore Tab - -![](images/BuildReportMainView.png) - -The Explore Tab contains detailed information about the currently selected build report. You can use the **View By** dropdown to change the way that assets are organized in the build report. - -You can sort the Explore View by four different item types: -* AssetBundles: Displays all AssetBundles built as part of the Addressables build. Expanding an AssetBundle displays the assets that bundle contains. This is the default view. -* Assets: Displays all Assets built as part of the Addressables build. Expanding an Asset shows all Assets and Bundles that depend on the expanded asset. -* Labels: Displays all the Assets built as part of the Addressables build, sorted by the label attached to the Asset. Expanding an asset shows the Assets and Bundles that depend on the expanded asset. -* Groups: Displays all the AssetBundles built as part of the Addressables build, sorted by which Group generated the bundle. Note that if you use the **Pack Together By Label** or **Pack Separately** group settings, it is possible for multiple AssetBundles to be generated by a single Group. - -You can use the search bar in the Build Report window to search within the Explore and [Potential Issues](AddressablesReportPotentialIssuesTab.md) Tabs. This filters all assets in the current view by the text written in the search bar. - -Selecting an asset in the Explore Tab will open its information in [The Inspector panel](addressables-report-inspector.md). +--- +uid: addressables-report-explore +--- + +# The Explore Tab + +![](images/BuildReportMainView.png) + +The Explore Tab contains detailed information about the currently selected build report. You can use the **View By** dropdown to change the way that assets are organized in the build report. + +You can sort the Explore View by four different item types: +* AssetBundles: Displays all AssetBundles built as part of the Addressables build. Expanding an AssetBundle displays the assets that bundle contains. This is the default view. +* Assets: Displays all Assets built as part of the Addressables build. Expanding an Asset shows all Assets and Bundles that depend on the expanded asset. +* Labels: Displays all the Assets built as part of the Addressables build, sorted by the label attached to the Asset. Expanding an asset shows the Assets and Bundles that depend on the expanded asset. +* Groups: Displays all the AssetBundles built as part of the Addressables build, sorted by which Group generated the bundle. Note that if you use the **Pack Together By Label** or **Pack Separately** group settings, it is possible for multiple AssetBundles to be generated by a single Group. + +You can use the search bar in the Build Report window to search within the Explore and [Potential Issues](AddressablesReportPotentialIssuesTab.md) Tabs. This filters all assets in the current view by the text written in the search bar. + +Selecting an asset in the Explore Tab will open its information in [The Inspector panel](addressables-report-inspector.md). diff --git a/Documentation~/AddressablesReportPotentialIssuesTab.md b/Documentation~/AddressablesReportPotentialIssuesTab.md index 8a4147d7..5d9f4d19 100644 --- a/Documentation~/AddressablesReportPotentialIssuesTab.md +++ b/Documentation~/AddressablesReportPotentialIssuesTab.md @@ -1,15 +1,15 @@ ---- -uid: addressables-report-potential-issues ---- - -# The Potential Issues View - -![](images/BuildReportPotentialIssuesView.png) - -The Potential Issues Tab scans the selected build report for any potential issues or problems that might arise as part of your build, similar to [Analyze rules](AnalyzeTool.md). Currently, there is only one view present within the Potential Issues View. - -The **Duplicated Assets View** displays a list of all of the non-addressable assets that are duplicated between multiple bundles in your build. This often happens when two addressable assets are in different bundles, but both reference a common asset that's not marked as addressable. - -This kind of issue can be fixed by either moving the addressable assets in question into the same bundle, or by making the duplicated asset addressable. Either method will have implications on your build dependencies. Use whichever method minimizes the impact on having the asset duplicated. - -Selecting an asset in the Potential Issues Tab will open its information in [the Inspector panel](xref:addressables-report-inspector-reference). +--- +uid: addressables-report-potential-issues +--- + +# The Potential Issues View + +![](images/BuildReportPotentialIssuesView.png) + +The Potential Issues Tab scans the selected build report for any potential issues or problems that might arise as part of your build, similar to [Analyze rules](AnalyzeTool.md). Currently, there is only one view present within the Potential Issues View. + +The **Duplicated Assets View** displays a list of all of the non-addressable assets that are duplicated between multiple bundles in your build. This often happens when two addressable assets are in different bundles, but both reference a common asset that's not marked as addressable. + +This kind of issue can be fixed by either moving the addressable assets in question into the same bundle, or by making the duplicated asset addressable. Either method will have implications on your build dependencies. Use whichever method minimizes the impact on having the asset duplicated. + +Selecting an asset in the Potential Issues Tab will open its information in [the Inspector panel](xref:addressables-report-inspector-reference). diff --git a/Documentation~/AddressablesReportSummaryTab.md b/Documentation~/AddressablesReportSummaryTab.md index b73d07b0..a40f50a6 100644 --- a/Documentation~/AddressablesReportSummaryTab.md +++ b/Documentation~/AddressablesReportSummaryTab.md @@ -1,15 +1,15 @@ ---- -uid: addressables-report-summary ---- - -# The Summary Tab - -![](images/BuildReportSummaryView.png) - -The Summary Tab contains general information about the currently selected build report, along with information about any detected potential issues within the build. This information includes the locations of the catalogs created by the build, which profile the current build was built with, how long the build took, and the version of both the Addressables package and the Unity Editor that the build was created with. - -The Summary Tab also contains some high level aggregated information about the build, including the number of AssetBundles created as part of the build, the size of the bundles built, and the number of assets in the build. - -The count of assets pulled into the build by an Addressable asset is an important property in this view. This count includes assets that are referenced by an Addressable asset, but that are not marked as addressable. These assets must be included in the build to allow for assets that depend on them to be loaded. - -Note that if multiple addressable assets in different bundles depend on the same non-addressable asset, then that non-addressable asset will be duplicated in multiple bundles. For more information about duplicated assets, see [Duplicated Assets View](AddressablesReportPotentialIssuesTab.md). +--- +uid: addressables-report-summary +--- + +# The Summary Tab + +![](images/BuildReportSummaryView.png) + +The Summary Tab contains general information about the currently selected build report, along with information about any detected potential issues within the build. This information includes the locations of the catalogs created by the build, which profile the current build was built with, how long the build took, and the version of both the Addressables package and the Unity Editor that the build was created with. + +The Summary Tab also contains some high level aggregated information about the build, including the number of AssetBundles created as part of the build, the size of the bundles built, and the number of assets in the build. + +The count of assets pulled into the build by an Addressable asset is an important property in this view. This count includes assets that are referenced by an Addressable asset, but that are not marked as addressable. These assets must be included in the build to allow for assets that depend on them to be loaded. + +Note that if multiple addressable assets in different bundles depend on the same non-addressable asset, then that non-addressable asset will be duplicated in multiple bundles. For more information about duplicated assets, see [Duplicated Assets View](AddressablesReportPotentialIssuesTab.md). diff --git a/Documentation~/AnalyzeTool.md b/Documentation~/AnalyzeTool.md index e5537480..e7d8316e 100644 --- a/Documentation~/AnalyzeTool.md +++ b/Documentation~/AnalyzeTool.md @@ -1,171 +1,171 @@ ---- -uid: addressables-analyze-tool ---- - -# Analyze tool - -Analyze is a tool that gathers information on your Projects' Addressables layout. In some cases, Analyze might take appropriate actions to clean up the state of your Project. In others, Analyze is purely an informational tool that allows you to make more informed decisions about your Addressables layout. - -## Using Analyze - -In the Unity Editor, open the **Addressables Analyze** window (**Window** > **Asset Management** > **Addressables** > **Analyze**), or open it via the **Addressables Groups** window by clicking the **Tools** > **Window** > **Analyze** button. - -The Analyze window displays a list of Analyze rules, along with the following operations: - -![](images/addr_analyze_window.png) - -__A__: Starts the analysis for any selected rules or their children. - -__B__: Performs the fix action for any selected rules or their children (must be a Fixable rule). - -__C__: Opens the clear options to clear the results for any selected rules or their children. - -__D:__ Opens the options to import a saved analysis result or export results to disk. - -__E__: Fixable rules are displayed under the "Fixable Rules" item. - -__F__: Unfixable rules are displayed under the "Unfixable Rules" item. - -### The analyze operation -The analyze operation gathers the information needed by the rule. Run this action on a rule or set of rules to gather data about the build, dependency maps, and more. Each rule must gather any required data and report it back as a list of [AnalyzeResult] objects. - -No action should be taken to modify any data or the state of the Project during the analyze step. Based on the data gathered in this step, the [fix] operation might be the appropriate course of action. Some rules, however, only contain an analyze step, as no reasonably appropriate and universal action can be taken based on the information gathered. [Check Scene to Addressable Duplicate Dependencies] and [Check Resources to Addressable Duplicate Dependencies] are examples of such rules. - -Rules that are purely informational and contain no fix operation are categorized as **Unfixable Rules**. Those that do have a fix operation are categorized as **Fixable Rules**. - -### The clear step -The clear operation removes any data gathered by the analysis and updates the `TreeView` accordingly. - -### The fix operation -For **Fixable Rules**, you might choose to run the fix operation. The fix operation uses data gathered during the analyze step to perform any necessary modifications and resolve the issues. - -The provided [Check Duplicate Bundle Dependencies] rule is an example of a fixable rule. Problems detected by this rule's analysis can be fixed because there is a reasonably appropriate action that can be taken to resolve them. - -## Provided Analyze rules - -### Fixable rules - -#### Check Duplicate Bundle Dependencies - -This rule checks for potentially duplicated assets, by scanning all groups with [BundledAssetGroupSchemas] and projecting the asset group layout. This essentially requires triggering a full build, so this check is time-consuming and performance-intensive. - -**Issues**: Duplicated assets result from assets in different groups sharing dependencies, for example two Prefabs that share a material existing in different Addressable groups. That material (and any of its dependencies) would be pulled into both groups containing the Prefabs. To prevent this, the material must be marked as Addressable, either with one of the Prefabs, or in its own space, thereby putting the material and its dependencies in a separate Addressable group. - -**Resolution**: If this check discovers any issues, run the fix operation on this rule to create a new Addressable group to which to move all dependent assets. - -**Exceptions**: If you have an asset containing multiple objects, it is possible for different groups to only pull in portions of the asset, and not actually duplicate. An FBX with many meshes is an example of this. If one mesh is in "GroupA" and another is in "GroupB", this rule will think that the FBX is shared, and extract it into its own group if you run the fix operation. In this edge case, running the fix operation is actually harmful, as neither group would have the full FBX asset. - -Also note that duplicate assets might not always be an issue. If assets will never be requested by the same set of users (for example, region-specific assets), then you might want duplicate dependencies, or they might be inconsequential. Each Project is unique, so decide whether to fix duplicate asset dependencies on a case-by-case basis. - -### Unfixable rules - -#### Check Resources to Addressable Duplicate Dependencies - -This rule detects if any assets or asset dependencies are duplicated between built Addressable data and assets residing in a `Resources` folder. - -**Issues**: These duplicates mean that data will be included in both the application build and the Addressables build. - -**Resolution**: This rule is unfixable, because no appropriate action exists. It is purely informational, alerting you to the redundancy. You must decide how to proceed and what action to take, if any. One example of a possible manual fix is to move the offending asset(s) out of the `Resources` folder, and make them Addressable. - -#### Check Scene to Addressable Duplicate Dependencies - -This rule detects any assets or asset dependencies that are shared between the Scenes in the Editor Scene list and Addressables. - -**Issues**: These duplicates mean that data will be included in both the application build and the Addressables build. - -**Resolution**: It is purely informational, alerting you to the redundancy. You must decide how to proceed and what action to take, if any. One example of a possible manual fix is to pull the built-in Scene(s) with duplicated references out of Build Settings and make it an Addressable Scene. - -#### Bundle Layout Preview - -This rule will show how assets explicitly marked as Addressable will be laid out in the Addressable build. Given these explicit assets, the tool also shows what assets are implicitly referenced by, and so will be included in, the build. - -Data gathered by this rule doesn't indicate any particular issues and is only intended to provide extra information. - -## Extending Analyze - -Each unique Project might require additional Analyze rules beyond what comes pre-packaged. The Addressable Assets System allows you to create your own custom rule classes. - -Refer to the [Custom analyze rule project] in the [Addressables-Sample] repository for an example. - - -### AnalyzeRule objects - -Create a new child class of the [AnalyzeRule] class, overriding the following properties: - -* [CanFix] tells Analyze if the rule is deemed fixable or not. -* [ruleName] is the display name you'll see for this rule in the **Analyze window**. - -You'll also need to override the following methods, which are detailed below: - -* [List\ RefreshAnalysis(AddressableAssetSettings settings)] -* [void FixIssues(AddressableAssetSettings settings)] -* [void ClearAnalysis()] - -> [!TIP] -> If your rule is designated unfixable, you don't have to override the `FixIssues` method. - -#### RefreshAnalysis - -This is your analyze operation. In this method, perform any calculations you'd like and cache any data you might need for a potential fix. The return value is a `List` list. After you'd gathered your data, create a new [AnalyzeResult] for each entry in your analysis, containing the data as a string for the first parameter and a [MessageType] for the second (to optionally designate the message type as a warning or error). Return the list of objects you create. - -If you need to make child elements in the `TreeView` for a particular [AnalyzeResult] object, you can delineate the parent item and any children with [kDelimiter]. Include the delimiter between the parent and child items. - -#### FixIssues - -This is your fix operation. If there is an appropriate action to take in response to the analyze step, execute it here. - -#### ClearAnalysis - -This is your clear operation. Any data you cached in the analyze step can be cleaned or removed in this function. The `TreeView` will update to reflect the lack of data. - -### Adding custom rules to the GUI - -A custom rule must register itself with the GUI class using `AnalyzeSystem.RegisterNewRule()`, to appear in the **Analyze** window. For example: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/MyRule.cs#doc_CustomRule)] - - - -#### AnalyzeRule classes - -In order to make it faster to setup custom rules, Addressables includes the following classes, which inherit from [AnalyzeRule]: - -* [BundleRuleBase] is a base class for handling [AnalyzeRule] tasks. It includes some basic methods to retrieve information about bundle and resource dependencies. -* __Check bundle duplicates__ base classes help check for bundle dependency duplicates. Override the [FixIssues] method implementation to perform some custom action. - * [CheckBundleDupeDependencies] inherits from [BundleRuleBase] and includes further methods for [AnalyzeRule] to check bundle dependencies for duplicates and a method to attempt to resolve these duplicates. - * [CheckResourcesDupeDependencies] is the same, but resource dependencies specific. - * [CheckSceneDupeDependencies] is the same, but for scene dependencies specific. - -[AnalyzeResult]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.AnalyzeResult -[AnalyzeRule]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule -[BundledAssetGroupSchemas]: xref:UnityEditor.AddressableAssets.Settings.GroupSchemas.BundledAssetGroupSchema -[CanFix]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.CanFix -[Check Duplicate Bundle Dependencies]: #check-duplicate-bundle-dependencies -[Check Resources to Addressable Duplicate Dependencies]: #check-resources-to-addressable-duplicate-dependencies -[Check Scene to Addressable Duplicate Dependencies]: #check-scene-to-addressable-duplicate-dependencies -[fix]: #the-fix-operation -[kDelimiter]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.kDelimiter -[List\ RefreshAnalysis(AddressableAssetSettings settings)]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.RefreshAnalysis* -[MessageType]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.AnalyzeResult.severity -[ruleName]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.ruleName -[void ClearAnalysis()]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.ClearAnalysis -[void FixIssues(AddressableAssetSettings settings)]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.FixIssues* -[Addressables-Sample]: https://github.com/Unity-Technologies/Addressables-Sample -[Custom analyze rule project]: https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Advanced/CustomAnalyzeRule -[BundleRuleBase]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.BundleRuleBase -[FixIssues]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.CheckBundleDupeDependencies.FixIssues* -[CheckBundleDupeDependencies]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.CheckBundleDupeDependencies -[CheckResourcesDupeDependencies]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.CheckResourcesDupeDependencies -[CheckSceneDupeDependencies]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.CheckSceneDupeDependencies +--- +uid: addressables-analyze-tool +--- + +# Analyze tool + +Analyze is a tool that gathers information on your Projects' Addressables layout. In some cases, Analyze might take appropriate actions to clean up the state of your Project. In others, Analyze is purely an informational tool that allows you to make more informed decisions about your Addressables layout. + +## Using Analyze + +In the Unity Editor, open the **Addressables Analyze** window (**Window** > **Asset Management** > **Addressables** > **Analyze**), or open it via the **Addressables Groups** window by clicking the **Tools** > **Window** > **Analyze** button. + +The Analyze window displays a list of Analyze rules, along with the following operations: + +![](images/addr_analyze_window.png) + +__A__: Starts the analysis for any selected rules or their children. + +__B__: Performs the fix action for any selected rules or their children (must be a Fixable rule). + +__C__: Opens the clear options to clear the results for any selected rules or their children. + +__D:__ Opens the options to import a saved analysis result or export results to disk. + +__E__: Fixable rules are displayed under the "Fixable Rules" item. + +__F__: Unfixable rules are displayed under the "Unfixable Rules" item. + +### The analyze operation +The analyze operation gathers the information needed by the rule. Run this action on a rule or set of rules to gather data about the build, dependency maps, and more. Each rule must gather any required data and report it back as a list of [AnalyzeResult] objects. + +No action should be taken to modify any data or the state of the Project during the analyze step. Based on the data gathered in this step, the [fix] operation might be the appropriate course of action. Some rules, however, only contain an analyze step, as no reasonably appropriate and universal action can be taken based on the information gathered. [Check Scene to Addressable Duplicate Dependencies] and [Check Resources to Addressable Duplicate Dependencies] are examples of such rules. + +Rules that are purely informational and contain no fix operation are categorized as **Unfixable Rules**. Those that do have a fix operation are categorized as **Fixable Rules**. + +### The clear step +The clear operation removes any data gathered by the analysis and updates the `TreeView` accordingly. + +### The fix operation +For **Fixable Rules**, you might choose to run the fix operation. The fix operation uses data gathered during the analyze step to perform any necessary modifications and resolve the issues. + +The provided [Check Duplicate Bundle Dependencies] rule is an example of a fixable rule. Problems detected by this rule's analysis can be fixed because there is a reasonably appropriate action that can be taken to resolve them. + +## Provided Analyze rules + +### Fixable rules + +#### Check Duplicate Bundle Dependencies + +This rule checks for potentially duplicated assets, by scanning all groups with [BundledAssetGroupSchemas] and projecting the asset group layout. This essentially requires triggering a full build, so this check is time-consuming and performance-intensive. + +**Issues**: Duplicated assets result from assets in different groups sharing dependencies, for example two Prefabs that share a material existing in different Addressable groups. That material (and any of its dependencies) would be pulled into both groups containing the Prefabs. To prevent this, the material must be marked as Addressable, either with one of the Prefabs, or in its own space, thereby putting the material and its dependencies in a separate Addressable group. + +**Resolution**: If this check discovers any issues, run the fix operation on this rule to create a new Addressable group to which to move all dependent assets. + +**Exceptions**: If you have an asset containing multiple objects, it is possible for different groups to only pull in portions of the asset, and not actually duplicate. An FBX with many meshes is an example of this. If one mesh is in "GroupA" and another is in "GroupB", this rule will think that the FBX is shared, and extract it into its own group if you run the fix operation. In this edge case, running the fix operation is actually harmful, as neither group would have the full FBX asset. + +Also note that duplicate assets might not always be an issue. If assets will never be requested by the same set of users (for example, region-specific assets), then you might want duplicate dependencies, or they might be inconsequential. Each Project is unique, so decide whether to fix duplicate asset dependencies on a case-by-case basis. + +### Unfixable rules + +#### Check Resources to Addressable Duplicate Dependencies + +This rule detects if any assets or asset dependencies are duplicated between built Addressable data and assets residing in a `Resources` folder. + +**Issues**: These duplicates mean that data will be included in both the application build and the Addressables build. + +**Resolution**: This rule is unfixable, because no appropriate action exists. It is purely informational, alerting you to the redundancy. You must decide how to proceed and what action to take, if any. One example of a possible manual fix is to move the offending asset(s) out of the `Resources` folder, and make them Addressable. + +#### Check Scene to Addressable Duplicate Dependencies + +This rule detects any assets or asset dependencies that are shared between the Scenes in the Editor Scene list and Addressables. + +**Issues**: These duplicates mean that data will be included in both the application build and the Addressables build. + +**Resolution**: It is purely informational, alerting you to the redundancy. You must decide how to proceed and what action to take, if any. One example of a possible manual fix is to pull the built-in Scene(s) with duplicated references out of Build Settings and make it an Addressable Scene. + +#### Bundle Layout Preview + +This rule will show how assets explicitly marked as Addressable will be laid out in the Addressable build. Given these explicit assets, the tool also shows what assets are implicitly referenced by, and so will be included in, the build. + +Data gathered by this rule doesn't indicate any particular issues and is only intended to provide extra information. + +## Extending Analyze + +Each unique Project might require additional Analyze rules beyond what comes pre-packaged. The Addressable Assets System allows you to create your own custom rule classes. + +Refer to the [Custom analyze rule project] in the [Addressables-Sample] repository for an example. + + +### AnalyzeRule objects + +Create a new child class of the [AnalyzeRule] class, overriding the following properties: + +* [CanFix] tells Analyze if the rule is deemed fixable or not. +* [ruleName] is the display name you'll see for this rule in the **Analyze window**. + +You'll also need to override the following methods, which are detailed below: + +* [List\ RefreshAnalysis(AddressableAssetSettings settings)] +* [void FixIssues(AddressableAssetSettings settings)] +* [void ClearAnalysis()] + +> [!TIP] +> If your rule is designated unfixable, you don't have to override the `FixIssues` method. + +#### RefreshAnalysis + +This is your analyze operation. In this method, perform any calculations you'd like and cache any data you might need for a potential fix. The return value is a `List` list. After you'd gathered your data, create a new [AnalyzeResult] for each entry in your analysis, containing the data as a string for the first parameter and a [MessageType] for the second (to optionally designate the message type as a warning or error). Return the list of objects you create. + +If you need to make child elements in the `TreeView` for a particular [AnalyzeResult] object, you can delineate the parent item and any children with [kDelimiter]. Include the delimiter between the parent and child items. + +#### FixIssues + +This is your fix operation. If there is an appropriate action to take in response to the analyze step, execute it here. + +#### ClearAnalysis + +This is your clear operation. Any data you cached in the analyze step can be cleaned or removed in this function. The `TreeView` will update to reflect the lack of data. + +### Adding custom rules to the GUI + +A custom rule must register itself with the GUI class using `AnalyzeSystem.RegisterNewRule()`, to appear in the **Analyze** window. For example: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/MyRule.cs#doc_CustomRule)] + + + +#### AnalyzeRule classes + +In order to make it faster to setup custom rules, Addressables includes the following classes, which inherit from [AnalyzeRule]: + +* [BundleRuleBase] is a base class for handling [AnalyzeRule] tasks. It includes some basic methods to retrieve information about bundle and resource dependencies. +* __Check bundle duplicates__ base classes help check for bundle dependency duplicates. Override the [FixIssues] method implementation to perform some custom action. + * [CheckBundleDupeDependencies] inherits from [BundleRuleBase] and includes further methods for [AnalyzeRule] to check bundle dependencies for duplicates and a method to attempt to resolve these duplicates. + * [CheckResourcesDupeDependencies] is the same, but resource dependencies specific. + * [CheckSceneDupeDependencies] is the same, but for scene dependencies specific. + +[AnalyzeResult]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.AnalyzeResult +[AnalyzeRule]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule +[BundledAssetGroupSchemas]: xref:UnityEditor.AddressableAssets.Settings.GroupSchemas.BundledAssetGroupSchema +[CanFix]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.CanFix +[Check Duplicate Bundle Dependencies]: #check-duplicate-bundle-dependencies +[Check Resources to Addressable Duplicate Dependencies]: #check-resources-to-addressable-duplicate-dependencies +[Check Scene to Addressable Duplicate Dependencies]: #check-scene-to-addressable-duplicate-dependencies +[fix]: #the-fix-operation +[kDelimiter]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.kDelimiter +[List\ RefreshAnalysis(AddressableAssetSettings settings)]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.RefreshAnalysis* +[MessageType]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.AnalyzeResult.severity +[ruleName]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.ruleName +[void ClearAnalysis()]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.ClearAnalysis +[void FixIssues(AddressableAssetSettings settings)]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.AnalyzeRule.FixIssues* +[Addressables-Sample]: https://github.com/Unity-Technologies/Addressables-Sample +[Custom analyze rule project]: https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Advanced/CustomAnalyzeRule +[BundleRuleBase]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.BundleRuleBase +[FixIssues]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.CheckBundleDupeDependencies.FixIssues* +[CheckBundleDupeDependencies]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.CheckBundleDupeDependencies +[CheckResourcesDupeDependencies]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.CheckResourcesDupeDependencies +[CheckSceneDupeDependencies]: xref:UnityEditor.AddressableAssets.Build.AnalyzeRules.CheckSceneDupeDependencies diff --git a/Documentation~/AssetDependencies.md b/Documentation~/AssetDependencies.md index ae6e21ca..fffb9af0 100644 --- a/Documentation~/AssetDependencies.md +++ b/Documentation~/AssetDependencies.md @@ -1,51 +1,51 @@ ---- -uid: addressables-asset-dependencies ---- - -# Asset dependencies overview - -When you include a scene in your Project Build Settings and build a player, Unity includes that scene and any assets used in the scene in your application's built-in data. Similarly, Unity includes any assets in your project's Resources folders in a separate, built-in collection of assets. The difference is that assets in a scene are only loaded as part of a scene, whereas assets in Resources can be loaded independently. - -Addressable assets can either be built into your application as an additional set of local assets, or kept external to the build as remote assets hosted on a server and downloaded when they're needed. You can update remote assets independently from the application itself, although remote assets can't include code, so you can only change assets and serialized data. - -![](images/addressables-assets-overview.png)
*How project assets are exported to a player build* - -If you use the same asset both in a scene and the Resources folder, then Unity makes copies of the asset when building rather than sharing a single instance. For example, if you use a material in a built-in scene and also use it in a prefab located in a Resources folder, you end up with two copies of that material in your build, even if the material asset itself isn't in the Resources folder. If you then mark that same material as Addressable, you end up with three copies. Files in the project's StreamingAssets folder can never be referenced by assets outside that folder. - -> [!NOTE] -> Before building a player, you must make a content build of your Addressable assets. During the player build, Unity copies your local Addressables to the StreamingAssets folder so that they're included in the build along with any assets you placed in StreamingAssets. Unity removes these assets at the end of the build process. You must upload the remote Addressables files produced by the content build to your hosting service. Refer to [Builds](xref:addressables-builds) for more information. - -When you use Addressables in a project, it's best practice to move any scenes and data in the Resources folders into [Addressable groups](Groups.md) and manage them as Addressables. - -The Build Settings scene list must contain at least one scene. You can create a minimal scene that initializes your application. - -A small amount of data in Resources folders typically doesn't cause performance issues. If you use third party packages that place assets there, you don't need to move them unless they cause problems. Addressable assets can't be stored in Resources folders. - -## Reference sub-objects - -Unity partially determines what to include in a content build based on how your assets and scripts reference each other. Sub-object references make the process more complicated. - -If an `AssetReference` points to a sub-object of an asset that's Addressable, Unity builds the entire object into the `AssetBundle` at build time. If the `AssetReference` points to an Addressable object such as a `GameObject`, `ScriptableObject`, or `Scene`, which directly references a sub-object, Unity only builds the sub-object into the `AssetBundle` as an implicit dependency. - -## Asset and AssetBundle dependencies - -When you add an asset to an [Addressables group](Groups.md), that asset is packed into an AssetBundle when you make a [content build](xref:addressables-builds). In this case the asset is explicitly included in the bundle, which is called an explicit asset. - -If an asset references other assets, then the referenced assets are dependencies of the original asset. This is called an asset dependency. For example, if the asset is packed into AssetBundle A and the referenced assets are packed into AssetBundle B, then bundle B is a dependency of bundle A. This is called an AssetBundle dependency. Refer to the [AssetBundle dependencies manual page](xref:AssetBundles-Dependencies) for more information. - -Asset dependencies are treated depending on whether or not they are also Addressable. Dependencies that are Addressable are packed into AssetBundles according to the settings of the group they're in. This might be the same bundle as the referencing asset or a different bundle. A dependency that isn't Addressable is included in the bundle of its referencing asset. The referenced asset is implicitly included in the bundle, which is called an implicit asset. - -> [!TIP] -> Use the [Build Layout Report](xref:addressables-build-layout-report) tool to display more detailed information about AssetBundles produced by a content build. - -## Reference multiple implicit assets - -If more than one Addressable references the same implicit asset, then copies of the implicit asset are included in each bundle containing a referencing Addressable. - -![](images/addressables-multiple-assets.png)
*Non-Addressable assets are copied to each bundle with a referencing Addressable* - -When an implicit asset is included in more than one bundle, multiple instances of that asset can be instantiated at runtime rather than the single instance that your game logic expects. If you change the instance state at runtime, only the object from the same bundle can detect the change because all the other assets now have their own individual instance rather than sharing the common one. - -To stop this duplication, you can make the implicit asset an Addressable asset and include it in one of the existing bundles or add it to a different bundle. The bundle the asset is added to is loaded whenever you load one of the Addressables that reference it. If the Addressables are packed into a different AssetBundle than the referenced asset, then the bundle containing the referenced asset is an AssetBundle dependency. - -The dependent bundle must be loaded when you load any asset in the current bundle, not just the asset containing the reference. Although none of the assets in this other AssetBundle are loaded, loading a bundle has its own runtime cost. Refer to [Memory implications of loading AssetBundle dependencies](memory-assetbundles.md) for more information. +--- +uid: addressables-asset-dependencies +--- + +# Asset dependencies overview + +When you include a scene in your Project Build Settings and build a player, Unity includes that scene and any assets used in the scene in your application's built-in data. Similarly, Unity includes any assets in your project's Resources folders in a separate, built-in collection of assets. The difference is that assets in a scene are only loaded as part of a scene, whereas assets in Resources can be loaded independently. + +Addressable assets can either be built into your application as an additional set of local assets, or kept external to the build as remote assets hosted on a server and downloaded when they're needed. You can update remote assets independently from the application itself, although remote assets can't include code, so you can only change assets and serialized data. + +![](images/addressables-assets-overview.png)
*How project assets are exported to a player build* + +If you use the same asset both in a scene and the Resources folder, then Unity makes copies of the asset when building rather than sharing a single instance. For example, if you use a material in a built-in scene and also use it in a prefab located in a Resources folder, you end up with two copies of that material in your build, even if the material asset itself isn't in the Resources folder. If you then mark that same material as Addressable, you end up with three copies. Files in the project's StreamingAssets folder can never be referenced by assets outside that folder. + +> [!NOTE] +> Before building a player, you must make a content build of your Addressable assets. During the player build, Unity copies your local Addressables to the StreamingAssets folder so that they're included in the build along with any assets you placed in StreamingAssets. Unity removes these assets at the end of the build process. You must upload the remote Addressables files produced by the content build to your hosting service. Refer to [Builds](xref:addressables-builds) for more information. + +When you use Addressables in a project, it's best practice to move any scenes and data in the Resources folders into [Addressable groups](Groups.md) and manage them as Addressables. + +The Build Settings scene list must contain at least one scene. You can create a minimal scene that initializes your application. + +A small amount of data in Resources folders typically doesn't cause performance issues. If you use third party packages that place assets there, you don't need to move them unless they cause problems. Addressable assets can't be stored in Resources folders. + +## Reference sub-objects + +Unity partially determines what to include in a content build based on how your assets and scripts reference each other. Sub-object references make the process more complicated. + +If an `AssetReference` points to a sub-object of an asset that's Addressable, Unity builds the entire object into the `AssetBundle` at build time. If the `AssetReference` points to an Addressable object such as a `GameObject`, `ScriptableObject`, or `Scene`, which directly references a sub-object, Unity only builds the sub-object into the `AssetBundle` as an implicit dependency. + +## Asset and AssetBundle dependencies + +When you add an asset to an [Addressables group](Groups.md), that asset is packed into an AssetBundle when you make a [content build](xref:addressables-builds). In this case the asset is explicitly included in the bundle, which is called an explicit asset. + +If an asset references other assets, then the referenced assets are dependencies of the original asset. This is called an asset dependency. For example, if the asset is packed into AssetBundle A and the referenced assets are packed into AssetBundle B, then bundle B is a dependency of bundle A. This is called an AssetBundle dependency. Refer to the [AssetBundle dependencies manual page](xref:AssetBundles-Dependencies) for more information. + +Asset dependencies are treated depending on whether or not they are also Addressable. Dependencies that are Addressable are packed into AssetBundles according to the settings of the group they're in. This might be the same bundle as the referencing asset or a different bundle. A dependency that isn't Addressable is included in the bundle of its referencing asset. The referenced asset is implicitly included in the bundle, which is called an implicit asset. + +> [!TIP] +> Use the [Build Layout Report](xref:addressables-build-layout-report) tool to display more detailed information about AssetBundles produced by a content build. + +## Reference multiple implicit assets + +If more than one Addressable references the same implicit asset, then copies of the implicit asset are included in each bundle containing a referencing Addressable. + +![](images/addressables-multiple-assets.png)
*Non-Addressable assets are copied to each bundle with a referencing Addressable* + +When an implicit asset is included in more than one bundle, multiple instances of that asset can be instantiated at runtime rather than the single instance that your game logic expects. If you change the instance state at runtime, only the object from the same bundle can detect the change because all the other assets now have their own individual instance rather than sharing the common one. + +To stop this duplication, you can make the implicit asset an Addressable asset and include it in one of the existing bundles or add it to a different bundle. The bundle the asset is added to is loaded whenever you load one of the Addressables that reference it. If the Addressables are packed into a different AssetBundle than the referenced asset, then the bundle containing the referenced asset is an AssetBundle dependency. + +The dependent bundle must be loaded when you load any asset in the current bundle, not just the asset containing the reference. Although none of the assets in this other AssetBundle are loaded, loading a bundle has its own runtime cost. Refer to [Memory implications of loading AssetBundle dependencies](memory-assetbundles.md) for more information. diff --git a/Documentation~/AssetReferences.md b/Documentation~/AssetReferences.md index dbe1ff38..4ecd6e7d 100644 --- a/Documentation~/AssetReferences.md +++ b/Documentation~/AssetReferences.md @@ -1,13 +1,13 @@ ---- -uid: addressables-asset-references ---- - -# Asset references overview - -An `AssetReference` is a type that can reference an Addressable asset. You can use it to add a field to a `MonoBehaviour` or `ScriptableObject` to reference an asset. - -|**Topic**|**Description**| -|---|---| -|[Asset references introduction](asset-reference-intro.md)|Understand what an asset reference is and when to use them.| -|[Create an AssetReference](asset-reference-create.md)|Create and use the `AssetReference` type.| -|[Load an AssetReference](LoadingAssetReferences.md)|Load assets with an `AssetReference`.| +--- +uid: addressables-asset-references +--- + +# Asset references overview + +An `AssetReference` is a type that can reference an Addressable asset. You can use it to add a field to a `MonoBehaviour` or `ScriptableObject` to reference an asset. + +|**Topic**|**Description**| +|---|---| +|[Asset references introduction](asset-reference-intro.md)|Understand what an asset reference is and when to use them.| +|[Create an AssetReference](asset-reference-create.md)|Create and use the `AssetReference` type.| +|[Load an AssetReference](LoadingAssetReferences.md)|Load assets with an `AssetReference`.| diff --git a/Documentation~/BuildArtifacts.md b/Documentation~/BuildArtifacts.md index 839472e8..b301ecd4 100644 --- a/Documentation~/BuildArtifacts.md +++ b/Documentation~/BuildArtifacts.md @@ -1,8 +1,8 @@ ---- -uid: addressables-build-artifacts ---- -# Build artifacts - -A [content build]( xref:addressables-builds) creates files in several locations and Unity doesn't include every file in a built player. Typically, Unity includes files associated with local content in the built player and excludes files associated with remote content. - -Most of the files associated with local content are in the `Library/com.unity.addressables` folder. This is a special subfolder in the `Library` folder which Unity uses to store Addressables files. For more information about the `Library` folder, refer to [Importing assets](xref:ImportingAssets). +--- +uid: addressables-build-artifacts +--- +# Build artifacts + +A [content build]( xref:addressables-builds) creates files in several locations and Unity doesn't include every file in a built player. Typically, Unity includes files associated with local content in the built player and excludes files associated with remote content. + +Most of the files associated with local content are in the `Library/com.unity.addressables` folder. This is a special subfolder in the `Library` folder which Unity uses to store Addressables files. For more information about the `Library` folder, refer to [Importing assets](xref:ImportingAssets). diff --git a/Documentation~/BuildLayoutReport.md b/Documentation~/BuildLayoutReport.md index 1a9825fd..b023df19 100644 --- a/Documentation~/BuildLayoutReport.md +++ b/Documentation~/BuildLayoutReport.md @@ -1,106 +1,106 @@ ---- -uid: addressables-build-layout-report ---- - -# Build layout report - -The build layout report provides detailed information and statistics about your Addressables builds, including: - -* Description of AssetBundles -* Sizes of each Asset and AssetBundle -* Explanation of non-Addressable Assets implicitly included in AssetBundles as dependencies. Refer to [Asset and AssetBundle dependencies](xref:addressables-asset-dependencies) for more information. -* [AssetBundle dependencies](xref:AssetBundles-Dependencies) - -When enabled, the Addressables build script creates the report whenever you build Addressables content. You can enable the report in the Addressables section of the [Preferences window](addressables-preferences.md). You can find the report in your project folder at `Library/com.unity.addressables/buildlayout`. Producing the report increases build time. - -Refer to [Building your Addressable content](xref:addressables-building-content) for more information about building content. - -## Create a build report - -To create a build report: - -1. Open the Unity Preferences window (menu: Edit > Preferences). -1. Select __Addressables__ from the list of preference types. -1. Enable the __Debug Build Layout__ option. -1. Perform a full build of your Addressables content. Refer to [Full builds](builds-full-build.md) for more information. -1. In a file system window, navigate to the `Library/com.unity.addressables/` folder of your Unity project. -1. Open the `buildlayout` file in a text editor. - -## Report data - -The build layout report contains the following information: - -* [Summary](#summary-section): Provides an overview of the build. -* [Group](#group-section): Provides information for each group. -* [Asset bundle](#assetbundle-information): Provides information about each bundle built for a group. -* [Asset](#asset-information): Provides information about each explicit asset in a bundle. -* [File](#file-information): Provides information about each serialized file in an AssetBundle archive. -* [Built-in bundles](#built-in-bundles): Provides information about bundles created for assets, such as the default shader, that are built into Unity. - -### Summary section - -Provides a summary of the build. - -| **Name**| **Description** | -|:---|:---| -| **Addressable Groups**| The number of groups included in the build. | -| **Explicit Assets Addressed**| The number of Addressable assets in the build (this number doesn't include assets in the build that are referenced by an Addressable asset, but which aren't marked as Addressable). | -| **Total Bundle**| The number of AssetBundles created by the build, including how many contain Scene data. | -| **Total Build Size**| The combined size of all AssetBundles. | -| **Total MonoScript Size**| The size of serialized MonoBehaviour and SerializedObject instances. | -| **Total AssetBundle Object Size**| The size of all AssetBundle object instances| - -### Group section - -Reports how Addressables packed the assets in a group into AssetBundles. - -| **Name**| **Description** | -|:---|:---| -| **Group summary**| Name, number of bundles created for group, total size, and number of explicit assets built for the group. | -| **Schemas**| Schemas and settings for the group. | -| **Asset bundles**| See [AssetBundle information](#assetbundle-information). | - -### AssetBundle information - -Reports details for each AssetBundle built for a group. - -| **Name**| **Description** | -|:---|:---| -| **File name**| The file name of the AssetBundle. | -| **Size**| The size of the AssetBundle | -| **Compression**| The compression setting used for the bundle. | -| **Object size**| | -| **Bundle Dependencies**| The list of other AssetBundles the current bundle depends upon. These bundles are always loaded with the current bundle. | -| **Expanded Bundle Dependencies**| | -| **Explicit Assets**| [Asset information](#asset-information) about Addressables included in the bundle. | -| **Files**| [File information](#file-information) about the files in the AssetBundle archive. Scene bundles contain up to two files per Scene, non-Scene bundles contain only one file. | - -### Asset information - -Provides Information for each asset in the Explicit Assets section. - -| **Name**| **Description** | -|:---|:---| -| **Asset path**| The path to the asset in your project | -| **Total Size**| | -| **Size from Objects**| | -| **Size from Streamed Data**| | -| **File Index**| The index of the file in the AssetBundle in which this asset is located. | -| **Addressable Name**| The address of the asset. | -| **External References**| | -| **Internal References**| | - -### File information - -Provides details about each serialized file in an AssetBundle archive - -| **Name**| **Description** | -|:---|:---| -| **File summary**| Index in file list, number and size of serialized MonoScripts in the file | -| **File sections**| A serialized file can have one or more of the following sections:
• No extension
• .resS
• .resource
• .sharedAssets | -| **Data from Other Assets**| Dependent assets referenced by assets in the file. | - -### Built-in bundles - -Lists any bundles that Addressables created from assets, such as the default shaders, that are provided as part of the Unity Engine. The Addressables build places such assets in the separate bundles listed here when needed to avoid duplicating the assets across multiple bundles as implicit dependencies. - +--- +uid: addressables-build-layout-report +--- + +# Build layout report + +The build layout report provides detailed information and statistics about your Addressables builds, including: + +* Description of AssetBundles +* Sizes of each Asset and AssetBundle +* Explanation of non-Addressable Assets implicitly included in AssetBundles as dependencies. Refer to [Asset and AssetBundle dependencies](xref:addressables-asset-dependencies) for more information. +* [AssetBundle dependencies](xref:AssetBundles-Dependencies) + +When enabled, the Addressables build script creates the report whenever you build Addressables content. You can enable the report in the Addressables section of the [Preferences window](addressables-preferences.md). You can find the report in your project folder at `Library/com.unity.addressables/buildlayout`. Producing the report increases build time. + +Refer to [Building your Addressable content](xref:addressables-building-content) for more information about building content. + +## Create a build report + +To create a build report: + +1. Open the Unity Preferences window (menu: Edit > Preferences). +1. Select __Addressables__ from the list of preference types. +1. Enable the __Debug Build Layout__ option. +1. Perform a full build of your Addressables content. Refer to [Full builds](builds-full-build.md) for more information. +1. In a file system window, navigate to the `Library/com.unity.addressables/` folder of your Unity project. +1. Open the `buildlayout` file in a text editor. + +## Report data + +The build layout report contains the following information: + +* [Summary](#summary-section): Provides an overview of the build. +* [Group](#group-section): Provides information for each group. +* [Asset bundle](#assetbundle-information): Provides information about each bundle built for a group. +* [Asset](#asset-information): Provides information about each explicit asset in a bundle. +* [File](#file-information): Provides information about each serialized file in an AssetBundle archive. +* [Built-in bundles](#built-in-bundles): Provides information about bundles created for assets, such as the default shader, that are built into Unity. + +### Summary section + +Provides a summary of the build. + +| **Name**| **Description** | +|:---|:---| +| **Addressable Groups**| The number of groups included in the build. | +| **Explicit Assets Addressed**| The number of Addressable assets in the build (this number doesn't include assets in the build that are referenced by an Addressable asset, but which aren't marked as Addressable). | +| **Total Bundle**| The number of AssetBundles created by the build, including how many contain Scene data. | +| **Total Build Size**| The combined size of all AssetBundles. | +| **Total MonoScript Size**| The size of serialized MonoBehaviour and SerializedObject instances. | +| **Total AssetBundle Object Size**| The size of all AssetBundle object instances| + +### Group section + +Reports how Addressables packed the assets in a group into AssetBundles. + +| **Name**| **Description** | +|:---|:---| +| **Group summary**| Name, number of bundles created for group, total size, and number of explicit assets built for the group. | +| **Schemas**| Schemas and settings for the group. | +| **Asset bundles**| See [AssetBundle information](#assetbundle-information). | + +### AssetBundle information + +Reports details for each AssetBundle built for a group. + +| **Name**| **Description** | +|:---|:---| +| **File name**| The file name of the AssetBundle. | +| **Size**| The size of the AssetBundle | +| **Compression**| The compression setting used for the bundle. | +| **Object size**| | +| **Bundle Dependencies**| The list of other AssetBundles the current bundle depends upon. These bundles are always loaded with the current bundle. | +| **Expanded Bundle Dependencies**| | +| **Explicit Assets**| [Asset information](#asset-information) about Addressables included in the bundle. | +| **Files**| [File information](#file-information) about the files in the AssetBundle archive. Scene bundles contain up to two files per Scene, non-Scene bundles contain only one file. | + +### Asset information + +Provides Information for each asset in the Explicit Assets section. + +| **Name**| **Description** | +|:---|:---| +| **Asset path**| The path to the asset in your project | +| **Total Size**| | +| **Size from Objects**| | +| **Size from Streamed Data**| | +| **File Index**| The index of the file in the AssetBundle in which this asset is located. | +| **Addressable Name**| The address of the asset. | +| **External References**| | +| **Internal References**| | + +### File information + +Provides details about each serialized file in an AssetBundle archive + +| **Name**| **Description** | +|:---|:---| +| **File summary**| Index in file list, number and size of serialized MonoScripts in the file | +| **File sections**| A serialized file can have one or more of the following sections:
• No extension
• .resS
• .resource
• .sharedAssets | +| **Data from Other Assets**| Dependent assets referenced by assets in the file. | + +### Built-in bundles + +Lists any bundles that Addressables created from assets, such as the default shaders, that are provided as part of the Unity Engine. The Addressables build places such assets in the separate bundles listed here when needed to avoid duplicating the assets across multiple bundles as implicit dependencies. + diff --git a/Documentation~/BuildPlayerContent.md b/Documentation~/BuildPlayerContent.md index 6a745042..8abfee71 100644 --- a/Documentation~/BuildPlayerContent.md +++ b/Documentation~/BuildPlayerContent.md @@ -1,19 +1,19 @@ ---- -uid: addressables-api-build-player-content ---- - -# Build scripting - -You can use the `Addressables` API to customize your project build in the following ways: - -* Start a build from a script -* Override an existing script -* Extend [`BuildScriptBase`](xref:UnityEditor.AddressableAssets.Build.DataBuilders.BuildScriptBase) or implement [`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder) - -When you customize a build script to handle different asset types or handle assets in a different way, you might need to customize the [Play Mode Scripts](xref:addressables-asset-settings) so that the Unity Editor can handle those assets in the same way during Play mode. - -## Addtional resources - -* [Start a build from a script](build-scripting-start-build.md) -* [Custom build scripting](build-scripting-custom.md) +--- +uid: addressables-api-build-player-content +--- + +# Build scripting + +You can use the `Addressables` API to customize your project build in the following ways: + +* Start a build from a script +* Override an existing script +* Extend [`BuildScriptBase`](xref:UnityEditor.AddressableAssets.Build.DataBuilders.BuildScriptBase) or implement [`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder) + +When you customize a build script to handle different asset types or handle assets in a different way, you might need to customize the [Play Mode Scripts](xref:addressables-asset-settings) so that the Unity Editor can handle those assets in the same way during Play mode. + +## Addtional resources + +* [Start a build from a script](build-scripting-start-build.md) +* [Custom build scripting](build-scripting-custom.md) * [Build while recompiling](build-scripting-recompiling.md) \ No newline at end of file diff --git a/Documentation~/BuildProfileLog.md b/Documentation~/BuildProfileLog.md index e436d9cd..c4e824a3 100644 --- a/Documentation~/BuildProfileLog.md +++ b/Documentation~/BuildProfileLog.md @@ -1,21 +1,21 @@ ---- -uid: addressables-build-profile-log ---- - -# Build profile log - -The Addressables build process always creates a .json log file that contains build performance information. You can find the log file in your project folder at `Library/com.unity.addressables/AddressablesBuildTEP.json`. - -View the log file with the chrome://tracing tool in Google Chrome or another [Chromium](https://www.chromium.org/Home)-based browser. - -![](images/build-profile-log.png)
*A sample log file displayed in chrome://tracing* - -## View the build profile - -1. Open a Chromium-based browser. -2. Enter `chrome://tracing` in the browser to open the [Trace Event Profiling Tool](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool). -3. Click the __Load__ button. -4. In the file browser, navigate to your Unity project’s `Library/com.unity.addressables` folder. -5. Open the `AddressablesBuildTEP.json` file. - -Refer to [Unity Scriptable Build Pipeline](https://docs.unity3d.com/Packages/com.unity.scriptablebuildpipeline@latest) for more information about build performance logging. +--- +uid: addressables-build-profile-log +--- + +# Build profile log + +The Addressables build process always creates a .json log file that contains build performance information. You can find the log file in your project folder at `Library/com.unity.addressables/AddressablesBuildTEP.json`. + +View the log file with the chrome://tracing tool in Google Chrome or another [Chromium](https://www.chromium.org/Home)-based browser. + +![](images/build-profile-log.png)
*A sample log file displayed in chrome://tracing* + +## View the build profile + +1. Open a Chromium-based browser. +2. Enter `chrome://tracing` in the browser to open the [Trace Event Profiling Tool](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool). +3. Click the __Load__ button. +4. In the file browser, navigate to your Unity project’s `Library/com.unity.addressables` folder. +5. Open the `AddressablesBuildTEP.json` file. + +Refer to [Unity Scriptable Build Pipeline](https://docs.unity3d.com/Packages/com.unity.scriptablebuildpipeline@latest) for more information about build performance logging. diff --git a/Documentation~/BuildingContent.md b/Documentation~/BuildingContent.md index 73e604db..ce5b7c83 100644 --- a/Documentation~/BuildingContent.md +++ b/Documentation~/BuildingContent.md @@ -1,11 +1,11 @@ ---- -uid: addressables-building-content ---- - -# Create a build - -When you use the Addressables package, you can build your content (AssetBundles) as a separate step from your application player. The Addressables package provides its own build scripts for this purpose, accessible from the toolbar of the [Groups window](GroupsWindow.md). - -You can build your Addressables content as part of the Player build, or you can build them as separate steps. - -You can also perform a [full build](builds-full-build.md) or an [update build](builds-update-build.md). +--- +uid: addressables-building-content +--- + +# Create a build + +When you use the Addressables package, you can build your content (AssetBundles) as a separate step from your application player. The Addressables package provides its own build scripts for this purpose, accessible from the toolbar of the [Groups window](GroupsWindow.md). + +You can build your Addressables content as part of the Player build, or you can build them as separate steps. + +You can also perform a [full build](builds-full-build.md) or an [update build](builds-update-build.md). diff --git a/Documentation~/BuildingShaders.md b/Documentation~/BuildingShaders.md index c15f4803..0c0198a7 100644 --- a/Documentation~/BuildingShaders.md +++ b/Documentation~/BuildingShaders.md @@ -1,11 +1,11 @@ ---- -uid: addressables-shaders ---- - -# Build shaders - -By default, Unity [strips shaders variants](xref:shader-variant-stripping) that aren't used in any scenes. This can exclude variants that are only used in AssetBundles. To ensure that certain variants are not stripped, include them in the **Shader Stripping** properties in [Graphics Settings](xref:class-GraphicsSettings). - -For example, if you have Addressable assets that use lightmap-related shaders such as [Mixed Lights](xref:LightMode-Mixed), go to **Edit** > **Project Settings** > **Graphics** > **Shader Stripping** and set the **Lightmap Mode** property to **Custom**. - -[Quality Settings](xref:class-QualitySettings) also affect shader variants used in AssetBundles. +--- +uid: addressables-shaders +--- + +# Build shaders + +By default, Unity [strips shaders variants](xref:shader-variant-stripping) that aren't used in any scenes. This can exclude variants that are only used in AssetBundles. To ensure that certain variants are not stripped, include them in the **Shader Stripping** properties in [Graphics Settings](xref:class-GraphicsSettings). + +For example, if you have Addressable assets that use lightmap-related shaders such as [Mixed Lights](xref:LightMode-Mixed), go to **Edit** > **Project Settings** > **Graphics** > **Shader Stripping** and set the **Lightmap Mode** property to **Custom**. + +[Quality Settings](xref:class-QualitySettings) also affect shader variants used in AssetBundles. diff --git a/Documentation~/Builds.md b/Documentation~/Builds.md index 738d4f7b..7f21b604 100644 --- a/Documentation~/Builds.md +++ b/Documentation~/Builds.md @@ -1,20 +1,20 @@ ---- -uid: addressables-builds ---- - -# Build content - -A content build processes Addressables [groups](groups-intro.md) to produce the [content catalog](build-content-catalogs.md), runtime settings, and the [AssetBundles](xref:AssetBundlesIntro) that contain your assets. - -|**Topic**|**Description**| -|---|---| -|[Build content introduction](build-intro.md)|Understand the various build options.| -|[Build Addressables content with Player builds](build-player-builds.md)|Understand how building works with Player builds.| -|[Asset dependencies overview](AssetDependencies.md)|Understand asset dependencies and how they affect builds.| -|[Create a build](BuildingContent.md)|Create a new build.| -|[Build scripting](BuildPlayerContent.md)|Understand how to create builds from scripts.| -|[Build sprite atlases](AddressablesAndSpriteAtlases.md)|Considerations for building sprite atlases.| -|[Build shaders](BuildingShaders.md)|Considerations for building shaders.| -|[Build artifacts](BuildArtifacts.md)|Understand build artifacts and what file types Unity includes in your build.| -|[Content update builds](ContentUpdateWorkflow.md)|Understand how to perform an update build.| +--- +uid: addressables-builds +--- + +# Build content + +A content build processes Addressables [groups](groups-intro.md) to produce the [content catalog](build-content-catalogs.md), runtime settings, and the [AssetBundles](xref:AssetBundlesIntro) that contain your assets. + +|**Topic**|**Description**| +|---|---| +|[Build content introduction](build-intro.md)|Understand the various build options.| +|[Build Addressables content with Player builds](build-player-builds.md)|Understand how building works with Player builds.| +|[Asset dependencies overview](AssetDependencies.md)|Understand asset dependencies and how they affect builds.| +|[Create a build](BuildingContent.md)|Create a new build.| +|[Build scripting](BuildPlayerContent.md)|Understand how to create builds from scripts.| +|[Build sprite atlases](AddressablesAndSpriteAtlases.md)|Considerations for building sprite atlases.| +|[Build shaders](BuildingShaders.md)|Considerations for building shaders.| +|[Build artifacts](BuildArtifacts.md)|Understand build artifacts and what file types Unity includes in your build.| +|[Content update builds](ContentUpdateWorkflow.md)|Understand how to perform an update build.| |[Use continuous integration to build Addressables](ContinuousIntegration.md)|Build content with continuous integration.| \ No newline at end of file diff --git a/Documentation~/ContentPackingAndLoadingSchema.md b/Documentation~/ContentPackingAndLoadingSchema.md index 968f226f..01e3221b 100644 --- a/Documentation~/ContentPackingAndLoadingSchema.md +++ b/Documentation~/ContentPackingAndLoadingSchema.md @@ -1,107 +1,107 @@ ---- -uid: addressables-content-packing-and-loading-schema ---- - -## Content Packing & Loading schema reference - -The Content Packing & Loading schema is the main Addressables schema used by the default build script, and it defines the settings for building and loading Addressable assets. - -To open the Content Packing & Loading schema, open the [Addressables Groups window](GroupsWindow.md) (**Window > Asset Management > Addressables > Groups**), then select a group. The group's settings are displayed in the Inspector. - -## Build and Load Paths - -The Build and Load Paths settings determine where the artifacts for your content builds are created and where the Addressables system should look for them at runtime. - -![](images/groups-build-load.png)
*Building and loading paths* - -| **Property**|| **Description** | -|:---|---|:---| -| __Build & Load Paths__ || The [Profile path](xref:addressables-profiles) pair that defines where the Addressables build system creates artifacts for this group and where the Addressables system loads those artifacts at runtime. Choose a path pair from the list or select `` if you want to set the build and load paths separately.| -| __Build Path__

__Load Path__

Only available if you set __Build & Load Paths__ to ``.|| A Profile variable that defines where the Addressables build system creates artifacts for this group, or loads the build artifacts of the group. You can also set a custom string. Use one of the following: -||__LocalBuildPath__| Use for assets that you plan to distribute as part of your application installation. -||__RemoteBuildPath__| Use for assets that you plan to distribute using a remote hosting service such Unity Cloud Content Delivery or other Content Delivery Network. -||__Custom__| Specify a string as the path for this group.| - -The build and load path options are defined by variables in a [Profile](xref:addressables-profiles). Note that only variables intended for a given purpose should be used for a setting. For example, choosing a load path variable for a build path setting wouldn't give you a useful result. - -When you choose a Profile variable, a preview of the path is displayed in the __Path Preview__. Components of the path in braces, such as `{UnityEngine.AddressableAssets.Addressable.RuntimePath}`, indicate that a static variable is used to construct the final path at runtime. That portion of the path is replaced by the current value of the static variable when the Addressables system initializes at runtime. - -> [!WARNING] -> Usually, you shouldn't change the local build or load paths from their default values. If you do, you must copy the local build artifacts from your custom build location to the project's `StreamingAssets` folder before making a Player build. Altering these paths also precludes building your Addressables as part of the Player build. - -## Advanced Options - -![](images/groups-advanced.png)
*The Advanced Options section* - -| **Property**| **Description** | -|:---|---| -| __Asset Bundle Compression__| The compression type for all bundles produced from the group. LZ4 is usually the most efficient option, but other options can be better in specific circumstances. Refer to [AssetBundle Compression](#assetbundle-compression) for more information. | -| __Include In Build__| Enable this property to include assets in this group in a content build. | -| __Force Unique Provider__| Enable this property to use unique instances of Resource Provider classes for this group. Enable this option if you have custom Provider implementations for the asset types in this group and instances of those Providers must not be shared between groups. | -| __Use Asset Bundle Cache__| Enable this property to cache remotely distributed bundles. | -| __Asset Bundle CRC__| Enable this property to verify a bundle's integrity before loading it. For more information see [AssetBundle CRC](#assetbundle-crc):
• __Disabled__: Never check bundle integrity.
• __Enabled, Including Cached__: Always check bundle integrity.
• __Enabled, Excluding Cached__: Check integrity of bundles when downloading.
| -|__Use UnityWebRequest for Local Asset Bundles__|Enable this property to load local AssetBundle archives from this group using [`UnityWebRequestAssetBundle.GetAssetBundle`](xref:UnityEngine.Networking.UnityWebRequest.GetAssetBundle(System.String,System.UInt32)) instead of [`AssetBundle.LoadFromFileAsync`](xref:UnityEngine.AssetBundle.LoadFromFileAsync(System.String,System.UInt32,System.UInt64)). | -| __Request Timeout__| The timeout interval for downloading remote bundles. | -| __Use Http Chunked Transfer__| Enable this property to use the HTTP/1.1 chunked-transfer encoding method when downloading bundles.

Deprecated and ignored in Unity 2019.3+. | -| __Http Redirect Limit__| The number of redirects allowed when downloading bundles. Set to -1 for no limit. | -| __Retry Count__| The number of times to retry failed downloads. | -|__Include Addresses in Catalog__|Enable this property to include the address strings in the catalog. If you don't load assets in the group using their address strings, you can disable this property to decrease the size of the catalog.| -|__Include GUIDs in Catalog__|Enable this property to include GUID strings in the catalog. You must include GUID strings to access an asset with an [`AssetReference`](xref:addressables-asset-references). If you don't load assets in the group using an `AssetReference` or GUID strings, you can disable this property to decrease the size of the catalog.| -|__Include Labels in Catalog__|Enable this property to include label strings in the catalog. If you don't load assets in the group using labels, you can disable this property to decrease the size of the catalog. | -|__Internal Asset Naming Mode__|Determines the identification of assets in AssetBundles and is used to load the asset from the bundle. This value is used as the `internalId` of the asset location. Changing this setting affects a bundles CRC and Hash value.

**Warning**: Don't modify this setting for [Content update builds](xref:addressables-content-update-builds) because the data stored in the [content state file](xref:addressables-build-artifacts) becomes invalid.

The different modes are:

- __Full Path__: The path of the asset in your project. Recommended during development because you can identify assets being loaded by their ID if needed.
- __Filename__: The asset's file name. This can also be used to identify an asset. **Note**: You can't have multiple assets with the same name.
- __GUID__: A deterministic value for the asset.
- __Dynamic__: The shortest ID that can be constructed based on the assets in the group. Recommended for release because it can reduce the amount of data in the AssetBundle and catalog, and lower runtime memory overhead.| -|__Internal Bundle Id Mode__|Determines how an AssetBundle is identified internally. This affects how an AssetBundle locates dependencies that are contained in other bundles. Changing this value affects the CRC and Hash of this bundle and all other bundles that reference it.

**Warning**: Don't modify this setting for [Content update builds](xref:addressables-content-update-builds) because the data stored in the [content state file](xref:addressables-build-artifacts) becomes invalid.

The different modes are:

- __Group Guid__: A unique identifier for the Group. This mode is recommended because it doesn't change.
- __Group Guid Project Id Hash__: Uses a combination of the Group GUID and the Cloud Project ID, if Cloud Services are enabled. This changes if the Project is bound to a different Cloud Project ID. This mode is recommended when sharing assets between multiple projects because the ID constructed is deterministic and unique between projects.
- __Group Guid Project Id Entries Hash__: Uses a combination of the Group GUID, Cloud Project ID (if Cloud Services are enabled), and asset entries in the Group. Using this mode can cause bundle cache version issues. Adding or removing entries results in a different hash.| -|__Cache Clear Behavior__| Determines when an installed application clears AssetBundles from the cache.| -| __Bundle Mode__| Set how to pack the assets in this group into bundles:

- __Pack Together__: Create a single bundle containing all assets.
- __Pack Separately__: Create a bundle for each primary asset in the group. Subassets, such as sprites in a sprite sheet are packed together. Assets within a folder added to the group are also packed together.
- __Pack Together by Label__: Create a bundle for assets sharing the same combination of labels. | -| __Bundle Naming Mode__| Set how to construct the file names of AssetBundles:
- __Filename__: The filename is a string derived from the group name. No hash is appended to it.
- __Append Hash to Filename__: The filename is a string derived from the group name with bundle hash appended to it. The bundle hash is calculated using the contents of the bundle.
- __Use Hash of AssetBundle__: The filename is the bundle hash.
- __Use Hash of Filename__: The filename is a hash calculated from the a string derived from the group name.| -|__Asset Load Mode__|Set whether to load assets individually as you request them (the default) or always load all assets in the group together. It is recommended to use __Requested Asset and Dependencies__ for most cases. Refer to [Asset Load Mode](#asset-load-mode) for more information. | -| __Asset Provider__| Defines which Provider class Addressables uses to load assets from the AssetBundles generated from this group. Set this option to __Assets from Bundles Provider__ unless you have a custom Provider implementation to provide assets from an AssetBundle. | -| __Asset Bundle Provider__| Defines which Provider class Addressables uses to load AssetBundles generated from this group. Set this option to __AssetBundle Provider__ unless you have a custom Provider implementation to provide AssetBundles. | - -### AssetBundle compression - -Addressables provides three different options for bundle compression: - -* **Uncompressed**: This option is largest on disk, and fastest to load. If your application has space to spare, consider this option for local content. An advantage of uncompressed bundles is how they handle being patched. If you're developing for a platform where the platform itself provides patching, uncompressed bundles provide the most accurate (smallest) patching. Either of the other compression options cause some bloat of patches. -* **LZ4**: If Uncompressed is not a viable option, then LZ4 should be used for all other local content. This is a chunk-based compression which provides the ability to load parts of the file without needing to load it in its entirety. -* **LZMA**: Use LZMA for all remote content, but not for any local content. It provides the smallest bundle size, but is slow to load. If you store local bundles in LZMA you can create a smaller player, but load times are significantly worse than uncompressed or LZ4. For downloaded bundles, LZMA avoids the slow load time by recompressing the downloaded bundle when storing it in the AssetBundle cache. By default, bundles are stored in the cache with LZ4 compression. - -To set the compression, use the Advanced settings on each group. Compression doesn't affect in-memory size of your loaded content. - -> [!NOTE] -> LZMA AssetBundle compression isn't available for AssetBundles on WebGL. You can use LZ4 compression instead. For more WebGL AssetBundle information, see [Building and running a WebGL project](xref:webgl-building). - -The hardware characteristics of a platform mean that uncompressed bundles aren't always the fastest to load. The maximum speed of loading uncompressed bundles is gated by IO speed, while the speed of loading LZ4-compressed bundles is gated by either IO speed or CPU, depending on hardware. - -On most platforms, loading LZ4-compressed bundles is CPU bound, and loading uncompressed bundles is faster. On platforms that have low IO speeds and high CPU speeds, LZ4 loading can be faster. It's best practice to run performance analysis to validate whether your game fits the common patterns, or needs some unique tweaking. - -More information on Unity's compression selection is available in the [AssetBundle compression manual page](xref:AssetBundles-Cache). - -### AssetBundle CRC - -Different CRC settings are best used depending upon different circumstances. Checking for a change in the file requires the entire AssetBundle to be decompressed and the check processed on the uncompressed bytes. This can impact performance negatively. - -Corruption is likely to only happen during a download, because disk storage is generally reliable and unlikely to have corrupted files after saving to disk. If your AssetBundle contains data that might be tampered with, such as settings values, then you might want to consider enabling CRC checks on saved AssetBundles. - -For local AssetBundles, if the application download performs a check on the download before saving to disk, consider setting this property to __Disabled__ because the download will have already been checked. - -For remote AssetBundles, __Enabled, Excluding cache__ is a good default. When downloading and caching an AssetBundle to disk, the bytes are decompressed and a CRC calculation is done during file saving. This doesn't impact performance and the corruption is most likely to occur during this phase from the download. __Including cache__ is good to use where the data needs to be checked every time such as settings values. - -### Asset Load Mode - -For most platforms and collection of content, you should use __Requested Asset and Dependencies__. This mode only loads what's required for the Assets requested with [`LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetAsync*) or [`LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync``1(System.Collections.Generic.IList{System.Object},System.Action{``0},UnityEngine.AddressableAssets.Addressables.MergeMode)). Objects are loaded based in the order that they appear in a bundle file, which can result in reading the same file multiple times. Enabling the __Contiguous Bundles__ option in [Addressables Build settings](xref:addressables-asset-settings) can help reduce the number of extra file reads. - -This prevents situations where Assets are loaded into memory that aren't used. - -Performance in situations where you load all Assets that are packed together, such as a loading screen. Most types of content have either have similar or improved performance when loading each individually using __Requested Asset and Dependencies__ mode. This mode sequentially reads entire bundle files, which may be more preferable in some platforms. - -> [!NOTE] -> The examples below apply to desktop and mobile platforms. Performance might differ between platforms. The __All Packed Assets and Dependencies__ mode typically performs better than loading assets individually on the Nintendo Switch due its hardware and memory reading limitations. -> You should profile loading performance for your specific content and platform to see what works for your application. - -Loading performance can vary between content type. As an example, large counts of serialized data such as prefabs or ScriptableObjects with direct references to other serialized data load faster using __All Packed Assets and Dependencies__. With some other Assets like Textures, you can often achieve better performance when you load each Asset individually. - -If using [Synchronous Addressables](xref:synchronous-addressables), there is little performance between asset load modes. Because of greater flexibility you should use __Requested Asset and Dependencies__ where you know the content will be loaded synchronously. - -On loading the first Asset with __All Packed Assets and Dependencies__, all Assets are loaded into memory. Later `LoadAssetAsync` calls for Assets from that pack return the preloaded asset without needing to load it. - -Even though all the Assets in a group and any dependencies are loaded in memory when you use the **All Packed Assets and Dependencies** option, the reference count of an individual asset isn't incremented unless you explicitly load it (or it is a dependency of an asset that you load explicitly). If you later call [`Resources.UnloadUnusedAssets`](xref:UnityEngine.Resources.UnloadUnusedAssets), or you load a new scene using [`LoadSceneMode.Single`](xref:UnityEngine.SceneManagement.LoadSceneMode.Single), then any unused assets (those with a reference count of zero) are unloaded. +--- +uid: addressables-content-packing-and-loading-schema +--- + +## Content Packing & Loading schema reference + +The Content Packing & Loading schema is the main Addressables schema used by the default build script, and it defines the settings for building and loading Addressable assets. + +To open the Content Packing & Loading schema, open the [Addressables Groups window](GroupsWindow.md) (**Window > Asset Management > Addressables > Groups**), then select a group. The group's settings are displayed in the Inspector. + +## Build and Load Paths + +The Build and Load Paths settings determine where the artifacts for your content builds are created and where the Addressables system should look for them at runtime. + +![](images/groups-build-load.png)
*Building and loading paths* + +| **Property**|| **Description** | +|:---|---|:---| +| __Build & Load Paths__ || The [Profile path](xref:addressables-profiles) pair that defines where the Addressables build system creates artifacts for this group and where the Addressables system loads those artifacts at runtime. Choose a path pair from the list or select `` if you want to set the build and load paths separately.| +| __Build Path__

__Load Path__

Only available if you set __Build & Load Paths__ to ``.|| A Profile variable that defines where the Addressables build system creates artifacts for this group, or loads the build artifacts of the group. You can also set a custom string. Use one of the following: +||__LocalBuildPath__| Use for assets that you plan to distribute as part of your application installation. +||__RemoteBuildPath__| Use for assets that you plan to distribute using a remote hosting service such Unity Cloud Content Delivery or other Content Delivery Network. +||__Custom__| Specify a string as the path for this group.| + +The build and load path options are defined by variables in a [Profile](xref:addressables-profiles). Note that only variables intended for a given purpose should be used for a setting. For example, choosing a load path variable for a build path setting wouldn't give you a useful result. + +When you choose a Profile variable, a preview of the path is displayed in the __Path Preview__. Components of the path in braces, such as `{UnityEngine.AddressableAssets.Addressable.RuntimePath}`, indicate that a static variable is used to construct the final path at runtime. That portion of the path is replaced by the current value of the static variable when the Addressables system initializes at runtime. + +> [!WARNING] +> Usually, you shouldn't change the local build or load paths from their default values. If you do, you must copy the local build artifacts from your custom build location to the project's `StreamingAssets` folder before making a Player build. Altering these paths also precludes building your Addressables as part of the Player build. + +## Advanced Options + +![](images/groups-advanced.png)
*The Advanced Options section* + +| **Property**| **Description** | +|:---|---| +| __Asset Bundle Compression__| The compression type for all bundles produced from the group. LZ4 is usually the most efficient option, but other options can be better in specific circumstances. Refer to [AssetBundle Compression](#assetbundle-compression) for more information. | +| __Include In Build__| Enable this property to include assets in this group in a content build. | +| __Force Unique Provider__| Enable this property to use unique instances of Resource Provider classes for this group. Enable this option if you have custom Provider implementations for the asset types in this group and instances of those Providers must not be shared between groups. | +| __Use Asset Bundle Cache__| Enable this property to cache remotely distributed bundles. | +| __Asset Bundle CRC__| Enable this property to verify a bundle's integrity before loading it. For more information see [AssetBundle CRC](#assetbundle-crc):
• __Disabled__: Never check bundle integrity.
• __Enabled, Including Cached__: Always check bundle integrity.
• __Enabled, Excluding Cached__: Check integrity of bundles when downloading.
| +|__Use UnityWebRequest for Local Asset Bundles__|Enable this property to load local AssetBundle archives from this group using [`UnityWebRequestAssetBundle.GetAssetBundle`](xref:UnityEngine.Networking.UnityWebRequest.GetAssetBundle(System.String,System.UInt32)) instead of [`AssetBundle.LoadFromFileAsync`](xref:UnityEngine.AssetBundle.LoadFromFileAsync(System.String,System.UInt32,System.UInt64)). | +| __Request Timeout__| The timeout interval for downloading remote bundles. | +| __Use Http Chunked Transfer__| Enable this property to use the HTTP/1.1 chunked-transfer encoding method when downloading bundles.

Deprecated and ignored in Unity 2019.3+. | +| __Http Redirect Limit__| The number of redirects allowed when downloading bundles. Set to -1 for no limit. | +| __Retry Count__| The number of times to retry failed downloads. | +|__Include Addresses in Catalog__|Enable this property to include the address strings in the catalog. If you don't load assets in the group using their address strings, you can disable this property to decrease the size of the catalog.| +|__Include GUIDs in Catalog__|Enable this property to include GUID strings in the catalog. You must include GUID strings to access an asset with an [`AssetReference`](xref:addressables-asset-references). If you don't load assets in the group using an `AssetReference` or GUID strings, you can disable this property to decrease the size of the catalog.| +|__Include Labels in Catalog__|Enable this property to include label strings in the catalog. If you don't load assets in the group using labels, you can disable this property to decrease the size of the catalog. | +|__Internal Asset Naming Mode__|Determines the identification of assets in AssetBundles and is used to load the asset from the bundle. This value is used as the `internalId` of the asset location. Changing this setting affects a bundles CRC and Hash value.

**Warning**: Don't modify this setting for [Content update builds](xref:addressables-content-update-builds) because the data stored in the [content state file](xref:addressables-build-artifacts) becomes invalid.

The different modes are:

- __Full Path__: The path of the asset in your project. Recommended during development because you can identify assets being loaded by their ID if needed.
- __Filename__: The asset's file name. This can also be used to identify an asset. **Note**: You can't have multiple assets with the same name.
- __GUID__: A deterministic value for the asset.
- __Dynamic__: The shortest ID that can be constructed based on the assets in the group. Recommended for release because it can reduce the amount of data in the AssetBundle and catalog, and lower runtime memory overhead.| +|__Internal Bundle Id Mode__|Determines how an AssetBundle is identified internally. This affects how an AssetBundle locates dependencies that are contained in other bundles. Changing this value affects the CRC and Hash of this bundle and all other bundles that reference it.

**Warning**: Don't modify this setting for [Content update builds](xref:addressables-content-update-builds) because the data stored in the [content state file](xref:addressables-build-artifacts) becomes invalid.

The different modes are:

- __Group Guid__: A unique identifier for the Group. This mode is recommended because it doesn't change.
- __Group Guid Project Id Hash__: Uses a combination of the Group GUID and the Cloud Project ID, if Cloud Services are enabled. This changes if the Project is bound to a different Cloud Project ID. This mode is recommended when sharing assets between multiple projects because the ID constructed is deterministic and unique between projects.
- __Group Guid Project Id Entries Hash__: Uses a combination of the Group GUID, Cloud Project ID (if Cloud Services are enabled), and asset entries in the Group. Using this mode can cause bundle cache version issues. Adding or removing entries results in a different hash.| +|__Cache Clear Behavior__| Determines when an installed application clears AssetBundles from the cache.| +| __Bundle Mode__| Set how to pack the assets in this group into bundles:

- __Pack Together__: Create a single bundle containing all assets.
- __Pack Separately__: Create a bundle for each primary asset in the group. Subassets, such as sprites in a sprite sheet are packed together. Assets within a folder added to the group are also packed together.
- __Pack Together by Label__: Create a bundle for assets sharing the same combination of labels. | +| __Bundle Naming Mode__| Set how to construct the file names of AssetBundles:
- __Filename__: The filename is a string derived from the group name. No hash is appended to it.
- __Append Hash to Filename__: The filename is a string derived from the group name with bundle hash appended to it. The bundle hash is calculated using the contents of the bundle.
- __Use Hash of AssetBundle__: The filename is the bundle hash.
- __Use Hash of Filename__: The filename is a hash calculated from the a string derived from the group name.| +|__Asset Load Mode__|Set whether to load assets individually as you request them (the default) or always load all assets in the group together. It is recommended to use __Requested Asset and Dependencies__ for most cases. Refer to [Asset Load Mode](#asset-load-mode) for more information. | +| __Asset Provider__| Defines which Provider class Addressables uses to load assets from the AssetBundles generated from this group. Set this option to __Assets from Bundles Provider__ unless you have a custom Provider implementation to provide assets from an AssetBundle. | +| __Asset Bundle Provider__| Defines which Provider class Addressables uses to load AssetBundles generated from this group. Set this option to __AssetBundle Provider__ unless you have a custom Provider implementation to provide AssetBundles. | + +### AssetBundle compression + +Addressables provides three different options for bundle compression: + +* **Uncompressed**: This option is largest on disk, and fastest to load. If your application has space to spare, consider this option for local content. An advantage of uncompressed bundles is how they handle being patched. If you're developing for a platform where the platform itself provides patching, uncompressed bundles provide the most accurate (smallest) patching. Either of the other compression options cause some bloat of patches. +* **LZ4**: If Uncompressed is not a viable option, then LZ4 should be used for all other local content. This is a chunk-based compression which provides the ability to load parts of the file without needing to load it in its entirety. +* **LZMA**: Use LZMA for all remote content, but not for any local content. It provides the smallest bundle size, but is slow to load. If you store local bundles in LZMA you can create a smaller player, but load times are significantly worse than uncompressed or LZ4. For downloaded bundles, LZMA avoids the slow load time by recompressing the downloaded bundle when storing it in the AssetBundle cache. By default, bundles are stored in the cache with LZ4 compression. + +To set the compression, use the Advanced settings on each group. Compression doesn't affect in-memory size of your loaded content. + +> [!NOTE] +> LZMA AssetBundle compression isn't available for AssetBundles on WebGL. You can use LZ4 compression instead. For more WebGL AssetBundle information, see [Building and running a WebGL project](xref:webgl-building). + +The hardware characteristics of a platform mean that uncompressed bundles aren't always the fastest to load. The maximum speed of loading uncompressed bundles is gated by IO speed, while the speed of loading LZ4-compressed bundles is gated by either IO speed or CPU, depending on hardware. + +On most platforms, loading LZ4-compressed bundles is CPU bound, and loading uncompressed bundles is faster. On platforms that have low IO speeds and high CPU speeds, LZ4 loading can be faster. It's best practice to run performance analysis to validate whether your game fits the common patterns, or needs some unique tweaking. + +More information on Unity's compression selection is available in the [AssetBundle compression manual page](xref:AssetBundles-Cache). + +### AssetBundle CRC + +Different CRC settings are best used depending upon different circumstances. Checking for a change in the file requires the entire AssetBundle to be decompressed and the check processed on the uncompressed bytes. This can impact performance negatively. + +Corruption is likely to only happen during a download, because disk storage is generally reliable and unlikely to have corrupted files after saving to disk. If your AssetBundle contains data that might be tampered with, such as settings values, then you might want to consider enabling CRC checks on saved AssetBundles. + +For local AssetBundles, if the application download performs a check on the download before saving to disk, consider setting this property to __Disabled__ because the download will have already been checked. + +For remote AssetBundles, __Enabled, Excluding cache__ is a good default. When downloading and caching an AssetBundle to disk, the bytes are decompressed and a CRC calculation is done during file saving. This doesn't impact performance and the corruption is most likely to occur during this phase from the download. __Including cache__ is good to use where the data needs to be checked every time such as settings values. + +### Asset Load Mode + +For most platforms and collection of content, you should use __Requested Asset and Dependencies__. This mode only loads what's required for the Assets requested with [`LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetAsync*) or [`LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync``1(System.Collections.Generic.IList{System.Object},System.Action{``0},UnityEngine.AddressableAssets.Addressables.MergeMode)). Objects are loaded based in the order that they appear in a bundle file, which can result in reading the same file multiple times. Enabling the __Contiguous Bundles__ option in [Addressables Build settings](xref:addressables-asset-settings) can help reduce the number of extra file reads. + +This prevents situations where Assets are loaded into memory that aren't used. + +Performance in situations where you load all Assets that are packed together, such as a loading screen. Most types of content have either have similar or improved performance when loading each individually using __Requested Asset and Dependencies__ mode. This mode sequentially reads entire bundle files, which may be more preferable in some platforms. + +> [!NOTE] +> The examples below apply to desktop and mobile platforms. Performance might differ between platforms. The __All Packed Assets and Dependencies__ mode typically performs better than loading assets individually on the Nintendo Switch due its hardware and memory reading limitations. +> You should profile loading performance for your specific content and platform to see what works for your application. + +Loading performance can vary between content type. As an example, large counts of serialized data such as prefabs or ScriptableObjects with direct references to other serialized data load faster using __All Packed Assets and Dependencies__. With some other Assets like Textures, you can often achieve better performance when you load each Asset individually. + +If using [Synchronous Addressables](xref:synchronous-addressables), there is little performance between asset load modes. Because of greater flexibility you should use __Requested Asset and Dependencies__ where you know the content will be loaded synchronously. + +On loading the first Asset with __All Packed Assets and Dependencies__, all Assets are loaded into memory. Later `LoadAssetAsync` calls for Assets from that pack return the preloaded asset without needing to load it. + +Even though all the Assets in a group and any dependencies are loaded in memory when you use the **All Packed Assets and Dependencies** option, the reference count of an individual asset isn't incremented unless you explicitly load it (or it is a dependency of an asset that you load explicitly). If you later call [`Resources.UnloadUnusedAssets`](xref:UnityEngine.Resources.UnloadUnusedAssets), or you load a new scene using [`LoadSceneMode.Single`](xref:UnityEngine.SceneManagement.LoadSceneMode.Single), then any unused assets (those with a reference count of zero) are unloaded. diff --git a/Documentation~/ContentUpdateWorkflow.md b/Documentation~/ContentUpdateWorkflow.md index 77a5245a..7be72538 100644 --- a/Documentation~/ContentUpdateWorkflow.md +++ b/Documentation~/ContentUpdateWorkflow.md @@ -1,15 +1,15 @@ ---- -uid: addressables-content-update-builds ---- - -# Content update builds - -When you need to update your application, you can create a content update build to only distribute the updated content of your application. - -|**Topic**|**Description**| -|---|---| -|[Content update builds overview](content-update-builds-overview.md)| Understand the workflow to update a build.| -|[Build a content update](content-update-build-create.md)|Create a content update build.| -|[Check for content updates at runtime](content-update-builds-check.md)|Understand how to check for updates at runtime.| -|[Content update examples](content-update-examples.md)|Examples and workflows for content updates.| +--- +uid: addressables-content-update-builds +--- + +# Content update builds + +When you need to update your application, you can create a content update build to only distribute the updated content of your application. + +|**Topic**|**Description**| +|---|---| +|[Content update builds overview](content-update-builds-overview.md)| Understand the workflow to update a build.| +|[Build a content update](content-update-build-create.md)|Create a content update build.| +|[Check for content updates at runtime](content-update-builds-check.md)|Understand how to check for updates at runtime.| +|[Content update examples](content-update-examples.md)|Examples and workflows for content updates.| |[Content update build settings](content-update-build-settings.md)|Reference for the various content update build settings.| \ No newline at end of file diff --git a/Documentation~/ContinuousIntegration.md b/Documentation~/ContinuousIntegration.md index a8b53d12..8b8b9921 100644 --- a/Documentation~/ContinuousIntegration.md +++ b/Documentation~/ContinuousIntegration.md @@ -1,34 +1,34 @@ ---- -uid: addressables-ci ---- - -# Use continuous integration to build Addressables - -You can use a continuous integration (CI) system to perform Addressables content builds and your application player builds. This page provides general guidelines for building Addressables with CI systems. - -## Select a content builder - -One of the main choices when building Addressables content is selecting a content builder. By default, if you call [`AddressableAssetSettings.BuildPlayerContent`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.BuildPlayerContent) it uses the `BuildScriptPackedMode` script as the [`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder) instance. The `BuildPlayerContent` method checks the [`ActivePlayerDataBuilder`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.ActivePlayerDataBuilder) setting and calls into that script's `BuildDataImplementation` - -If you've implemented your own custom `IDataBuilder` and want to use it for your CI builds, set the [`ActivePlayerDataBuilderIndex`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.ActivePlayerDataBuilderIndex) property of [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings). By default, you can access the correct settings instance through [`AddressableAssetSettingsDefaultObject.Settings`](xref:UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject.Settings). This index refers to the position of the `IDataBuilder` in the list of [`AddressableAssetSettings.DataBuilders`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.DataBuilders). The following code sample demonstrates how to set a custom `IDataBuilder`: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/CustomDataBuilder.cs#doc_SetCustomBuilder)] - -## Clean the Addressables content builder cache - -`IDataBuilder` implementations define a [`ClearCachedData`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder.ClearCachedData) method, which cleans up any files created by that data builder. For example, the default `BuildScriptPackedMode` script deletes the following: - -- The content catalog -- The serialized settings file -- The built AssetBundles -- Any link.xml files created - -You can call `IDataBuilder.ClearCachedData` as part of your CI process to make sure the build doesn't use files generated by earlier builds. - -## Clean the scriptable build pipeline cache - -Cleaning the Scriptable Build Pipeline (SBP) cache cleans the `BuildCache` folder from the `Library` directory along with all the hash maps generated by the build and the Type Database. The `Library/BuildCache` folder contains `.info` files created by SBP during the build which speeds up subsequent builds by reading data from these `.info` files instead of re-generating data that hasn't changed. - -To clear the SBP cache in a script without opening a prompt dialog, call [`BuildCache.PurgeCache(false)`](xref:UnityEditor.Build.Pipeline.Utilities.BuildCache.PurgeCache*). - -When building Addressables content or player builds with command line arguments or through continuous integration, you should restart the Unity Editor for each target platform. This ensures that Unity can't invoke `-executeMethod` until after script compilation completes for a platform. For more information about using command line arguments, refer to the Unity User Manual documentation [Command line arguments](https://docs.unity3d.com/Manual/CommandLineArguments.html). +--- +uid: addressables-ci +--- + +# Use continuous integration to build Addressables + +You can use a continuous integration (CI) system to perform Addressables content builds and your application player builds. This page provides general guidelines for building Addressables with CI systems. + +## Select a content builder + +One of the main choices when building Addressables content is selecting a content builder. By default, if you call [`AddressableAssetSettings.BuildPlayerContent`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.BuildPlayerContent) it uses the `BuildScriptPackedMode` script as the [`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder) instance. The `BuildPlayerContent` method checks the [`ActivePlayerDataBuilder`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.ActivePlayerDataBuilder) setting and calls into that script's `BuildDataImplementation` + +If you've implemented your own custom `IDataBuilder` and want to use it for your CI builds, set the [`ActivePlayerDataBuilderIndex`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.ActivePlayerDataBuilderIndex) property of [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings). By default, you can access the correct settings instance through [`AddressableAssetSettingsDefaultObject.Settings`](xref:UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject.Settings). This index refers to the position of the `IDataBuilder` in the list of [`AddressableAssetSettings.DataBuilders`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.DataBuilders). The following code sample demonstrates how to set a custom `IDataBuilder`: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/CustomDataBuilder.cs#doc_SetCustomBuilder)] + +## Clean the Addressables content builder cache + +`IDataBuilder` implementations define a [`ClearCachedData`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder.ClearCachedData) method, which cleans up any files created by that data builder. For example, the default `BuildScriptPackedMode` script deletes the following: + +- The content catalog +- The serialized settings file +- The built AssetBundles +- Any link.xml files created + +You can call `IDataBuilder.ClearCachedData` as part of your CI process to make sure the build doesn't use files generated by earlier builds. + +## Clean the scriptable build pipeline cache + +Cleaning the Scriptable Build Pipeline (SBP) cache cleans the `BuildCache` folder from the `Library` directory along with all the hash maps generated by the build and the Type Database. The `Library/BuildCache` folder contains `.info` files created by SBP during the build which speeds up subsequent builds by reading data from these `.info` files instead of re-generating data that hasn't changed. + +To clear the SBP cache in a script without opening a prompt dialog, call [`BuildCache.PurgeCache(false)`](xref:UnityEditor.Build.Pipeline.Utilities.BuildCache.PurgeCache*). + +When building Addressables content or player builds with command line arguments or through continuous integration, you should restart the Unity Editor for each target platform. This ensures that Unity can't invoke `-executeMethod` until after script compilation completes for a platform. For more information about using command line arguments, refer to the Unity User Manual documentation [Command line arguments](https://docs.unity3d.com/Manual/CommandLineArguments.html). diff --git a/Documentation~/DiagnosticTools.md b/Documentation~/DiagnosticTools.md index c7836cc7..9fc24aac 100644 --- a/Documentation~/DiagnosticTools.md +++ b/Documentation~/DiagnosticTools.md @@ -1,15 +1,15 @@ ---- -uid: addressables-diagnostic-tools ---- - -# Diagnostic tools - -The Addressables packages contains diagnostic tools to analyze your Addressables setup, performance, and build results. - -|**Topic**|**Description**| -|---|---| -|[Addressables Profiler module](ProfilerModule.md)| Reference for the Addressables Profiler module, which gives you information about the assets used in your application.| -|[Analyze tool](AnalyzeTool.md)| A tool to analyze and fix issues with the Addressables build based on a set of rules. | -|[Build layout report](BuildLayoutReport.md)|Reference for the build layout report, which gives you information about your build.| -|[Build profile log](BuildProfileLog.md)|Reference for the build profile log, which contains performance information.| +--- +uid: addressables-diagnostic-tools +--- + +# Diagnostic tools + +The Addressables packages contains diagnostic tools to analyze your Addressables setup, performance, and build results. + +|**Topic**|**Description**| +|---|---| +|[Addressables Profiler module](ProfilerModule.md)| Reference for the Addressables Profiler module, which gives you information about the assets used in your application.| +|[Analyze tool](AnalyzeTool.md)| A tool to analyze and fix issues with the Addressables build based on a set of rules. | +|[Build layout report](BuildLayoutReport.md)|Reference for the build layout report, which gives you information about your build.| +|[Build profile log](BuildProfileLog.md)|Reference for the build profile log, which contains performance information.| |[Addressables Report ](addressables-report.md)| Generate a report with detailed information about the current Addressables build. | \ No newline at end of file diff --git a/Documentation~/DownloadDependenciesAsync.md b/Documentation~/DownloadDependenciesAsync.md index b8478262..7f141d1c 100644 --- a/Documentation~/DownloadDependenciesAsync.md +++ b/Documentation~/DownloadDependenciesAsync.md @@ -1,45 +1,45 @@ ---- -uid: addressables-api-download-dependencies-async ---- - -# Preload dependencies - -When you distribute content remotely, you can improve performance by downloading dependencies in advance of when your application needs them. For example, you can download essential content on start up when your game is launched for the first time to make sure that users don't have to wait for content in the middle of gameplay. - -## Download dependencies - -Use the [`Addressables.DownloadDependenciesAsync`](xref:UnityEngine.AddressableAssets.Addressables.DownloadDependenciesAsync*) method to make sure that all the dependencies needed to load an Addressable key are available either in local content installed with the app or the download cache: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/MiscellaneousTopics.cs#doc_Download)] - -> [!TIP] -> If you have a set of assets that you want to pre-download, you can assign the same label, such as `preload`, to the assets and use that label as the key when calling [`Addressables.DownloadDependenciesAsync`](xref:UnityEngine.AddressableAssets.Addressables.DownloadDependenciesAsync*). Addressables downloads all the AssetBundles containing an asset with that label if not already available, along with any bundles containing the assets' dependencies. - -## Get progress updates - -An [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) instance provides the following ways to get progress updates: - -* [`AsyncOperationHandle.PercentComplete`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.PercentComplete): Reports the percentage of sub-operations that have finished. For example, if an operation uses six sub-operations to perform its task, the `PercentComplete` indicates the entire operation is 50% complete when three of those operations have finished (it doesn't matter how much data each operation loads). -* [`AsyncOperationHandle.GetDownloadStatus`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.GetDownloadStatus): Returns a [`DownloadStatus`](xref:UnityEngine.ResourceManagement.AsyncOperations.DownloadStatus) struct that reports the percentage in terms of total download size. For example, if an operation has six sub-operations, but the first operation represented 50% of the total download size, then `GetDownloadStatus` indicates the operation is 50% complete when the first operation finishes. - -The following example illustrates how you can use `GetDownloadStatus` to check the status and dispatch progress events during the download: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/PreloadWithProgress.cs#doc_Preload)] - -To discover how much data you need to download to load one or more assets, you can call [`Addressables.GetDownloadSizeAsync`](xref:UnityEngine.AddressableAssets.Addressables.GetDownloadSizeAsync*): - -[!code-cs[sample](../Tests/Editor/DocExampleCode/PreloadWithProgress.cs#doc_DownloadSize)] - -The `Result` of the completed operation is the number of bytes that must be downloaded. If Addressables has already cached all the required AssetBundles, then `Result` is zero. - -Always release the download operation handle after you have read the `Result` object. If you don't need to access the results of the download operation, you can automatically release the handle by setting the `autoReleaseHandle` parameter to true, as shown in the following example: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/Preload.cs#doc_Preload)] - -### Clear the dependency cache - -If you want to clear any AssetBundles cached by Addressables, call [`Addressables.ClearDependencyCacheAsync`](xref:UnityEngine.AddressableAssets.Addressables.ClearDependencyCacheAsync*). This method clears the cached AssetBundles containing the assets identified by a key along with any bundles containing those assets' dependencies. - -`ClearDependencyCacheAsync` only clears assets bundles related to the specified key. If you updated the content catalog so the key no longer exists or it no longer depends on the same AssetBundles, then these bundles remain in the cache until they expire based on [cache settings](xref:UnityEngine.Cache). - -To clear all AssetBundles, you can use the methods in the [UnityEngine.Caching](xref:UnityEngine.Caching) class. +--- +uid: addressables-api-download-dependencies-async +--- + +# Preload dependencies + +When you distribute content remotely, you can improve performance by downloading dependencies in advance of when your application needs them. For example, you can download essential content on start up when your game is launched for the first time to make sure that users don't have to wait for content in the middle of gameplay. + +## Download dependencies + +Use the [`Addressables.DownloadDependenciesAsync`](xref:UnityEngine.AddressableAssets.Addressables.DownloadDependenciesAsync*) method to make sure that all the dependencies needed to load an Addressable key are available either in local content installed with the app or the download cache: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/MiscellaneousTopics.cs#doc_Download)] + +> [!TIP] +> If you have a set of assets that you want to pre-download, you can assign the same label, such as `preload`, to the assets and use that label as the key when calling [`Addressables.DownloadDependenciesAsync`](xref:UnityEngine.AddressableAssets.Addressables.DownloadDependenciesAsync*). Addressables downloads all the AssetBundles containing an asset with that label if not already available, along with any bundles containing the assets' dependencies. + +## Get progress updates + +An [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) instance provides the following ways to get progress updates: + +* [`AsyncOperationHandle.PercentComplete`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.PercentComplete): Reports the percentage of sub-operations that have finished. For example, if an operation uses six sub-operations to perform its task, the `PercentComplete` indicates the entire operation is 50% complete when three of those operations have finished (it doesn't matter how much data each operation loads). +* [`AsyncOperationHandle.GetDownloadStatus`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.GetDownloadStatus): Returns a [`DownloadStatus`](xref:UnityEngine.ResourceManagement.AsyncOperations.DownloadStatus) struct that reports the percentage in terms of total download size. For example, if an operation has six sub-operations, but the first operation represented 50% of the total download size, then `GetDownloadStatus` indicates the operation is 50% complete when the first operation finishes. + +The following example illustrates how you can use `GetDownloadStatus` to check the status and dispatch progress events during the download: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/PreloadWithProgress.cs#doc_Preload)] + +To discover how much data you need to download to load one or more assets, you can call [`Addressables.GetDownloadSizeAsync`](xref:UnityEngine.AddressableAssets.Addressables.GetDownloadSizeAsync*): + +[!code-cs[sample](../Tests/Editor/DocExampleCode/PreloadWithProgress.cs#doc_DownloadSize)] + +The `Result` of the completed operation is the number of bytes that must be downloaded. If Addressables has already cached all the required AssetBundles, then `Result` is zero. + +Always release the download operation handle after you have read the `Result` object. If you don't need to access the results of the download operation, you can automatically release the handle by setting the `autoReleaseHandle` parameter to true, as shown in the following example: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/Preload.cs#doc_Preload)] + +### Clear the dependency cache + +If you want to clear any AssetBundles cached by Addressables, call [`Addressables.ClearDependencyCacheAsync`](xref:UnityEngine.AddressableAssets.Addressables.ClearDependencyCacheAsync*). This method clears the cached AssetBundles containing the assets identified by a key along with any bundles containing those assets' dependencies. + +`ClearDependencyCacheAsync` only clears assets bundles related to the specified key. If you updated the content catalog so the key no longer exists or it no longer depends on the same AssetBundles, then these bundles remain in the cache until they expire based on [cache settings](xref:UnityEngine.Cache). + +To clear all AssetBundles, you can use the methods in the [UnityEngine.Caching](xref:UnityEngine.Caching) class. diff --git a/Documentation~/GetRuntimeAddress.md b/Documentation~/GetRuntimeAddress.md index a90bde2c..bdf18333 100644 --- a/Documentation~/GetRuntimeAddress.md +++ b/Documentation~/GetRuntimeAddress.md @@ -1,17 +1,17 @@ ---- -uid: addressables-get-address ---- - -# Get addresses at runtime - -By default, Addressables uses the address you assign to an asset as the [`PrimaryKey`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation.PrimaryKey) value of its [`IResourceLocation`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation) instance. - -If you disable the [Include Addresses in Catalog](xref:addressables-content-packing-and-loading-schema) option of the Addressables group to which the asset belongs, the `PrimaryKey` can be a GUID, label, or an empty string. If you want to get the address of an asset that you load with an `AssetReference` or label, you can load the asset's locations, as described in [Load assets by location](xref:addressables-api-load-asset-async) documentation. You can then use the `IResourceLocation` instance to both access the `PrimaryKey` value and to load the asset. - -The following example gets the address of the asset assigned to an [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) object named `MyRef1`: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/MiscellaneousTopics.cs#doc_AddressFromReference)] - -Labels often refer to multiple assets. The following example illustrates how to load multiple prefab assets and use their primary key value to add them to a dictionary: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/MiscellaneousTopics.cs#doc_PreloadHazards)] +--- +uid: addressables-get-address +--- + +# Get addresses at runtime + +By default, Addressables uses the address you assign to an asset as the [`PrimaryKey`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation.PrimaryKey) value of its [`IResourceLocation`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation) instance. + +If you disable the [Include Addresses in Catalog](xref:addressables-content-packing-and-loading-schema) option of the Addressables group to which the asset belongs, the `PrimaryKey` can be a GUID, label, or an empty string. If you want to get the address of an asset that you load with an `AssetReference` or label, you can load the asset's locations, as described in [Load assets by location](xref:addressables-api-load-asset-async) documentation. You can then use the `IResourceLocation` instance to both access the `PrimaryKey` value and to load the asset. + +The following example gets the address of the asset assigned to an [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) object named `MyRef1`: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/MiscellaneousTopics.cs#doc_AddressFromReference)] + +Labels often refer to multiple assets. The following example illustrates how to load multiple prefab assets and use their primary key value to add them to a dictionary: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/MiscellaneousTopics.cs#doc_PreloadHazards)] diff --git a/Documentation~/GroupSchemas.md b/Documentation~/GroupSchemas.md index 4266a8b4..4515d410 100644 --- a/Documentation~/GroupSchemas.md +++ b/Documentation~/GroupSchemas.md @@ -1,48 +1,48 @@ ---- -uid: addressables-group-schemas ---- - -# Group settings and schemas overview - -Group settings set how Unity treats the assets in a group in content builds. Group settings control properties such as the location where Unity builds AssetBundles or bundle compression settings. - -To open a group's settings, open the [Addressables Groups window](GroupsWindow.md) (**Window > Asset Management > Addressables > Groups**), then select a group. The group's settings are displayed in the Inspector. - -A group's settings are declared in Schema objects attached to the group. When you create a group with the [Packed Assets template](xref:group-templates), the Content Packing & Loading and Content Update Restriction schemas define the settings for the group. The default [Build scripts](xref:addressables-builds) expect these settings. - -![](images/groups-group-settings.png)
*The Inspector window for the Default Local Group* - -> [!NOTE] -> If you create a group with the Blank template, then Unity doesn't attach any schemas to the group. The default build script can't process assets in a blank group. - -## Schemas - -A group schema is a `ScriptableObject` that defines a collection of settings for an Addressables group. You can assign any number of schemas to a group. The Addressables system defines a number of schemas for its own purposes. You can also create custom schemas to support your own build scripts and utilities. - -The built-in schemas include: - -* __Content Packing & Loading__: The main Addressables schema used by the default build script and defines the settings for building and loading Addressable assets. For information on the settings for this schema, refer to [Content Packing & Loading schema reference](ContentPackingAndLoadingSchema.md). -* __Content Update Restrictions__: Defines settings for making differential updates of an earlier build. For more information about this schema refer to [Content Update Restriction schema reference](UpdateRestrictionSchema.md). - -## Create a custom schema - -To create your own schema, extend the [`AddressableAssetGroupSchema`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroupSchema) class, which is a kind of `ScriptableObject`: - -```csharp -using UnityEditor.AddressableAssets.Settings; - -public class __CustomSchema __: AddressableAssetGroupSchema -{ - public string CustomDescription; -} -``` - -Once you've defined a custom schema object, you can add it to existing groups and group templates using the Add Schema buttons in the Inspector windows of those entities. - -You might also want to create a custom Unity Editor script to help users interact with your custom settings. For more information, refer to [Custom Inspector scripts](xref:VariablesAndTheInspector). - -In a build script, you can access the schema settings for a group using its [`AddressableAssetGroup`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup) object. - -## Additional resources - +--- +uid: addressables-group-schemas +--- + +# Group settings and schemas overview + +Group settings set how Unity treats the assets in a group in content builds. Group settings control properties such as the location where Unity builds AssetBundles or bundle compression settings. + +To open a group's settings, open the [Addressables Groups window](GroupsWindow.md) (**Window > Asset Management > Addressables > Groups**), then select a group. The group's settings are displayed in the Inspector. + +A group's settings are declared in Schema objects attached to the group. When you create a group with the [Packed Assets template](xref:group-templates), the Content Packing & Loading and Content Update Restriction schemas define the settings for the group. The default [Build scripts](xref:addressables-builds) expect these settings. + +![](images/groups-group-settings.png)
*The Inspector window for the Default Local Group* + +> [!NOTE] +> If you create a group with the Blank template, then Unity doesn't attach any schemas to the group. The default build script can't process assets in a blank group. + +## Schemas + +A group schema is a `ScriptableObject` that defines a collection of settings for an Addressables group. You can assign any number of schemas to a group. The Addressables system defines a number of schemas for its own purposes. You can also create custom schemas to support your own build scripts and utilities. + +The built-in schemas include: + +* __Content Packing & Loading__: The main Addressables schema used by the default build script and defines the settings for building and loading Addressable assets. For information on the settings for this schema, refer to [Content Packing & Loading schema reference](ContentPackingAndLoadingSchema.md). +* __Content Update Restrictions__: Defines settings for making differential updates of an earlier build. For more information about this schema refer to [Content Update Restriction schema reference](UpdateRestrictionSchema.md). + +## Create a custom schema + +To create your own schema, extend the [`AddressableAssetGroupSchema`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroupSchema) class, which is a kind of `ScriptableObject`: + +```csharp +using UnityEditor.AddressableAssets.Settings; + +public class __CustomSchema __: AddressableAssetGroupSchema +{ + public string CustomDescription; +} +``` + +Once you've defined a custom schema object, you can add it to existing groups and group templates using the Add Schema buttons in the Inspector windows of those entities. + +You might also want to create a custom Unity Editor script to help users interact with your custom settings. For more information, refer to [Custom Inspector scripts](xref:VariablesAndTheInspector). + +In a build script, you can access the schema settings for a group using its [`AddressableAssetGroup`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup) object. + +## Additional resources + * [Content Packing & Loading schema reference](ContentPackingAndLoadingSchema.md). \ No newline at end of file diff --git a/Documentation~/GroupTemplates.md b/Documentation~/GroupTemplates.md index 0e0d93a7..635eca0e 100644 --- a/Documentation~/GroupTemplates.md +++ b/Documentation~/GroupTemplates.md @@ -1,20 +1,20 @@ ---- -uid: group-templates ---- - -# Create a group template - -A group template defines which types of schema objects Unity creates for a new group. The Addressables system includes the Packed Assets template, which includes all the settings needed to build and load Addressables using the default build scripts. - -If you want to create your own build scripts or utilities that need additional settings, you can define these settings in your own schema objects and create your own group templates. The following instructions describe how to do this: - -1. Navigate to the desired location in your Assets folder using the Project panel. -2. Create a Blank Group Template (menu: **Assets** > **Addressables** > **Group Templates** > **Blank Group Templates**). -3. Assign a name to the template. -4. In the Inspector window, add a description, if desired. -5. Click the **Add Schema** button and choose from the list of schemas. - -Repeat these steps to add as many new schemas as needed. - -> [!NOTE] -> If you use the default build script, a group must use the __Content Packing & Loading__ schema. If you use content update builds, a group must include the __Content Update Restrictions__ schema. Refer to [Builds](xref:addressables-builds) for more information. +--- +uid: group-templates +--- + +# Create a group template + +A group template defines which types of schema objects Unity creates for a new group. The Addressables system includes the Packed Assets template, which includes all the settings needed to build and load Addressables using the default build scripts. + +If you want to create your own build scripts or utilities that need additional settings, you can define these settings in your own schema objects and create your own group templates. The following instructions describe how to do this: + +1. Navigate to the desired location in your Assets folder using the Project panel. +2. Create a Blank Group Template (menu: **Assets** > **Addressables** > **Group Templates** > **Blank Group Templates**). +3. Assign a name to the template. +4. In the Inspector window, add a description, if desired. +5. Click the **Add Schema** button and choose from the list of schemas. + +Repeat these steps to add as many new schemas as needed. + +> [!NOTE] +> If you use the default build script, a group must use the __Content Packing & Loading__ schema. If you use content update builds, a group must include the __Content Update Restrictions__ schema. Refer to [Builds](xref:addressables-builds) for more information. diff --git a/Documentation~/Groups.md b/Documentation~/Groups.md index 2e41a54b..d6205527 100644 --- a/Documentation~/Groups.md +++ b/Documentation~/Groups.md @@ -1,17 +1,17 @@ ---- -uid: addressables-groups ---- - -# Groups overview - -A group is the main organizational unit of the Addressables system. Create and manage your groups and the assets they contain with the [Addressables Groups window](xref:addressables-groups-window). - -|**Topic**|**Description**| -|---|---| -|[Groups introduction](groups-intro.md)|Understand groups and how to work with them.| -|[Manage and create groups](groups-create.md)|Create profiles in the Unity Editor.| -|[Labels overview](Labels.md)|Understand and work with labels.| -|[Create a group template](GroupTemplates.md)|Create group templates.| -|[Pack groups into AssetBundles](PackingGroupsAsBundles.md)|Understand how you can put groups into AssetBundles.| -| [Addressables Groups window reference](GroupsWindow.md)|Reference information for the Addressables Groups window.| -|[Group settings and schemas overview](GroupSchemas.md)|Reference information for group settings and their schemas.| +--- +uid: addressables-groups +--- + +# Groups overview + +A group is the main organizational unit of the Addressables system. Create and manage your groups and the assets they contain with the [Addressables Groups window](xref:addressables-groups-window). + +|**Topic**|**Description**| +|---|---| +|[Groups introduction](groups-intro.md)|Understand groups and how to work with them.| +|[Manage and create groups](groups-create.md)|Create profiles in the Unity Editor.| +|[Labels overview](Labels.md)|Understand and work with labels.| +|[Create a group template](GroupTemplates.md)|Create group templates.| +|[Pack groups into AssetBundles](PackingGroupsAsBundles.md)|Understand how you can put groups into AssetBundles.| +| [Addressables Groups window reference](GroupsWindow.md)|Reference information for the Addressables Groups window.| +|[Group settings and schemas overview](GroupSchemas.md)|Reference information for group settings and their schemas.| diff --git a/Documentation~/GroupsWindow.md b/Documentation~/GroupsWindow.md index b3bd5590..b282d2fe 100644 --- a/Documentation~/GroupsWindow.md +++ b/Documentation~/GroupsWindow.md @@ -1,94 +1,94 @@ ---- -uid: addressables-groups-window ---- - -# Addressables Groups window reference - -Use the Addressables Groups window to manage your groups and Addressable assets. To open the window, go to **Window** > **Asset Management** > **Addressables** > **Groups**. - -The Groups window also serves as a central location for starting content builds and accessing the tools and settings of the Addressables system. - -A group is the main organizational unit of the Addressables system. Use this window to create and manage your groups and the assets they contain. - -![](images/addressables-groups-window.png)

*The Addressables Groups window showing the toolbar and list of groups and assets.* - -## Group list - -The Group list displays the Addressable groups in your Project. Expand a group in the list to display the assets that it contains. You can also expand composite assets, such as sprite sheets, to display the sub-objects they contain. - -When you first install the Addressables package, the Groups window displays two groups of assets: - -* __Default Local Group (Default)__: Initially empty, Unity adds any assets you make Addressable to this group. The group is set up so that its assets are built to your local build path and included in your Project builds. You can change the name, settings, and make another group the default group, if desired. The settings of the default group are also used to create [shared AssetBundles](xref:addressables-build-artifacts). - -The list columns contain the following information: - -| **Column**|**Description** | -|---|---| -| __Notifications__| Any notifications about a Group, or asset, that's flagged during the build. -| __Group Name \ Addressable Name__| The name of the item. For groups, this is an arbitrary name that you can assign. For assets, this is the Addressable address. You can edit the name or address using the context menu. | -| __Icon__| The Unity asset icon based on asset type. | -| __Path__| The path to the source asset in your project. | -| __Labels__| Displays any labels assigned to the asset. Click on a label entry to change the assigned labels or to manage your label definitions. | - -To sort the assets displayed in the group list, select one of the column headers. This sorts the assets within each group, but doesn't reorder the groups. To change the order that the groups are displayed, drag them into the desired position. - -## Groups window toolbar - -The toolbar at the top of the Addressables Group window provides the following settings: - -|**Setting**|**Description**| -|---|---| -|**New**|Choose a template to create a new group, or blank for no schema. Refer to [Group templates](xref:group-templates) for information about creating your own templates.| -|**Profile**|Set the active Profile to select the paths used for building and loading Addressables. Choose an existing profile or select __Manage Profiles__ to open the [Profiles window](xref:addressables-profiles).| -|**Tools**|Open the various Addressables tools available. Choose from:

- __Inspect System Settings__: Open the [Addressables Settings](xref:addressables-asset-settings) Inspector.
- __Check for Content Update Restrictions__: Run a pre-update content check. Refer to [Update Restrictions](xref:addressables-content-update-builds) for more information.
- __Window__: Open other Addressables system windows: [Profiles](xref:addressables-profiles), [Labels](xref:addressables-labels), or the [Addressables Report](addressables-report.md) window.
- __Groups View__: Set Group window display options:
- __Show Sprite and Subobject Addresses__: Enable to display sprite and sub-objects in the Group list or just the parent object
- __Group Hierarchy with Dashes__: Enable to display groups that contain dashes `-` in their names as if the dashes represented a group hierarchy. For example, if you name two groups `x-y-z` and `x-y-w`, the window displays an entry called `x` with a child called `y`, which contains two groups, called `x-y-z` and `x-y-w`. Enabling this option affects the group display only.| -|**Play mode Script**|Set the active Play mode Script. The active Play mode Script determines how Addressables are loaded in the Editor Play mode. Refer to [Play mode Scripts](#play-mode-scripts) for more information.| -|**Build**|Select a content build command:

- __New Build__: Choose a build script to run a full content build.
- __Update a Previous Build__: Run a differential update based on an earlier build.
- __Clear Build Cache__: choose a command to clean existing build artifacts.

Refer to [Builds](xref:addressables-builds) for more information.| - -## Play mode Scripts - -The active Play mode script determines how the Addressable system accesses Addressable assets when you run your game in Play mode. When you select a Play mode script, it remains the active script until you choose a different one. The Play mode Script has no effect on asset loading when you build and run your application outside the Unity Editor. - -The Play mode Scripts include: - -* __Use Asset Database__: Loads assets directly from the Editor Asset Database, which is also used for all non-Addressable assets. You don't have to build your Addressable content when using this option. -* __Use Existing Build__: Loads assets from bundles created by an earlier content build. You must run a full build using a Build Script such as [Default Build Script](xref:addressables-builds) before using this option. Remote content must be hosted at the __RemoteLoadPath__ of the Profile used to build the content. - -## Find an asset - -To locate an Addressable Asset in the Groups window, type all or part of its address, path, or a label into the filter control on the Groups window toolbar. - -![](images/addressables-groups-find.png)
*Filtering the group list by the string "NP" to find all assets labeled NPC* - -To locate the asset in your project, select it in the Groups window. Unity then selects the asset in the Project window and displays the asset's details in the Inspector window. - -> [!TIP] -> * To view the groups of the assets found, enable __Hierarchical Search__. Disable this option to only display groups if they match the search string. Select the magnifying glass icon in the search box to enable or disable __Hierarchical Search__. -> * To view sub-object addresses, such as the Sprites in a Sprite Atlas, enable the __Show Sprite and Subobject Addresses__ option using the __Tools__ menu on the Groups window toolbar. - - -## Group context menu - -To open the Group context menu and access group-related commands, right-click on a group name. - -| **Command**| **Description** | -|:---|:---| -| __Remove Group(s)__| Removes the Group and deletes its associated ScriptableObject asset. Unity reverts any assets in the group into non-Addressable assets. | -| __Simplify Addressable Names__| Shortens the name of assets in the group by removing path-like components and extensions. | -| __Set as Default__| Sets the group as the default group. When you mark an asset as Addressable without explicitly assigning a group, Unity adds the asset to the default group. | -| __Inspect Group Settings__| Selects the group asset in the Unity Project window and in the Inspector window so that you can view the settings. | -| __Rename__| Enables you to edit the name of the group. | -| __Create New Group__| Creates a new group based on a group template. | - -## Asset context menu - -To open the Addressable asset context menu and access asset-related commands, right-click on an asset. - -| **Command**| **Description** | -|:---|:---| -| __Move Addressables to Group__| Move the selected assets to a different, existing group. | -| __Move Addressables to New Group__| Create a new group with the same settings as the current group and move the selected assets to it. | -| __Remove Addressables__| Remove the selected assets from the Group and make the assets non-Addressable. | -| __Simplify Addressable Names__| Shortens the names of the selected assets by removing path-like components and extensions. | -| __Copy Address to CLipboard__| Copies the asset's assigned address string to your system Clipboard. | -| __Change Address__| Edit the asset's name. | -| __Create New Group__| Create a new group based on a group template. This doesn't move the selected assets. | +--- +uid: addressables-groups-window +--- + +# Addressables Groups window reference + +Use the Addressables Groups window to manage your groups and Addressable assets. To open the window, go to **Window** > **Asset Management** > **Addressables** > **Groups**. + +The Groups window also serves as a central location for starting content builds and accessing the tools and settings of the Addressables system. + +A group is the main organizational unit of the Addressables system. Use this window to create and manage your groups and the assets they contain. + +![](images/addressables-groups-window.png)

*The Addressables Groups window showing the toolbar and list of groups and assets.* + +## Group list + +The Group list displays the Addressable groups in your Project. Expand a group in the list to display the assets that it contains. You can also expand composite assets, such as sprite sheets, to display the sub-objects they contain. + +When you first install the Addressables package, the Groups window displays two groups of assets: + +* __Default Local Group (Default)__: Initially empty, Unity adds any assets you make Addressable to this group. The group is set up so that its assets are built to your local build path and included in your Project builds. You can change the name, settings, and make another group the default group, if desired. The settings of the default group are also used to create [shared AssetBundles](xref:addressables-build-artifacts). + +The list columns contain the following information: + +| **Column**|**Description** | +|---|---| +| __Notifications__| Any notifications about a Group, or asset, that's flagged during the build. +| __Group Name \ Addressable Name__| The name of the item. For groups, this is an arbitrary name that you can assign. For assets, this is the Addressable address. You can edit the name or address using the context menu. | +| __Icon__| The Unity asset icon based on asset type. | +| __Path__| The path to the source asset in your project. | +| __Labels__| Displays any labels assigned to the asset. Click on a label entry to change the assigned labels or to manage your label definitions. | + +To sort the assets displayed in the group list, select one of the column headers. This sorts the assets within each group, but doesn't reorder the groups. To change the order that the groups are displayed, drag them into the desired position. + +## Groups window toolbar + +The toolbar at the top of the Addressables Group window provides the following settings: + +|**Setting**|**Description**| +|---|---| +|**New**|Choose a template to create a new group, or blank for no schema. Refer to [Group templates](xref:group-templates) for information about creating your own templates.| +|**Profile**|Set the active Profile to select the paths used for building and loading Addressables. Choose an existing profile or select __Manage Profiles__ to open the [Profiles window](xref:addressables-profiles).| +|**Tools**|Open the various Addressables tools available. Choose from:

- __Inspect System Settings__: Open the [Addressables Settings](xref:addressables-asset-settings) Inspector.
- __Check for Content Update Restrictions__: Run a pre-update content check. Refer to [Update Restrictions](xref:addressables-content-update-builds) for more information.
- __Window__: Open other Addressables system windows: [Profiles](xref:addressables-profiles), [Labels](xref:addressables-labels), or the [Addressables Report](addressables-report.md) window.
- __Groups View__: Set Group window display options:
- __Show Sprite and Subobject Addresses__: Enable to display sprite and sub-objects in the Group list or just the parent object
- __Group Hierarchy with Dashes__: Enable to display groups that contain dashes `-` in their names as if the dashes represented a group hierarchy. For example, if you name two groups `x-y-z` and `x-y-w`, the window displays an entry called `x` with a child called `y`, which contains two groups, called `x-y-z` and `x-y-w`. Enabling this option affects the group display only.| +|**Play mode Script**|Set the active Play mode Script. The active Play mode Script determines how Addressables are loaded in the Editor Play mode. Refer to [Play mode Scripts](#play-mode-scripts) for more information.| +|**Build**|Select a content build command:

- __New Build__: Choose a build script to run a full content build.
- __Update a Previous Build__: Run a differential update based on an earlier build.
- __Clear Build Cache__: choose a command to clean existing build artifacts.

Refer to [Builds](xref:addressables-builds) for more information.| + +## Play mode Scripts + +The active Play mode script determines how the Addressable system accesses Addressable assets when you run your game in Play mode. When you select a Play mode script, it remains the active script until you choose a different one. The Play mode Script has no effect on asset loading when you build and run your application outside the Unity Editor. + +The Play mode Scripts include: + +* __Use Asset Database__: Loads assets directly from the Editor Asset Database, which is also used for all non-Addressable assets. You don't have to build your Addressable content when using this option. +* __Use Existing Build__: Loads assets from bundles created by an earlier content build. You must run a full build using a Build Script such as [Default Build Script](xref:addressables-builds) before using this option. Remote content must be hosted at the __RemoteLoadPath__ of the Profile used to build the content. + +## Find an asset + +To locate an Addressable Asset in the Groups window, type all or part of its address, path, or a label into the filter control on the Groups window toolbar. + +![](images/addressables-groups-find.png)
*Filtering the group list by the string "NP" to find all assets labeled NPC* + +To locate the asset in your project, select it in the Groups window. Unity then selects the asset in the Project window and displays the asset's details in the Inspector window. + +> [!TIP] +> * To view the groups of the assets found, enable __Hierarchical Search__. Disable this option to only display groups if they match the search string. Select the magnifying glass icon in the search box to enable or disable __Hierarchical Search__. +> * To view sub-object addresses, such as the Sprites in a Sprite Atlas, enable the __Show Sprite and Subobject Addresses__ option using the __Tools__ menu on the Groups window toolbar. + + +## Group context menu + +To open the Group context menu and access group-related commands, right-click on a group name. + +| **Command**| **Description** | +|:---|:---| +| __Remove Group(s)__| Removes the Group and deletes its associated ScriptableObject asset. Unity reverts any assets in the group into non-Addressable assets. | +| __Simplify Addressable Names__| Shortens the name of assets in the group by removing path-like components and extensions. | +| __Set as Default__| Sets the group as the default group. When you mark an asset as Addressable without explicitly assigning a group, Unity adds the asset to the default group. | +| __Inspect Group Settings__| Selects the group asset in the Unity Project window and in the Inspector window so that you can view the settings. | +| __Rename__| Enables you to edit the name of the group. | +| __Create New Group__| Creates a new group based on a group template. | + +## Asset context menu + +To open the Addressable asset context menu and access asset-related commands, right-click on an asset. + +| **Command**| **Description** | +|:---|:---| +| __Move Addressables to Group__| Move the selected assets to a different, existing group. | +| __Move Addressables to New Group__| Create a new group with the same settings as the current group and move the selected assets to it. | +| __Remove Addressables__| Remove the selected assets from the Group and make the assets non-Addressable. | +| __Simplify Addressable Names__| Shortens the names of the selected assets by removing path-like components and extensions. | +| __Copy Address to CLipboard__| Copies the asset's assigned address string to your system Clipboard. | +| __Change Address__| Edit the asset's name. | +| __Create New Group__| Create a new group based on a group template. This doesn't move the selected assets. | diff --git a/Documentation~/InitializeAsync.md b/Documentation~/InitializeAsync.md index fccabea0..d0419099 100644 --- a/Documentation~/InitializeAsync.md +++ b/Documentation~/InitializeAsync.md @@ -1,56 +1,56 @@ ---- -uid: addressables-api-initialize-async ---- - -# Addressables initialization - -The Addressables system initializes itself at runtime the first time you load an Addressable or make another call to an Addressable API. Call [`Addressables.InitializeAsync`](xref:UnityEngine.AddressableAssets.Addressables.InitializeAsync*) to initialize Addressables earlier. This method does nothing if initialization has already happened. - -## Initialization tasks - -The initialization operation performs the following tasks: - -* Sets up the [`ResourceManager`](xref:UnityEngine.ResourceManagement.ResourceManager) and the [`ResourceLocators`](xref:UnityEngine.AddressableAssets.ResourceLocators). -* Loads configuration data that Addressables creates from StreamingAssets. -* Executes any [initialization object](xref:addressables-asset-settings) operations. -* Loads the content catalog. By default, Addressables first checks for updates to the content catalog and downloads a new catalog if available. - -The following Addressables settings can change initialization behavior: - -* [Only update catalogs manually](xref:addressables-asset-settings): Addressables won't automatically check for an updated catalog. Refer to [Updating catalogs](xref:addressables-api-load-content-catalog-async) for information about manually updating catalogs. -* [Build Remote Catalog](xref:addressables-asset-settings): Addressables won't try to load remote content without a remote catalog. -* [Custom certificate handler](xref:addressables-asset-settings): Identify a custom certificate handler if you need one to access a remote asset hosting service. -* [Initialization object list](xref:addressables-asset-settings): Add the [`IObjectInitializationDataProvider`](xref:UnityEngine.ResourceManagement.Util.IObjectInitializationDataProvider) ScriptableObject to your application that Addressables invokes during the initialization operation. - -Set the following runtime properties before the initialization operation starts: - -* [Custom URL transform function](xref:addressables-api-transform-internal-id). -* [ResourceManager exception handler](xref:UnityEngine.ResourceManagement.ResourceManager.ExceptionHandler). -* Static properties used for any custom runtime placeholders in [Profile variables](xref:addressables-profile-variables). - -## Initialization objects - -You can attach objects to the Addressable Assets settings and pass them to the initialization process at runtime. For example, you can create a [`CacheInitializationSettings`](xref:UnityEditor.AddressableAssets.Settings.CacheInitializationSettings) object to initialize Unity's [`Cache`](xref:UnityEngine.Cache) settings at runtime. - -To create your own types of initialization object, create a ScriptableObject that implements the [`IObjectInitializationDataProvider`](xref:UnityEngine.ResourceManagement.Util.IObjectInitializationDataProvider) interface. Use this object to create the [`ObjectInitializationData`](xref:UnityEngine.ResourceManagement.Util.ObjectInitializationData) asset that Addressables includes with your the runtime data. - -### Cache initialization objects - -Use a [`CacheInitializationSettings`](xref:UnityEditor.AddressableAssets.Settings.CacheInitializationSettings) object to initialize Unity's [`Cache`](xref:UnityEngine.Cache) settings at runtime. - -To specify the cache initialization settings that the Addressables system uses: - -1. Create a CacheInitializationSettings asset (menu: __Assets > Addressables > Initialization > Cache Initialization Settings__). -2. Select the new asset file in the Project panel to view the settings in the Inspector - ![](images/cache-initialization-settings.png) - -3. Adjust the settings as desired. -4. Open the Addressables Settings Inspector (menu: __Window > Asset Management > Addressables > Settings__). -5. In the __Initialization Objects__ section of the Inspector, click the __+__ button to add a new object to the list. -6. Select the CacheInitializationSettings asset in the File dialog and click __Open__. -7. The cache settings object is added to the list. - -When Addressables initializes at runtime, it applies these settings to the default Unity `Cache`. The settings apply to all AssetBundles in the default cache, not just those downloaded by the Addressables system. Refer to [Caching](xref:UnityEngine.Caching) for more information about the Unity cache system. - -> [!TIP] -> Android applications built with Unity 2020.1 or earlier, or running on Android 9 or earlier can only play videos from uncompressed AssetBundles. To disable recompression of the cache, use a `CacheInitializationSettings` object by disabling the __Compress Bundles__ option. +--- +uid: addressables-api-initialize-async +--- + +# Addressables initialization + +The Addressables system initializes itself at runtime the first time you load an Addressable or make another call to an Addressable API. Call [`Addressables.InitializeAsync`](xref:UnityEngine.AddressableAssets.Addressables.InitializeAsync*) to initialize Addressables earlier. This method does nothing if initialization has already happened. + +## Initialization tasks + +The initialization operation performs the following tasks: + +* Sets up the [`ResourceManager`](xref:UnityEngine.ResourceManagement.ResourceManager) and the [`ResourceLocators`](xref:UnityEngine.AddressableAssets.ResourceLocators). +* Loads configuration data that Addressables creates from StreamingAssets. +* Executes any [initialization object](xref:addressables-asset-settings) operations. +* Loads the content catalog. By default, Addressables first checks for updates to the content catalog and downloads a new catalog if available. + +The following Addressables settings can change initialization behavior: + +* [Only update catalogs manually](xref:addressables-asset-settings): Addressables won't automatically check for an updated catalog. Refer to [Updating catalogs](xref:addressables-api-load-content-catalog-async) for information about manually updating catalogs. +* [Build Remote Catalog](xref:addressables-asset-settings): Addressables won't try to load remote content without a remote catalog. +* [Custom certificate handler](xref:addressables-asset-settings): Identify a custom certificate handler if you need one to access a remote asset hosting service. +* [Initialization object list](xref:addressables-asset-settings): Add the [`IObjectInitializationDataProvider`](xref:UnityEngine.ResourceManagement.Util.IObjectInitializationDataProvider) ScriptableObject to your application that Addressables invokes during the initialization operation. + +Set the following runtime properties before the initialization operation starts: + +* [Custom URL transform function](xref:addressables-api-transform-internal-id). +* [ResourceManager exception handler](xref:UnityEngine.ResourceManagement.ResourceManager.ExceptionHandler). +* Static properties used for any custom runtime placeholders in [Profile variables](xref:addressables-profile-variables). + +## Initialization objects + +You can attach objects to the Addressable Assets settings and pass them to the initialization process at runtime. For example, you can create a [`CacheInitializationSettings`](xref:UnityEditor.AddressableAssets.Settings.CacheInitializationSettings) object to initialize Unity's [`Cache`](xref:UnityEngine.Cache) settings at runtime. + +To create your own types of initialization object, create a ScriptableObject that implements the [`IObjectInitializationDataProvider`](xref:UnityEngine.ResourceManagement.Util.IObjectInitializationDataProvider) interface. Use this object to create the [`ObjectInitializationData`](xref:UnityEngine.ResourceManagement.Util.ObjectInitializationData) asset that Addressables includes with your the runtime data. + +### Cache initialization objects + +Use a [`CacheInitializationSettings`](xref:UnityEditor.AddressableAssets.Settings.CacheInitializationSettings) object to initialize Unity's [`Cache`](xref:UnityEngine.Cache) settings at runtime. + +To specify the cache initialization settings that the Addressables system uses: + +1. Create a CacheInitializationSettings asset (menu: __Assets > Addressables > Initialization > Cache Initialization Settings__). +2. Select the new asset file in the Project panel to view the settings in the Inspector + ![](images/cache-initialization-settings.png) + +3. Adjust the settings as desired. +4. Open the Addressables Settings Inspector (menu: __Window > Asset Management > Addressables > Settings__). +5. In the __Initialization Objects__ section of the Inspector, click the __+__ button to add a new object to the list. +6. Select the CacheInitializationSettings asset in the File dialog and click __Open__. +7. The cache settings object is added to the list. + +When Addressables initializes at runtime, it applies these settings to the default Unity `Cache`. The settings apply to all AssetBundles in the default cache, not just those downloaded by the Addressables system. Refer to [Caching](xref:UnityEngine.Caching) for more information about the Unity cache system. + +> [!TIP] +> Android applications built with Unity 2020.1 or earlier, or running on Android 9 or earlier can only play videos from uncompressed AssetBundles. To disable recompression of the cache, use a `CacheInitializationSettings` object by disabling the __Compress Bundles__ option. diff --git a/Documentation~/Labels.md b/Documentation~/Labels.md index 52fafca8..92622bd9 100644 --- a/Documentation~/Labels.md +++ b/Documentation~/Labels.md @@ -1,30 +1,30 @@ ---- -uid: addressables-labels ---- - -# Labels overview - -You can tag your Addressable assets with one or more labels in the [Addressables Groups](xref:addressables-groups) window. Labels have a few uses in the Addressables system, including: - -* You can use one or more labels as keys to identify which assets to load at runtime. -* You can pack assets in a group into AssetBundles based on their assigned labels. -* You can use labels in the filter box of the Groups window to help find labeled assets - -When you load assets using a list of labels, you can specify whether you want to load all assets that have any label in the list or only assets that have every label in the list. - -For example, if you used the labels, `characters` and `animals` to load assets, you could choose to load the union of those two sets of assets, which includes all characters and all animals, or the intersection of those two sets, which includes only characters that are animals. Refer to [Loading multiple assets](load-assets.md#load-multiple-assets) for more information. - -When you choose to pack assets in a group based on their assigned labels using the group [Bundle Mode](xref:addressables-content-packing-and-loading-schema) setting, the Addressables build script creates a bundle for each unique combination of labels in the group. For example, if you have assets in a group that you have labeled as either `cat` or `dog` and either `small` or `large`, the build produces four bundles: one for small cats, one for small dogs, one for large cats, and another for large dogs. - -## Managing labels - -To create and delete labels, use the Labels window, which is accessible from the [Addressables Groups window](GroupsWindow.md) (**Window > Asset Management > Addressables > Groups > Tools > Windows > Labels**). - -![](images/addressables-labels-window.png)
*The Labels window* - -To create a new label, select the __+__ button at the bottom of the list. Enter the new name and click __Save__. - -To delete a label, select it in the list and then select the __-__ button. Deleting a label also removes it from all assets. - -> [!TIP] -> Until you run an Addressables build, you can undo the deletion of a label by adding it back to the Labels dialog (using the exact same string). This also adds the label back to its original assets. After you run an Addressables build, however, re-adding a deleted label no longer reapplies it to any assets. +--- +uid: addressables-labels +--- + +# Labels overview + +You can tag your Addressable assets with one or more labels in the [Addressables Groups](xref:addressables-groups) window. Labels have a few uses in the Addressables system, including: + +* You can use one or more labels as keys to identify which assets to load at runtime. +* You can pack assets in a group into AssetBundles based on their assigned labels. +* You can use labels in the filter box of the Groups window to help find labeled assets + +When you load assets using a list of labels, you can specify whether you want to load all assets that have any label in the list or only assets that have every label in the list. + +For example, if you used the labels, `characters` and `animals` to load assets, you could choose to load the union of those two sets of assets, which includes all characters and all animals, or the intersection of those two sets, which includes only characters that are animals. Refer to [Loading multiple assets](load-assets.md#load-multiple-assets) for more information. + +When you choose to pack assets in a group based on their assigned labels using the group [Bundle Mode](xref:addressables-content-packing-and-loading-schema) setting, the Addressables build script creates a bundle for each unique combination of labels in the group. For example, if you have assets in a group that you have labeled as either `cat` or `dog` and either `small` or `large`, the build produces four bundles: one for small cats, one for small dogs, one for large cats, and another for large dogs. + +## Managing labels + +To create and delete labels, use the Labels window, which is accessible from the [Addressables Groups window](GroupsWindow.md) (**Window > Asset Management > Addressables > Groups > Tools > Windows > Labels**). + +![](images/addressables-labels-window.png)
*The Labels window* + +To create a new label, select the __+__ button at the bottom of the list. Enter the new name and click __Save__. + +To delete a label, select it in the list and then select the __-__ button. Deleting a label also removes it from all assets. + +> [!TIP] +> Until you run an Addressables build, you can undo the deletion of a label by adding it back to the Labels dialog (using the exact same string). This also adds the label back to its original assets. After you run an Addressables build, however, re-adding a deleted label no longer reapplies it to any assets. diff --git a/Documentation~/LoadContentCatalogAsync.md b/Documentation~/LoadContentCatalogAsync.md index 56f0933b..c4b6720d 100644 --- a/Documentation~/LoadContentCatalogAsync.md +++ b/Documentation~/LoadContentCatalogAsync.md @@ -1,47 +1,47 @@ ---- -uid: addressables-api-load-content-catalog-async ---- - -# Manage catalogs at runtime - -By default, the Addressables system manages the [catalog](build-content-catalogs.md) automatically at runtime. If you built your application with a remote catalog, the Addressables system automatically checks for a new catalog, and downloads the new version and loads it into memory. - -You can load additional catalogs at runtime. For example, you can load a catalog produced by a separate, compatible project to load Addressable assets built by that project. Refer to [Loading content from multiple projects](xref:addressables-multiple-projects) for more information. - -If you want to change the default catalog update behavior of the Addressables system, you can disable the automatic check and check for updates manually. Refer to [Updating catalogs](#update-catalogs) for more information. - -## Load additional catalogs - -Use [`Addressables.LoadContentCatalogAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadContentCatalogAsync*) to load additional content catalogs, either from a hosting service or from the local file system. You need to supply the location of the catalog you want to load. After the operation to load the catalog is complete, you can call any Addressables loading functions using the keys in the new catalog. - -If you supply the catalog hash file at the same URL as the catalog, Addressables caches the secondary catalog. When the client application loads the catalog, it only downloads a new version of the catalog if the hash changes. - -The hash file needs to be in the same location and have the same name as the catalog file. The only difference between the file path for the catalog and the hash file is the file extension. - -`LoadContentCatalogAsync` comes with a parameter `autoReleaseHandle`. In order for the system to download a new remote catalog, any prior calls to `LoadContentCatalogAsync` that point to the catalog you want to load need to be released. Otherwise, the system picks up the content catalog load operation from the operation cache. If the cached operation is picked up, the new remote catalog isn't downloaded. If set to true, the parameter `autoReleaseHandle` makes sure that the operation doesn't stay in the operation cache after completing. - -Once you load a catalog, you can't unload it. However, you can update a loaded catalog. You must release the operation handle for the operation that loaded the catalog before updating a catalog. Refer to [Updating catalogs](#update-catalogs) for more information. - -In general, there is no reason to hold on to the operation handle after loading a catalog. You can release it automatically by setting the `autoReleaseHandle` parameter to true when loading a catalog, as shown in the following example: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/MiscellaneousTopics.cs#doc_LoadAdditionalCatalog)] - -> [!TIP] -> Use the [Catalog Download Timeout](xref:addressables-asset-settings) property in Addressables settings to specify a timeout for downloading catalogs. - -## Update catalogs - -If the catalog hash file is available, Addressables checks the hash when loading a catalog to check if the version at the provided URL is more recent than the cached version of the catalog. You can disable the default catalog check, and call the [`Addressables.UpdateCatalogs`](xref:UnityEngine.AddressableAssets.Addressables.UpdateCatalogs*) method when you want to update the catalog. If you loaded a catalog manually with [`LoadContentCatalogAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadContentCatalogAsync*), you must release the operation handle before you can update the catalog. - -When you call the `UpdateCatalog` method, Unity blocks all other Addressable requests until the operation is complete. You can release the operation handle that `UpdateCatalog` returns immediately after the operation finishes, or set the `autoRelease` parameter to `true`. - -If you call `UpdateCatalog` without providing a list of catalogs, Addressables checks all the loaded catalogs for updates. - -[!code-cs[sample](../Tests/Editor/DocExampleCode/MiscellaneousTopics.cs#doc_UpdateCatalog)] - -You can also call [`Addressables.CheckForCatalogUpdates`](xref:UnityEngine.AddressableAssets.Addressables.CheckForCatalogUpdates*) directly to get the list of catalogs that have updates and then perform the update: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/MiscellaneousTopics.cs#doc_CheckCatalog)] - -> [!IMPORTANT] -> If you update a catalog when you have already loaded content from the related AssetBundles, there might be conflicts between the loaded AssetBundles and the updated versions. Enable the [Unique Bundle Ids](xref:addressables-content-update-builds) option in Addressable settings to stop the possibility of bundle ID collisions at runtime. Enabling this option also means that more AssetBundles must typically be rebuilt when you perform a content update. Refer to [Content update builds](content-update-builds-overview.md) for more information. You can also unload any content and AssetBundles that must be updated, which can be a slow operation. +--- +uid: addressables-api-load-content-catalog-async +--- + +# Manage catalogs at runtime + +By default, the Addressables system manages the [catalog](build-content-catalogs.md) automatically at runtime. If you built your application with a remote catalog, the Addressables system automatically checks for a new catalog, and downloads the new version and loads it into memory. + +You can load additional catalogs at runtime. For example, you can load a catalog produced by a separate, compatible project to load Addressable assets built by that project. Refer to [Loading content from multiple projects](xref:addressables-multiple-projects) for more information. + +If you want to change the default catalog update behavior of the Addressables system, you can disable the automatic check and check for updates manually. Refer to [Updating catalogs](#update-catalogs) for more information. + +## Load additional catalogs + +Use [`Addressables.LoadContentCatalogAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadContentCatalogAsync*) to load additional content catalogs, either from a hosting service or from the local file system. You need to supply the location of the catalog you want to load. After the operation to load the catalog is complete, you can call any Addressables loading functions using the keys in the new catalog. + +If you supply the catalog hash file at the same URL as the catalog, Addressables caches the secondary catalog. When the client application loads the catalog, it only downloads a new version of the catalog if the hash changes. + +The hash file needs to be in the same location and have the same name as the catalog file. The only difference between the file path for the catalog and the hash file is the file extension. + +`LoadContentCatalogAsync` comes with a parameter `autoReleaseHandle`. In order for the system to download a new remote catalog, any prior calls to `LoadContentCatalogAsync` that point to the catalog you want to load need to be released. Otherwise, the system picks up the content catalog load operation from the operation cache. If the cached operation is picked up, the new remote catalog isn't downloaded. If set to true, the parameter `autoReleaseHandle` makes sure that the operation doesn't stay in the operation cache after completing. + +Once you load a catalog, you can't unload it. However, you can update a loaded catalog. You must release the operation handle for the operation that loaded the catalog before updating a catalog. Refer to [Updating catalogs](#update-catalogs) for more information. + +In general, there is no reason to hold on to the operation handle after loading a catalog. You can release it automatically by setting the `autoReleaseHandle` parameter to true when loading a catalog, as shown in the following example: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/MiscellaneousTopics.cs#doc_LoadAdditionalCatalog)] + +> [!TIP] +> Use the [Catalog Download Timeout](xref:addressables-asset-settings) property in Addressables settings to specify a timeout for downloading catalogs. + +## Update catalogs + +If the catalog hash file is available, Addressables checks the hash when loading a catalog to check if the version at the provided URL is more recent than the cached version of the catalog. You can disable the default catalog check, and call the [`Addressables.UpdateCatalogs`](xref:UnityEngine.AddressableAssets.Addressables.UpdateCatalogs*) method when you want to update the catalog. If you loaded a catalog manually with [`LoadContentCatalogAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadContentCatalogAsync*), you must release the operation handle before you can update the catalog. + +When you call the `UpdateCatalog` method, Unity blocks all other Addressable requests until the operation is complete. You can release the operation handle that `UpdateCatalog` returns immediately after the operation finishes, or set the `autoRelease` parameter to `true`. + +If you call `UpdateCatalog` without providing a list of catalogs, Addressables checks all the loaded catalogs for updates. + +[!code-cs[sample](../Tests/Editor/DocExampleCode/MiscellaneousTopics.cs#doc_UpdateCatalog)] + +You can also call [`Addressables.CheckForCatalogUpdates`](xref:UnityEngine.AddressableAssets.Addressables.CheckForCatalogUpdates*) directly to get the list of catalogs that have updates and then perform the update: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/MiscellaneousTopics.cs#doc_CheckCatalog)] + +> [!IMPORTANT] +> If you update a catalog when you have already loaded content from the related AssetBundles, there might be conflicts between the loaded AssetBundles and the updated versions. Enable the [Unique Bundle Ids](xref:addressables-content-update-builds) option in Addressable settings to stop the possibility of bundle ID collisions at runtime. Enabling this option also means that more AssetBundles must typically be rebuilt when you perform a content update. Refer to [Content update builds](content-update-builds-overview.md) for more information. You can also unload any content and AssetBundles that must be updated, which can be a slow operation. diff --git a/Documentation~/LoadingAddressableAssets.md b/Documentation~/LoadingAddressableAssets.md index 58288f75..43a27691 100644 --- a/Documentation~/LoadingAddressableAssets.md +++ b/Documentation~/LoadingAddressableAssets.md @@ -1,21 +1,21 @@ ---- -uid: addressables-api-load-asset-async ---- - -# Loading Addressable assets - -The [`Addressables`](xref:UnityEngine.AddressableAssets.Addressables) class provides methods to load Addressable assets. You can load assets one at a time or in batches. - -|**Topic**|**Description**| -|---|---| -|[Load Addressable assets introduction](load-addressable-assets.md)| Understand how Addressables loads content.| -|[Asynchronous loading](load-assets-asynchronous.md)| Understand asynchronous loading, including operation handles, and how to enable synchronous loading.| -|[Load assets](load-assets.md)|Load a single or multiple assets.| -|[Load assets by location](load-assets-location.md)| Load assets by address, label, or AssetReference.| -|[Load a scene](LoadingScenes.md)|Load and make a scene Addressable.| -|[Load AssetBundles](LoadingAssetBundles.md)| Control how AssetBundles load.| -|[Safely edit loaded assets](safely-edit-loaded-asset.md)| Learn how to edit an asset safely while it's loaded. | -|[Unload Addressable assets](UnloadingAddressableAssets.md)|How to unload Addressable assets.| -|[Change resource URLs](TransformInternalId.md)|How to change the URLs that assets are loaded from.| -|[Preload dependencies](DownloadDependenciesAsync.md)|Understand how to set loading dependencies.| +--- +uid: addressables-api-load-asset-async +--- + +# Loading Addressable assets + +The [`Addressables`](xref:UnityEngine.AddressableAssets.Addressables) class provides methods to load Addressable assets. You can load assets one at a time or in batches. + +|**Topic**|**Description**| +|---|---| +|[Load Addressable assets introduction](load-addressable-assets.md)| Understand how Addressables loads content.| +|[Asynchronous loading](load-assets-asynchronous.md)| Understand asynchronous loading, including operation handles, and how to enable synchronous loading.| +|[Load assets](load-assets.md)|Load a single or multiple assets.| +|[Load assets by location](load-assets-location.md)| Load assets by address, label, or AssetReference.| +|[Load a scene](LoadingScenes.md)|Load and make a scene Addressable.| +|[Load AssetBundles](LoadingAssetBundles.md)| Control how AssetBundles load.| +|[Safely edit loaded assets](safely-edit-loaded-asset.md)| Learn how to edit an asset safely while it's loaded. | +|[Unload Addressable assets](UnloadingAddressableAssets.md)|How to unload Addressable assets.| +|[Change resource URLs](TransformInternalId.md)|How to change the URLs that assets are loaded from.| +|[Preload dependencies](DownloadDependenciesAsync.md)|Understand how to set loading dependencies.| |[Load content from multiple projects](MultiProject.md)|Load content from and work with multiple projects.| \ No newline at end of file diff --git a/Documentation~/LoadingAssetBundles.md b/Documentation~/LoadingAssetBundles.md index 0f6b88ef..f7f30a74 100644 --- a/Documentation~/LoadingAssetBundles.md +++ b/Documentation~/LoadingAssetBundles.md @@ -1,68 +1,68 @@ ---- -uid: addressables-loading-bundles ---- - -# Load AssetBundles - -The Addressables system packs assets into AssetBundles and loads these bundles as you load individual assets. You can control how AssetBundles load which are exposed on the `BundledAssetGroupSchema` class. You can set these options through the scripting API or under the Advanced options in the Inspector of the `AddressablesAssetGroup` Inspector. - -## UnityWebRequestForLocalBundles - -Addressables can load AssetBundles via two engine APIs: `UnityWebRequest.GetAssetBundle`, and `AssetBundle.LoadFromFileAsync`. The default behavior is to use `AssetBundle.LoadFromFileAsync` when the AssetBundle is in local storage and use `UnityWebRequest` when the AssetBundle path is a URL. - -You can override this behavior to use `UnityWebRequest` for local Asset Bundles by setting `BundledAssetGroupSchema.UseUnityWebRequestForLocalBundles` to true. It can also be set through the BundledAssetGroupSchema GUI. - -A few of these situations include: - -* You are shipping local AssetBundles that use LZMA compression because you want your shipped game package to be as small as possible. In this case, you would want to use UnityWebRequest to recompress those AssetBundles LZ4 into the local disk cache. -* You are shipping an Android game and your APK contains AssetBundles that are compressed with the default APK compression. -* You want the entire local AssetBundle to be loaded into memory to avoid disk seeks. If you use `UnityWebRequest` and have caching disabled, the entire AssetBundle file will be loaded into the memory cache. This increases your runtime memory usage, but may improve loading performance as it eliminates disk seeking after the initial AssetBundle load. - -The first two situations above result in the AssetBundle existing on the player device twice (original and cached representations). This means the initial loads (decompressing and copying to cache) are slower than subsequent loads (loading from cache) - -## Handle download errors - -When a download fails, the RemoteProviderException contains errors that can be used to determine how to handle the failure. -The RemoteProviderException is either the `AsyncOperationHandle.OperationException` or an inner exception. As shown below: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/DownloadError.cs#doc_DownloadError)] - -Possible error strings: -* "Request aborted" -* "Unable to write data" -* "Malformed URL" -* "Out of memory" -* "No Internet Connection" -* "Encountered invalid redirect (missing Location header?)" -* "Cannot modify request at this time" -* "Unsupported Protocol" -* "Destination host has an erroneous SSL certificate" -* "Unable to load SSL Cipher for verification" -* "SSL CA certificate error" -* "Unrecognized content-encoding" -* "Request already transmitted" -* "Invalid HTTP Method" -* "Header name contains invalid characters" -* "Header value contains invalid characters" -* "Cannot override system-specified headers" -* "Backend Initialization Error" -* "Cannot resolve proxy" -* "Cannot resolve destination host" -* "Cannot connect to destination host" -* "Access denied" -* "Generic/unknown HTTP error" -* "Unable to read data" -* "Request timeout" -* "Error during HTTP POST transmission" -* "Unable to complete SSL connection" -* "Redirect limit exceeded" -* "Received no data in response" -* "Destination host does not support SSL" -* "Failed to transmit data" -* "Failed to receive data" -* "Login failed" -* "SSL shutdown failed" -* "Redirect limit is invalid" -* "Not implemented" -* "Data Processing Error, see Download Handler error" +--- +uid: addressables-loading-bundles +--- + +# Load AssetBundles + +The Addressables system packs assets into AssetBundles and loads these bundles as you load individual assets. You can control how AssetBundles load which are exposed on the `BundledAssetGroupSchema` class. You can set these options through the scripting API or under the Advanced options in the Inspector of the `AddressablesAssetGroup` Inspector. + +## UnityWebRequestForLocalBundles + +Addressables can load AssetBundles via two engine APIs: `UnityWebRequest.GetAssetBundle`, and `AssetBundle.LoadFromFileAsync`. The default behavior is to use `AssetBundle.LoadFromFileAsync` when the AssetBundle is in local storage and use `UnityWebRequest` when the AssetBundle path is a URL. + +You can override this behavior to use `UnityWebRequest` for local Asset Bundles by setting `BundledAssetGroupSchema.UseUnityWebRequestForLocalBundles` to true. It can also be set through the BundledAssetGroupSchema GUI. + +A few of these situations include: + +* You are shipping local AssetBundles that use LZMA compression because you want your shipped game package to be as small as possible. In this case, you would want to use UnityWebRequest to recompress those AssetBundles LZ4 into the local disk cache. +* You are shipping an Android game and your APK contains AssetBundles that are compressed with the default APK compression. +* You want the entire local AssetBundle to be loaded into memory to avoid disk seeks. If you use `UnityWebRequest` and have caching disabled, the entire AssetBundle file will be loaded into the memory cache. This increases your runtime memory usage, but may improve loading performance as it eliminates disk seeking after the initial AssetBundle load. + +The first two situations above result in the AssetBundle existing on the player device twice (original and cached representations). This means the initial loads (decompressing and copying to cache) are slower than subsequent loads (loading from cache) + +## Handle download errors + +When a download fails, the RemoteProviderException contains errors that can be used to determine how to handle the failure. +The RemoteProviderException is either the `AsyncOperationHandle.OperationException` or an inner exception. As shown below: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/DownloadError.cs#doc_DownloadError)] + +Possible error strings: +* "Request aborted" +* "Unable to write data" +* "Malformed URL" +* "Out of memory" +* "No Internet Connection" +* "Encountered invalid redirect (missing Location header?)" +* "Cannot modify request at this time" +* "Unsupported Protocol" +* "Destination host has an erroneous SSL certificate" +* "Unable to load SSL Cipher for verification" +* "SSL CA certificate error" +* "Unrecognized content-encoding" +* "Request already transmitted" +* "Invalid HTTP Method" +* "Header name contains invalid characters" +* "Header value contains invalid characters" +* "Cannot override system-specified headers" +* "Backend Initialization Error" +* "Cannot resolve proxy" +* "Cannot resolve destination host" +* "Cannot connect to destination host" +* "Access denied" +* "Generic/unknown HTTP error" +* "Unable to read data" +* "Request timeout" +* "Error during HTTP POST transmission" +* "Unable to complete SSL connection" +* "Redirect limit exceeded" +* "Received no data in response" +* "Destination host does not support SSL" +* "Failed to transmit data" +* "Failed to receive data" +* "Login failed" +* "SSL shutdown failed" +* "Redirect limit is invalid" +* "Not implemented" +* "Data Processing Error, see Download Handler error" * "Unknown Error" \ No newline at end of file diff --git a/Documentation~/LoadingAssetReferences.md b/Documentation~/LoadingAssetReferences.md index 04671659..3fba3e8f 100644 --- a/Documentation~/LoadingAssetReferences.md +++ b/Documentation~/LoadingAssetReferences.md @@ -1,11 +1,11 @@ ---- -uid: addressables-loading-asset-reference ---- - -# Load an AssetReference - -The [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) class has its own load method, [`LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetAsync*): - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadReference.cs#doc_Load)] - -You can also use the `AssetReference` object as a key to the [`Addressables.LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetAsync*) methods. If you need to spawn multiple instances of the asset assigned to an AssetReference, use `Addressables.LoadAssetAsync`, which gives you an operation handle that you can use to release each instance. +--- +uid: addressables-loading-asset-reference +--- + +# Load an AssetReference + +The [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) class has its own load method, [`LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetAsync*): + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadReference.cs#doc_Load)] + +You can also use the `AssetReference` object as a key to the [`Addressables.LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetAsync*) methods. If you need to spawn multiple instances of the asset assigned to an AssetReference, use `Addressables.LoadAssetAsync`, which gives you an operation handle that you can use to release each instance. diff --git a/Documentation~/LoadingScenes.md b/Documentation~/LoadingScenes.md index 37b24750..0dc2d8b3 100644 --- a/Documentation~/LoadingScenes.md +++ b/Documentation~/LoadingScenes.md @@ -1,41 +1,41 @@ ---- -uid: addressables-loading-scenes ---- - -# Load a scene - -Use the [`Addressables.LoadSceneAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadSceneAsync*) method to load an Addressable scene asset by address or other Addressable key object. - -`Addressables.LoadSceneAsync` uses the Unity Engine [`SceneManager.LoadSceneAsync`](xref:UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(System.String,UnityEngine.SceneManagement.LoadSceneMode)) method internally. APIs that affect the behavior of `SceneManager.LoadSceneAsync` also affect `Addressables.LoadSceneAsync` in the same way, such as [`Application.backgroundLoadingPriority`](xref:UnityEngine.Application.backgroundLoadingPriority). - -The remaining parameters of the `Addressables.LoadSceneAsync` method correspond to those used with the `SceneManager.LoadSceneAsync` method: - -* `loadMode`: Whether to add the loaded scene into the current scene, or to unload and replace the current scene. -* `loadSceneParameters`: Includes `loadMode` and `localPhysicsMode`. This is used when loading the scene to specify whether to create a 2D or 3D physics scene. -* `activateOnLoad`: Whether to activate the scene as soon as it finishes loading or to wait until you call the `SceneInstance` object's [`ActivateAsync`](xref:UnityEngine.ResourceManagement.ResourceProviders.SceneInstance.ActivateAsync*) method. Corresponds to the [`AsyncOperation.allowSceneActivation`](xref:UnityEngine.AsyncOperation.allowSceneActivation) option. Defaults to true. -* `priority`: The priority of the `AsyncOperation` used to load the Scene. Corresponds to the [`AsyncOperation.priority`](xref:UnityEngine.AsyncOperation.priority) option. Defaults to 100. - -> [!WARNING] -> Setting the `activateOnLoad` parameter to false blocks the `AsyncOperation` queue, including the loading of any other Addressable assets, until you activate the scene. To activate the scene, call the [`ActivateAsync`](xref:UnityEngine.ResourceManagement.ResourceProviders.SceneInstance.ActivateAsync*) method of the [`SceneInstance`](xref:UnityEngine.ResourceManagement.ResourceProviders.SceneInstance) returned by [`LoadSceneAsync`](xref:UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(System.String,UnityEngine.SceneManagement.LoadSceneMode)). Refer to [AsyncOperation.allowSceneActivation](xref:UnityEngine.AsyncOperation.allowSceneActivation) for additional information. - -The following example loads a scene additively. The component that loads the scene stores the operation handle and uses it to unload and release the scene when the parent GameObject is destroyed. - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadScene.cs#doc_Load)] - -Refer to the [Scene loading project](https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Basic/Scene%20Loading) in the Addressables samples repository for additional examples. - -If you load a Scene with [`LoadSceneMode.Single`](xref:UnityEngine.SceneManagement.LoadSceneMode.Single), the Unity runtime unloads the current Scene and calls [`Resources.UnloadUnusedAssets`](xref:UnityEngine.Resources.UnloadUnusedAssets). Refer to [Releasing Addressable assets](xref:addressables-unloading) for more information. - -> [!NOTE] -> In the Editor, you can always load scenes in the current project, even when they're packaged in a remote bundle that's not available and you set the Play Mode Script to __Use Existing Build__. The Editor loads the scene using the Asset Database. - -## Use Addressables in a scene - -If a scene is Addressable, you can use Addressable assets in the scene just like any other assets. You can place prefabs and other assets in the scene, and assign assets to component properties. If you use an asset that isn't Addressable, that asset becomes an implicit dependency of the scene and the build system packs it in the same AssetBundle as the scene when you make a content build. Addressable assets are packed into their own AssetBundles according to the group they're in. - -> [!NOTE] -> Implicit dependencies used in more than one place can be duplicated in multiple AssetBundles and in the built-in scene data. Use the [Build Layout Report](xref:addressables-build-layout-report) to identify and resolve unwanted asset duplication resulting from your project content organization. - -If a scene isn't Addressable, then any Addressable assets you add directly to the scene hierarchy become implicit dependencies and Unity includes copies of those assets in the built-in scene data even if they also exist in an Addressable group. The same is true for any assets, such as materials assigned to a component on a GameObject in the scene. - -In custom component classes, you can use [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) fields to allow the assignment of Addressable assets in non-Addressable scenes. Otherwise, you can use [addresses](xref:addressables-overview) and [labels](Labels.md) to load assets at runtime from a script. You must load an `AssetReference` in code regardless of if the scene is Addressable. +--- +uid: addressables-loading-scenes +--- + +# Load a scene + +Use the [`Addressables.LoadSceneAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadSceneAsync*) method to load an Addressable scene asset by address or other Addressable key object. + +`Addressables.LoadSceneAsync` uses the Unity Engine [`SceneManager.LoadSceneAsync`](xref:UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(System.String,UnityEngine.SceneManagement.LoadSceneMode)) method internally. APIs that affect the behavior of `SceneManager.LoadSceneAsync` also affect `Addressables.LoadSceneAsync` in the same way, such as [`Application.backgroundLoadingPriority`](xref:UnityEngine.Application.backgroundLoadingPriority). + +The remaining parameters of the `Addressables.LoadSceneAsync` method correspond to those used with the `SceneManager.LoadSceneAsync` method: + +* `loadMode`: Whether to add the loaded scene into the current scene, or to unload and replace the current scene. +* `loadSceneParameters`: Includes `loadMode` and `localPhysicsMode`. This is used when loading the scene to specify whether to create a 2D or 3D physics scene. +* `activateOnLoad`: Whether to activate the scene as soon as it finishes loading or to wait until you call the `SceneInstance` object's [`ActivateAsync`](xref:UnityEngine.ResourceManagement.ResourceProviders.SceneInstance.ActivateAsync*) method. Corresponds to the [`AsyncOperation.allowSceneActivation`](xref:UnityEngine.AsyncOperation.allowSceneActivation) option. Defaults to true. +* `priority`: The priority of the `AsyncOperation` used to load the Scene. Corresponds to the [`AsyncOperation.priority`](xref:UnityEngine.AsyncOperation.priority) option. Defaults to 100. + +> [!WARNING] +> Setting the `activateOnLoad` parameter to false blocks the `AsyncOperation` queue, including the loading of any other Addressable assets, until you activate the scene. To activate the scene, call the [`ActivateAsync`](xref:UnityEngine.ResourceManagement.ResourceProviders.SceneInstance.ActivateAsync*) method of the [`SceneInstance`](xref:UnityEngine.ResourceManagement.ResourceProviders.SceneInstance) returned by [`LoadSceneAsync`](xref:UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(System.String,UnityEngine.SceneManagement.LoadSceneMode)). Refer to [AsyncOperation.allowSceneActivation](xref:UnityEngine.AsyncOperation.allowSceneActivation) for additional information. + +The following example loads a scene additively. The component that loads the scene stores the operation handle and uses it to unload and release the scene when the parent GameObject is destroyed. + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadScene.cs#doc_Load)] + +Refer to the [Scene loading project](https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Basic/Scene%20Loading) in the Addressables samples repository for additional examples. + +If you load a Scene with [`LoadSceneMode.Single`](xref:UnityEngine.SceneManagement.LoadSceneMode.Single), the Unity runtime unloads the current Scene and calls [`Resources.UnloadUnusedAssets`](xref:UnityEngine.Resources.UnloadUnusedAssets). Refer to [Releasing Addressable assets](xref:addressables-unloading) for more information. + +> [!NOTE] +> In the Editor, you can always load scenes in the current project, even when they're packaged in a remote bundle that's not available and you set the Play Mode Script to __Use Existing Build__. The Editor loads the scene using the Asset Database. + +## Use Addressables in a scene + +If a scene is Addressable, you can use Addressable assets in the scene just like any other assets. You can place prefabs and other assets in the scene, and assign assets to component properties. If you use an asset that isn't Addressable, that asset becomes an implicit dependency of the scene and the build system packs it in the same AssetBundle as the scene when you make a content build. Addressable assets are packed into their own AssetBundles according to the group they're in. + +> [!NOTE] +> Implicit dependencies used in more than one place can be duplicated in multiple AssetBundles and in the built-in scene data. Use the [Build Layout Report](xref:addressables-build-layout-report) to identify and resolve unwanted asset duplication resulting from your project content organization. + +If a scene isn't Addressable, then any Addressable assets you add directly to the scene hierarchy become implicit dependencies and Unity includes copies of those assets in the built-in scene data even if they also exist in an Addressable group. The same is true for any assets, such as materials assigned to a component on a GameObject in the scene. + +In custom component classes, you can use [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) fields to allow the assignment of Addressable assets in non-Addressable scenes. Otherwise, you can use [addresses](xref:addressables-overview) and [labels](Labels.md) to load assets at runtime from a script. You must load an `AssetReference` in code regardless of if the scene is Addressable. diff --git a/Documentation~/MemoryManagement.md b/Documentation~/MemoryManagement.md index 77de127a..37fd0a36 100644 --- a/Documentation~/MemoryManagement.md +++ b/Documentation~/MemoryManagement.md @@ -1,41 +1,41 @@ ---- -uid: addressables-memory-management ---- - -# Memory management overview - -The Addressables system keeps a reference count of every item it loads to manage the memory it uses to load assets and bundles. - -When Unity loads an Addressable, the system increments the reference count. When Unity releases the asset, the system decrements the reference count. When the reference count of an Addressable returns to zero, it can be unloaded. When you explicitly load an Addressable asset, you must also release the asset when you're finished using it. - -## Memory leaks - -To avoid memory leaks, where assets remain in memory after they're no longer needed, mirror every call to a load method with a call to a release method. You can release an asset with a reference to the asset instance itself or with the result handle that the original load operation returns. - -However, Unity doesn't unload released assets from memory immediately. The memory that an asset uses isn't freed until the AssetBundle it belongs to is also unloaded. You can call [`Resources.UnloadUnusedAssets`](xref:UnityEngine.Resources.UnloadUnusedAssets) to unload released assets, but it's a slow operation which can cause frame rate hitches. - -AssetBundles have their own reference count, and the system treats them like Addressables with the assets they contain as dependencies. When you load an asset from a bundle, the bundle's reference count increases and when you release the asset, the bundle reference count decreases. When a bundle's reference count returns to zero, that means none of the assets contained in the bundle are still in use. Unity then unloads the bundle and all the assets contained in it from memory. - -Use the [Profiler module](ProfilerModule.md) to monitor your loaded content. The module displays when assets and their dependencies are loaded and unloaded. - -## Memory clearance - -If an asset is no longer referenced, indicated by the released status and disabled text in the [Profiler module](ProfilerModule.md), this doesn't mean that Unity unloaded that asset. A common applicable scenario involves multiple assets in an AssetBundle. For example: - -* You have three assets (`tree`, `tank`, and `cow`) in an AssetBundle (`stuff`). -* When `tree` loads, the Profiler displays a single ref-count for `tree`, and one for `stuff`. -* Later, when `tank` loads, the Profiler displays a single ref-count for both `tree` and `tank`, and two ref-counts for the `stuff` AssetBundle. -* If you release `tree`, its ref-count becomes zero, and the blue bar goes away. - -In this example, the `tree` asset isn't unloaded at this point. You can load an AssetBundle, or its partial contents, but you can't unload part of an AssetBundle. No asset in `stuff` unloads until the AssetBundle is unloaded. - -The exception to this rule is the engine interface [`Resources.UnloadUnusedAssets`](xref:UnityEngine.Resources.UnloadUnusedAssets). Executing this method in the earlier example causes `tree` to unload. Because the Addressables system isn't aware of these events, the Profiler graph only reflects the Addressables ref-counts (not exactly what memory holds). If you use [`Resources.UnloadUnusedAssets`](xref:UnityEngine.Resources.UnloadUnusedAssets), it's a slow operation, and should only be called on a screen that won't display any hitches, such as a loading screen. - - -## Avoid asset churn - -Asset churn happens if you release an object that's the last item in an AssetBundle, and then immediately reload either that asset or another asset in the bundle. - -For example, if you have two materials, `boat` and `plane` that share a texture, `cammo`, which is in its own AssetBundle. Level 1 uses `boat` and level 2 uses `plane`. As you exit level 1 Unity releases `boat`, and immediately loads `plane`. When Unity releases `boat`, Addressables unloads texture `cammo`. Then, when Unity load `plane`, Addressables immediately reloads `cammo`. - +--- +uid: addressables-memory-management +--- + +# Memory management overview + +The Addressables system keeps a reference count of every item it loads to manage the memory it uses to load assets and bundles. + +When Unity loads an Addressable, the system increments the reference count. When Unity releases the asset, the system decrements the reference count. When the reference count of an Addressable returns to zero, it can be unloaded. When you explicitly load an Addressable asset, you must also release the asset when you're finished using it. + +## Memory leaks + +To avoid memory leaks, where assets remain in memory after they're no longer needed, mirror every call to a load method with a call to a release method. You can release an asset with a reference to the asset instance itself or with the result handle that the original load operation returns. + +However, Unity doesn't unload released assets from memory immediately. The memory that an asset uses isn't freed until the AssetBundle it belongs to is also unloaded. You can call [`Resources.UnloadUnusedAssets`](xref:UnityEngine.Resources.UnloadUnusedAssets) to unload released assets, but it's a slow operation which can cause frame rate hitches. + +AssetBundles have their own reference count, and the system treats them like Addressables with the assets they contain as dependencies. When you load an asset from a bundle, the bundle's reference count increases and when you release the asset, the bundle reference count decreases. When a bundle's reference count returns to zero, that means none of the assets contained in the bundle are still in use. Unity then unloads the bundle and all the assets contained in it from memory. + +Use the [Profiler module](ProfilerModule.md) to monitor your loaded content. The module displays when assets and their dependencies are loaded and unloaded. + +## Memory clearance + +If an asset is no longer referenced, indicated by the released status and disabled text in the [Profiler module](ProfilerModule.md), this doesn't mean that Unity unloaded that asset. A common applicable scenario involves multiple assets in an AssetBundle. For example: + +* You have three assets (`tree`, `tank`, and `cow`) in an AssetBundle (`stuff`). +* When `tree` loads, the Profiler displays a single ref-count for `tree`, and one for `stuff`. +* Later, when `tank` loads, the Profiler displays a single ref-count for both `tree` and `tank`, and two ref-counts for the `stuff` AssetBundle. +* If you release `tree`, its ref-count becomes zero, and the blue bar goes away. + +In this example, the `tree` asset isn't unloaded at this point. You can load an AssetBundle, or its partial contents, but you can't unload part of an AssetBundle. No asset in `stuff` unloads until the AssetBundle is unloaded. + +The exception to this rule is the engine interface [`Resources.UnloadUnusedAssets`](xref:UnityEngine.Resources.UnloadUnusedAssets). Executing this method in the earlier example causes `tree` to unload. Because the Addressables system isn't aware of these events, the Profiler graph only reflects the Addressables ref-counts (not exactly what memory holds). If you use [`Resources.UnloadUnusedAssets`](xref:UnityEngine.Resources.UnloadUnusedAssets), it's a slow operation, and should only be called on a screen that won't display any hitches, such as a loading screen. + + +## Avoid asset churn + +Asset churn happens if you release an object that's the last item in an AssetBundle, and then immediately reload either that asset or another asset in the bundle. + +For example, if you have two materials, `boat` and `plane` that share a texture, `cammo`, which is in its own AssetBundle. Level 1 uses `boat` and level 2 uses `plane`. As you exit level 1 Unity releases `boat`, and immediately loads `plane`. When Unity releases `boat`, Addressables unloads texture `cammo`. Then, when Unity load `plane`, Addressables immediately reloads `cammo`. + You can use the [Profiler module](ProfilerModule.md) to help detect asset churn by monitoring asset loading and unloading. \ No newline at end of file diff --git a/Documentation~/ModificationEvents.md b/Documentation~/ModificationEvents.md index ce0545e7..2755ad0a 100644 --- a/Documentation~/ModificationEvents.md +++ b/Documentation~/ModificationEvents.md @@ -1,70 +1,70 @@ ---- -uid: addressables-modification-events ---- - -# Modification events - -You can use modification events to signal to parts of the Addressables system when certain data is manipulated, such as when an `AddressableAssetGroup` or an `AddressableAssetEntry` is added or removed. - -Modification events are triggered as part of `SetDirty` calls inside of Addressables. `SetDirty` is used to indicate when an asset needs to be re-serialized by the `AssetDatabase`. As part of `SetDirty`, two modification event callbacks can trigger: - -* `public static event Action OnModificationGlobal` -* `public Action OnModification { get; set; }` - -These callbacks are found on [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings) through a static, or instance, accessors respectively. - -## Modification event example - -```c# -AddressableAssetSettings.OnModificationGlobal += (settings, modificationEvent, data) => - { - if(modificationEvent == AddressableAssetSettings.ModificationEvent.EntryAdded) - { - //Do work - } - }; - - AddressableAssetSettingsDefaultObject.Settings.OnModification += (settings, modificationEvent, data) => - { - if (modificationEvent == AddressableAssetSettings.ModificationEvent.EntryAdded) - { - //Do work - } - }; -``` -Modification events pass in a generic `object` for the data associated with the event. The following table outlines a list of the modification events and the data types that are passed with them. - -|**Modification event**|**Data passed**| -|---|---| -|GroupAdded|[`AddressableAssetGroup`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup), or list of groups that were added.| -|GroupRemoved| [`AddressableAssetGroup`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup), or list of groups that were removed.| -|GroupRenamed| [`AddressableAssetGroup`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup), or list of groups that were renamed.| -|GroupSchemaAdded| [`AddressableAssetGroup`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup), or list of groups that had schemas added to them.| -|GroupSchemaRemoved|[`AddressableAssetGroup`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup), or list of groups that had schemas removed from them.| -|GroupSchemaModified| [`AddressableAssetGroupSchema`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroupSchema) that was modified.| -|GroupTemplateAdded| `ScriptableObject`, typically one that implements [`IGroupTemplate`](xref:UnityEditor.AddressableAssets.Settings.IGroupTemplate), that was the added Group Template object.| -|GroupTemplateRemoved|`ScriptableObject`, typically one that implements [`IGroupTemplate`](xref:UnityEditor.AddressableAssets.Settings.IGroupTemplate), that was the removed Group Template object.| -|GroupTemplateSchemaAdded| [`AddressableAssetGroupTemplate`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroupTemplate) that had a schema added.| -|GroupTemplateSchemaRemoved|[`AddressableAssetGroupTemplate`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroupTemplate) that had a schema removed.| -|EntryCreated|[`AddressableAssetEntry`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetEntry) that was created.| -|EntryAdded|[`AddressableAssetEntry`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetEntry), or list of entries that were added.| -|EntryMoved|[`AddressableAssetEntry`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetEntry), or list of entries that were moved from one group to another.| -|EntryRemoved|[`AddressableAssetEntry`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetEntry), or list of entries that were removed.| -|LabelAdded|`string` label that was added.| -|LabelRemoved|`string` label that was removed.| -|ProfileAdded|`BuildProfile` that was added.| -|ProfileRemoved|`string` of the profile ID that was removed.| -|ProfileModified|`BuildProfile` that was modified, or `null` if a batch of `BuildProfile` objects were modified.| -|ActiveProfileSet|The data passed with this event if the `string` of the profile ID that is set as the active profile.| -|EntryModified|[`AddressableAssetEntry`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetEntry), or list of entries that were modified.| -|BuildSettingsChanged|[`AddressableAssetBuildSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetBuildSettings) object that was modified.| -|ActiveBuildScriptChanged|[`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder) build script that was set as the active builder.| -|DataBuilderAdded|`ScriptableObject`, typically one that implements [`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder), that was added to the list of DataBuilders.| -|DataBuilderRemoved|`ScriptableObject`, typically one that implements [`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder), that was removed from the list of DataBuilders.| -|InitializationObjectAdded|`ScriptableObject`, typically one that implements [`IObjectInitializationDataProvider`](xref:UnityEngine.ResourceManagement.Util.IObjectInitializationDataProvider), that was added to the list of InitializationObjects.| -|InitializationObjectRemoved|`ScriptableObject`, typically one that implements [`IObjectInitializationDataProvider`](xref:UnityEngine.ResourceManagement.Util.IObjectInitializationDataProvider), that was removed from the list of InitializationObjects.| -|ActivePlayModeScriptChanged|[`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder) that was set as the new active Play mode data builder.| -|BatchModification|`null`. This event is primarily used to indicate several modification events happening at the same time and the [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings) object needed to be marked dirty.| -|HostingServicesManagerModified| [`HostingServicesManager`](xref:UnityEditor.AddressableAssets.HostingServices.HostingServicesManager), or [`HttpHostingService`](xref:UnityEditor.AddressableAssets.HostingServices.HttpHostingService) that were modified.| -|GroupMoved|Full list of [`AddressableAssetGroups`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup).| +--- +uid: addressables-modification-events +--- + +# Modification events + +You can use modification events to signal to parts of the Addressables system when certain data is manipulated, such as when an `AddressableAssetGroup` or an `AddressableAssetEntry` is added or removed. + +Modification events are triggered as part of `SetDirty` calls inside of Addressables. `SetDirty` is used to indicate when an asset needs to be re-serialized by the `AssetDatabase`. As part of `SetDirty`, two modification event callbacks can trigger: + +* `public static event Action OnModificationGlobal` +* `public Action OnModification { get; set; }` + +These callbacks are found on [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings) through a static, or instance, accessors respectively. + +## Modification event example + +```c# +AddressableAssetSettings.OnModificationGlobal += (settings, modificationEvent, data) => + { + if(modificationEvent == AddressableAssetSettings.ModificationEvent.EntryAdded) + { + //Do work + } + }; + + AddressableAssetSettingsDefaultObject.Settings.OnModification += (settings, modificationEvent, data) => + { + if (modificationEvent == AddressableAssetSettings.ModificationEvent.EntryAdded) + { + //Do work + } + }; +``` +Modification events pass in a generic `object` for the data associated with the event. The following table outlines a list of the modification events and the data types that are passed with them. + +|**Modification event**|**Data passed**| +|---|---| +|GroupAdded|[`AddressableAssetGroup`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup), or list of groups that were added.| +|GroupRemoved| [`AddressableAssetGroup`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup), or list of groups that were removed.| +|GroupRenamed| [`AddressableAssetGroup`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup), or list of groups that were renamed.| +|GroupSchemaAdded| [`AddressableAssetGroup`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup), or list of groups that had schemas added to them.| +|GroupSchemaRemoved|[`AddressableAssetGroup`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup), or list of groups that had schemas removed from them.| +|GroupSchemaModified| [`AddressableAssetGroupSchema`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroupSchema) that was modified.| +|GroupTemplateAdded| `ScriptableObject`, typically one that implements [`IGroupTemplate`](xref:UnityEditor.AddressableAssets.Settings.IGroupTemplate), that was the added Group Template object.| +|GroupTemplateRemoved|`ScriptableObject`, typically one that implements [`IGroupTemplate`](xref:UnityEditor.AddressableAssets.Settings.IGroupTemplate), that was the removed Group Template object.| +|GroupTemplateSchemaAdded| [`AddressableAssetGroupTemplate`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroupTemplate) that had a schema added.| +|GroupTemplateSchemaRemoved|[`AddressableAssetGroupTemplate`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroupTemplate) that had a schema removed.| +|EntryCreated|[`AddressableAssetEntry`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetEntry) that was created.| +|EntryAdded|[`AddressableAssetEntry`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetEntry), or list of entries that were added.| +|EntryMoved|[`AddressableAssetEntry`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetEntry), or list of entries that were moved from one group to another.| +|EntryRemoved|[`AddressableAssetEntry`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetEntry), or list of entries that were removed.| +|LabelAdded|`string` label that was added.| +|LabelRemoved|`string` label that was removed.| +|ProfileAdded|`BuildProfile` that was added.| +|ProfileRemoved|`string` of the profile ID that was removed.| +|ProfileModified|`BuildProfile` that was modified, or `null` if a batch of `BuildProfile` objects were modified.| +|ActiveProfileSet|The data passed with this event if the `string` of the profile ID that is set as the active profile.| +|EntryModified|[`AddressableAssetEntry`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetEntry), or list of entries that were modified.| +|BuildSettingsChanged|[`AddressableAssetBuildSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetBuildSettings) object that was modified.| +|ActiveBuildScriptChanged|[`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder) build script that was set as the active builder.| +|DataBuilderAdded|`ScriptableObject`, typically one that implements [`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder), that was added to the list of DataBuilders.| +|DataBuilderRemoved|`ScriptableObject`, typically one that implements [`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder), that was removed from the list of DataBuilders.| +|InitializationObjectAdded|`ScriptableObject`, typically one that implements [`IObjectInitializationDataProvider`](xref:UnityEngine.ResourceManagement.Util.IObjectInitializationDataProvider), that was added to the list of InitializationObjects.| +|InitializationObjectRemoved|`ScriptableObject`, typically one that implements [`IObjectInitializationDataProvider`](xref:UnityEngine.ResourceManagement.Util.IObjectInitializationDataProvider), that was removed from the list of InitializationObjects.| +|ActivePlayModeScriptChanged|[`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder) that was set as the new active Play mode data builder.| +|BatchModification|`null`. This event is primarily used to indicate several modification events happening at the same time and the [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings) object needed to be marked dirty.| +|HostingServicesManagerModified| [`HostingServicesManager`](xref:UnityEditor.AddressableAssets.HostingServices.HostingServicesManager), or [`HttpHostingService`](xref:UnityEditor.AddressableAssets.HostingServices.HttpHostingService) that were modified.| +|GroupMoved|Full list of [`AddressableAssetGroups`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetGroup).| |CertificateHandlerChanged|New `System.Type` of the certificate handler to be used.| \ No newline at end of file diff --git a/Documentation~/MultiProject.md b/Documentation~/MultiProject.md index be1d537b..9e0005af 100644 --- a/Documentation~/MultiProject.md +++ b/Documentation~/MultiProject.md @@ -1,36 +1,36 @@ ---- -uid: addressables-multiple-projects ---- - -# Load content from multiple projects - -If you're working with multiple projects, such as a large project broken up across multiple Unity projects, you can use [`Addressables.LoadContentCatalogAsync`](LoadContentCatalogAsync.md) to link together code and content across the various projects. - -## Set up multiple projects - -To create a multi-project setup make sure of the following: - -* Each project uses the same version of the Unity Editor -* Each project uses the same version of the Addressables package - -Projects can contain whatever assets and code you need for your given situation. One of your projects must be your main or source project. This is the project that you'll build and deploy your game binaries from. Typically, this source project is comprised of code and little to no content. The main piece of content in the primary project is a bootstrap scene at minimum. You might want to include any scenes that need to be local for performance purposes before any AssetBundles have had a chance to be downloaded and cached. - -Secondary projects are the opposit and contain content and little to no code. These projects need to have all remote Addressable Groups and Build Remote Catalog enabled. Any local data built into these projects can't be loaded in your source project's application. Non-critical scenes can live in these projects and be downloaded by the primary project when requested. - -## Work with multiple project - -Once you have your projects setup, the workflow generally is as follows: - -1. Build remote content for all secondary projects -2. Build Addressables content for source project -3. Start the source project's Play mode or build the source project's binaries -4. In source project, use [`Addressables.LoadContentCatalogAsync`](LoadContentCatalogAsync.md) to load the remote catalogs of your other various projects -5. Proceed with game runtime as normal. Now that the catalogs are loaded, Addressables can load assets from any of these locations. - -It might be worth having a minimal amount of content built locally in the source project. Each project is unique, and has unique needs, but having a small set of content needed to run your game in the event of internet connection issues or other various problems is advisable. - -## Handle shaders - -Addressables builds a Unity built in shader bundle for each set of Addressables player data that gets built. This means that when multiple AssetBundles are loaded that were built in secondary projects, there might be multiple built in shader bundles loaded at the same time. - +--- +uid: addressables-multiple-projects +--- + +# Load content from multiple projects + +If you're working with multiple projects, such as a large project broken up across multiple Unity projects, you can use [`Addressables.LoadContentCatalogAsync`](LoadContentCatalogAsync.md) to link together code and content across the various projects. + +## Set up multiple projects + +To create a multi-project setup make sure of the following: + +* Each project uses the same version of the Unity Editor +* Each project uses the same version of the Addressables package + +Projects can contain whatever assets and code you need for your given situation. One of your projects must be your main or source project. This is the project that you'll build and deploy your game binaries from. Typically, this source project is comprised of code and little to no content. The main piece of content in the primary project is a bootstrap scene at minimum. You might want to include any scenes that need to be local for performance purposes before any AssetBundles have had a chance to be downloaded and cached. + +Secondary projects are the opposit and contain content and little to no code. These projects need to have all remote Addressable Groups and Build Remote Catalog enabled. Any local data built into these projects can't be loaded in your source project's application. Non-critical scenes can live in these projects and be downloaded by the primary project when requested. + +## Work with multiple project + +Once you have your projects setup, the workflow generally is as follows: + +1. Build remote content for all secondary projects +2. Build Addressables content for source project +3. Start the source project's Play mode or build the source project's binaries +4. In source project, use [`Addressables.LoadContentCatalogAsync`](LoadContentCatalogAsync.md) to load the remote catalogs of your other various projects +5. Proceed with game runtime as normal. Now that the catalogs are loaded, Addressables can load assets from any of these locations. + +It might be worth having a minimal amount of content built locally in the source project. Each project is unique, and has unique needs, but having a small set of content needed to run your game in the event of internet connection issues or other various problems is advisable. + +## Handle shaders + +Addressables builds a Unity built in shader bundle for each set of Addressables player data that gets built. This means that when multiple AssetBundles are loaded that were built in secondary projects, there might be multiple built in shader bundles loaded at the same time. + Depending on your specific situation, you might need to use the Shader Bundle Naming Prefix on the `AddressableAssetSettings` object. Each built in shader bundle needs to be named different from others built in your other projects. If they're not named differently you'll get `The AssetBundle [bundle] can't be loaded because another AssetBundle with the same files is already loaded.` errors. \ No newline at end of file diff --git a/Documentation~/PackingGroupsAsBundles.md b/Documentation~/PackingGroupsAsBundles.md index a0624385..874e9ffc 100644 --- a/Documentation~/PackingGroupsAsBundles.md +++ b/Documentation~/PackingGroupsAsBundles.md @@ -1,26 +1,26 @@ ---- -uid: addressables-packing-groups ---- - -# Pack groups into AssetBundles - -You have three options when you choose how to pack the assets in a group into AssetBundles: - -* You can pack all Addressables assigned to a group together in a single bundle. This corresponds to the **Pack Together** bundle mode. -* You can pack each Addressable assigned to a group separately in its own bundle. This corresponds to the **Pack Separately** bundle mode. -* You can pack all Addressables sharing the same set of labels into their own bundles. This corresponds to the **Pack Together By Label** bundle mode. - -For more information on bundle modes, refer to [Advanced Group Settings](xref:addressables-content-packing-and-loading-schema). - -Scene assets are always packed separately from other Addressable assets in the group. For this reason, a group containing a mix of scene and non-scene assets always produces at least two bundles when built: one for scenes and one for everything else. - -When you choose to pack each Addressable asset separately, Unity treats compound assets (such as sprite sheets) and assets in folders marked as Addressables differently: - -* All the assets in a folder that are marked as Addressable are packed together in the same folder (except for assets in the folder that are individually marked as Addressable themselves). -* Sprites in an Addressable Sprite Atlas are included in the same bundle. - -Refer to [Content Packing & Loading settings](xref:addressables-content-packing-and-loading-schema) for more information. - -> [!NOTE] -> Keeping many assets in the same group can increase the chance of version control conflicts when many people work on the same project. - +--- +uid: addressables-packing-groups +--- + +# Pack groups into AssetBundles + +You have three options when you choose how to pack the assets in a group into AssetBundles: + +* You can pack all Addressables assigned to a group together in a single bundle. This corresponds to the **Pack Together** bundle mode. +* You can pack each Addressable assigned to a group separately in its own bundle. This corresponds to the **Pack Separately** bundle mode. +* You can pack all Addressables sharing the same set of labels into their own bundles. This corresponds to the **Pack Together By Label** bundle mode. + +For more information on bundle modes, refer to [Advanced Group Settings](xref:addressables-content-packing-and-loading-schema). + +Scene assets are always packed separately from other Addressable assets in the group. For this reason, a group containing a mix of scene and non-scene assets always produces at least two bundles when built: one for scenes and one for everything else. + +When you choose to pack each Addressable asset separately, Unity treats compound assets (such as sprite sheets) and assets in folders marked as Addressables differently: + +* All the assets in a folder that are marked as Addressable are packed together in the same folder (except for assets in the folder that are individually marked as Addressable themselves). +* Sprites in an Addressable Sprite Atlas are included in the same bundle. + +Refer to [Content Packing & Loading settings](xref:addressables-content-packing-and-loading-schema) for more information. + +> [!NOTE] +> Keeping many assets in the same group can increase the chance of version control conflicts when many people work on the same project. + diff --git a/Documentation~/ProfileVariables.md b/Documentation~/ProfileVariables.md index 6b324fa7..05c363d3 100644 --- a/Documentation~/ProfileVariables.md +++ b/Documentation~/ProfileVariables.md @@ -1,75 +1,75 @@ ---- -uid: addressables-profile-variables ---- - -# Profile variables overview - -Profile variables are generic key/value combinations that you can use to change Addressables configurations for different development situations. - -There are two types of profile variables: - -* **Standard**: Standalone key/value pairs -* **Path pairs**: Uses a special naming convention to connect sets of variables together. - -Path pairs are typically used to change between different build and load paths for different development situations. For example, you might use path pairs to change the build and load paths for your Addressable content for various platforms. - -## Add a new standard variable - -You can add two kinds of variables to your profiles: - -* **Variable**: A basic variable, which defines a single value -* **Build and Load Path Variable**: A path pair, which defines a set of two path values. One value is for the build path and one is for the load path - -To add a new Profile variable, open the [Addressables Profiles window](addressables-profiles-window.md), open the **Create** menu and select either **Variable** or **Build Load Path Variable**. Assign the new variable a name and value, then select **Save**. Addressables then adds the new variable to all profiles. Right-click on the variable name to rename or delete the variable. - -You can use basic variables as components of your path values (for example, **BuildTarget**) and you can use them in your own build scripts. Use path pair variables to set the **Build & Local Paths** setting of your [groups](Groups.md) and remote catalog. - - -### Path Pairs - -Path pairs define a matched set of `BuildPath` and `LoadPath` variables. When you create a path pair, you can use the pair name to assign the path setting of a group or remote catalog as a unit. - -To create a path pair, go to **Create** and select **Build Load Path Variables**. Assign the path pair a prefix name and assign path strings to the individual fields. - -![](images/profiles-pairs.png)
*A new path pair* - -The new path pair uses the **Custom** setting for the **Bundle Location** property with your initial values. You can change to a different **Bundle Location** if needed. - -> [!TIP] -> You can convert two regular variables for the build and load paths into a path pair by renaming them in the Profile window. Set one to `VariableName.BuildPath` and the other to `VariableName.LoadPath`. - -![Path pairs grouped by a common prefix and separated by a period.](images/profiles-with-pairs.png)
-_The **Addressables Profiles** window showing two profiles with two path pairs._ - -### Default path values - -The default values for the build and load paths are: - -* Local build path: `[UnityEditor.EditorUserBuildSettings.activeBuildTarget]` -* Local load path: `[UnityEngine.AddressableAssets.Addressables.BuildPath]/[BuildTarget]` -* Remote build path: `ServerData/[BuildTarget]` -* Remote load path: - -Usually, you shouldn't need to change the local path values. The Unity build system expects the AssetBundles and other files to exist in the default location. If you change the local paths, you must copy the files from the build path to the load path before making your Player build. The load path must always be within the Unity `StreamingAssets` folder. - -If you distribute content remotely, you must change the remote load path to reflect the URL at which you host your remote content. You can set the remote build path to any convenient location: the build system doesn't rely on the default value. - -## Profile variable syntax - -All Profile variables are of type `string`. You can assign them a fixed path or value. You can also use two syntax designations to derive all or part of a variable's value from static properties or other variables: - -* __Brackets [ ]__: Addressables evaluates entries surrounded by brackets at build time. The entries can be other profile variables such as `BuildTarget`, or code variables such as `UnityEditor.EditorUserBuildSettings.activeBuildTarget`. During a build, as Addressables processes your groups, it evaluates the strings inside brackets and writes the result into the catalog. -* __Braces { }__: Addressables evaluates entries surrounded by braces at runtime. You can use code variables of runtime classes, such as `{UnityEngine.AddressableAssets.Addressables.RuntimePath}`. - -You can use static fields and properties inside either the brackets or braces. The names must be fully qualified and the types must be valid in context. For example, classes in the `UnityEditor` namespace can't be used at runtime. - -The code variables used in the default Profile variable settings include: - -* `[UnityEditor.EditorUserBuildSettings.activeBuildTarget]` -* `[UnityEngine.AddressableAssets.Addressables.BuildPath]` -* `[UnityEngine.AddressableAssets.Addressables.RuntimePath]` - -For example, a load path of `{MyNamespace.MyClass.MyURL}/content/[BuildTarget]` is set on a group that creates an AssetBundle called `trees.bundle`. During the build, the catalog registers the load path for that bundle as `{MyNamespace.MyClass.MyURL}/content/Android/trees.bundle`, evaluates `[BuildTarget]` as `Android`, and adds the AssetBundle name to the path. At runtime as the Addressables system processes the catalog it evaluates `{MyNamespace.MyClass.MyURL}` to produce the final load path, `http://example.com/content/Android/trees.bundle`. - -> [!NOTE] +--- +uid: addressables-profile-variables +--- + +# Profile variables overview + +Profile variables are generic key/value combinations that you can use to change Addressables configurations for different development situations. + +There are two types of profile variables: + +* **Standard**: Standalone key/value pairs +* **Path pairs**: Uses a special naming convention to connect sets of variables together. + +Path pairs are typically used to change between different build and load paths for different development situations. For example, you might use path pairs to change the build and load paths for your Addressable content for various platforms. + +## Add a new standard variable + +You can add two kinds of variables to your profiles: + +* **Variable**: A basic variable, which defines a single value +* **Build and Load Path Variable**: A path pair, which defines a set of two path values. One value is for the build path and one is for the load path + +To add a new Profile variable, open the [Addressables Profiles window](addressables-profiles-window.md), open the **Create** menu and select either **Variable** or **Build Load Path Variable**. Assign the new variable a name and value, then select **Save**. Addressables then adds the new variable to all profiles. Right-click on the variable name to rename or delete the variable. + +You can use basic variables as components of your path values (for example, **BuildTarget**) and you can use them in your own build scripts. Use path pair variables to set the **Build & Local Paths** setting of your [groups](Groups.md) and remote catalog. + + +### Path Pairs + +Path pairs define a matched set of `BuildPath` and `LoadPath` variables. When you create a path pair, you can use the pair name to assign the path setting of a group or remote catalog as a unit. + +To create a path pair, go to **Create** and select **Build Load Path Variables**. Assign the path pair a prefix name and assign path strings to the individual fields. + +![](images/profiles-pairs.png)
*A new path pair* + +The new path pair uses the **Custom** setting for the **Bundle Location** property with your initial values. You can change to a different **Bundle Location** if needed. + +> [!TIP] +> You can convert two regular variables for the build and load paths into a path pair by renaming them in the Profile window. Set one to `VariableName.BuildPath` and the other to `VariableName.LoadPath`. + +![Path pairs grouped by a common prefix and separated by a period.](images/profiles-with-pairs.png)
+_The **Addressables Profiles** window showing two profiles with two path pairs._ + +### Default path values + +The default values for the build and load paths are: + +* Local build path: `[UnityEditor.EditorUserBuildSettings.activeBuildTarget]` +* Local load path: `[UnityEngine.AddressableAssets.Addressables.BuildPath]/[BuildTarget]` +* Remote build path: `ServerData/[BuildTarget]` +* Remote load path: + +Usually, you shouldn't need to change the local path values. The Unity build system expects the AssetBundles and other files to exist in the default location. If you change the local paths, you must copy the files from the build path to the load path before making your Player build. The load path must always be within the Unity `StreamingAssets` folder. + +If you distribute content remotely, you must change the remote load path to reflect the URL at which you host your remote content. You can set the remote build path to any convenient location: the build system doesn't rely on the default value. + +## Profile variable syntax + +All Profile variables are of type `string`. You can assign them a fixed path or value. You can also use two syntax designations to derive all or part of a variable's value from static properties or other variables: + +* __Brackets [ ]__: Addressables evaluates entries surrounded by brackets at build time. The entries can be other profile variables such as `BuildTarget`, or code variables such as `UnityEditor.EditorUserBuildSettings.activeBuildTarget`. During a build, as Addressables processes your groups, it evaluates the strings inside brackets and writes the result into the catalog. +* __Braces { }__: Addressables evaluates entries surrounded by braces at runtime. You can use code variables of runtime classes, such as `{UnityEngine.AddressableAssets.Addressables.RuntimePath}`. + +You can use static fields and properties inside either the brackets or braces. The names must be fully qualified and the types must be valid in context. For example, classes in the `UnityEditor` namespace can't be used at runtime. + +The code variables used in the default Profile variable settings include: + +* `[UnityEditor.EditorUserBuildSettings.activeBuildTarget]` +* `[UnityEngine.AddressableAssets.Addressables.BuildPath]` +* `[UnityEngine.AddressableAssets.Addressables.RuntimePath]` + +For example, a load path of `{MyNamespace.MyClass.MyURL}/content/[BuildTarget]` is set on a group that creates an AssetBundle called `trees.bundle`. During the build, the catalog registers the load path for that bundle as `{MyNamespace.MyClass.MyURL}/content/Android/trees.bundle`, evaluates `[BuildTarget]` as `Android`, and adds the AssetBundle name to the path. At runtime as the Addressables system processes the catalog it evaluates `{MyNamespace.MyClass.MyURL}` to produce the final load path, `http://example.com/content/Android/trees.bundle`. + +> [!NOTE] > Referencing a runtime variable in a Profile string doesn't prevent Unity from stripping that variable from your application's runtime libraries during the build optimization phase if nothing else in your code references the same variable. \ No newline at end of file diff --git a/Documentation~/ProfilerModule.md b/Documentation~/ProfilerModule.md index ec8e7d88..6bc609d4 100644 --- a/Documentation~/ProfilerModule.md +++ b/Documentation~/ProfilerModule.md @@ -1,97 +1,97 @@ ---- -uid: addressables-profiler-module ---- - -# Addressables Profiler module - -The Addressables Profiler is a Unity Editor Profiler module that you can use to find out what content is loaded from Addressables. - -## Prerequisites - -* Basic Profiler usage supported from Unity 2021 or newer. To view detailed Profiler information 2022.2 or newer is required. All information in this documentation is for editor version 2022.2. -* [Build Reports](BuildLayoutReport.md) must be enabled and the runtime being profiled requires a build report. To enable build reports, go to the Editor preferences, select the [Addressables preferences](addressables-preferences.md), then enable **Debug Build Layout**. -* Collecting information about the running content requires build time data collection information for the debug build layout. These files are stored in the folder `/Library/com.unity.addressables/buildReports`. Each build you make creates a new build report file in this directory. When running the Profiler, any incoming Profiler data from the Profiler target is synced and looks for the build report file for that runtime in the `buildReports` folder. If the build report doesn't exist, such as if the project was built using a different machine, then the Profiler doesn't display the information for that data. Select **Find in file system** to opens a file select window, which can you can use to locate a build report file on disk elsewhere. -* The Unity Profiling Core API package is required for the Profiler to run. To install this package either install through the Package Manager or though the Addressables preferences window when enabling **Debug Build Layout**. -* The Profiler module doesn't support the Play Mode Scripts **Use Asset Database (Fastest)**. The content must be built and using **Use Existing Build** based Play Mode Scripts. - -## Open the Profiler module - -To open the Addressables Profiler: - -1. Open the Profiler window (__Window__ > __Analysis__ > __Profiler__). -1. In the top right of the Profiler window select the dropdown button labeled __Profiler Modules__. -1. Enable the option named __Addressable Assets__. - -## View the module - -The module view can be used to observe how many AssetBundles, assets, scenes, and catalogs are loaded at the frame in time. - -The following screenshot displays three assets and one Scene, from one catalog, and six AssetBundles: - -![](images/profiler-module.png) - -When you select a frame, the detail pane fills with information for that frame and displays a tree view for the loaded content. - -To change what content is displayed, select the detail pane toolbar dropdown button **View**. It has the following options: - -* __Groups__: Include groups in the tree view. -* __Asset Bundles__: Include AssetBundles in the tree view. -* __Assets__: Include assets in the tree view. -* __Objects__: Include the objects that are loaded within an asset. -* __Assets not loaded__: Display assets that are within a loaded bundle, but not actively loaded. - -The details pane has two regions. On the left side is the Tree View of the content, which displays loaded content and you can expand to display in depth content. On the right side is the Details Inspector, which displays detailed information for the content selected from the Tree View. - -![](images/profiler-details-pane.png) - -## Content Tree View - -You can enable or disable the Tree View columns based on your preferences. Context click on the Tree View header to display a list of the available columns. - -Each column displays information depending on the content in the row: - -|**Column**|**Description**| -|---|---| -| __Name__|Depending on the type, displays either:

- The Group name
-AssetBundle file name
- The address of the asset, or the asset path if the address isn't used
- Object name, or asset type for scenes. -|__Type__| The type of the asset or object.| -|__Handles__| Number of Addressables handles that actively hold onto the content. This is often referred to as Reference Count. During loading there is an additional handle to the content.| -|__Status__| The state of the content at the time, which can be:

- __Queued__: An AssetBundle is in the download queue.
- __Downloading__: An AssetBundle is being downloaded.
- __Loading__: The content is being loaded in the background.
- __Active__: The content is loaded and in use.
- __Released__: The content has been released and there are no more active handles to the content, but might still be in memory. Refer to [Memory management](MemoryManagement.md) for more information.| -|__%__| If the **Status** is **Downloading** or **Loading**, this displays the percentage progress of the download or load operation.| -|__Source__| Displays where the AssetBundle was loaded from:

- __Local__: Loaded from a local file on disk.
- __Cache__: Previously downloaded and cached to disk, and loading was from the cached file.
- __Download__: The AssetBundle hadn't been cached and needed to be downloaded.| -|__Refs By__| Number of elements that reference this content.| -|__Refs To__| Number of elements that this content references.| - -### Released assets - -When content is released from Addressables it might still be in memory until all content from the AssetBundle is released, and any other AssetBundle that has a dependency on any asset within the AssetBundle is also released. - -Released content is indicated by a faded, or grayed out font color in the Content Tree view. Refer to [Memory management](MemoryManagement.md) for more information on how Addressables manages memory. - -### Filter content - -You can use the search bar in the details pane to filter the content name. You can use search filter syntax to find other content: - -* __Handles__: `h` -* __Type__: `assetType`, `t` -* __Status__: `s` -* __RefsTo__: `rt`, `r` -* __RefsBy__: `rb`, `p` -* __Source__: `bundlesource`, `bs`, `b` - -Filter syntax is `:`, where the field is a numerical field, for example `handles:3`. The default equality is `=`. You can change the equality to greater than `>` or less than `<` by including the symbol before the number, for example `Handles:>2`. - -You can either use the column name without a space, or with the shorthand tag to filter. - -You can also use the type filter to filter by inclusion type. Use `explicit` where an asset is explicitly included in a group through Addressables, or `implicit`, where the asset was included in the AssetBundle because another included references to it. For example, `type:explicit`. - -## Inspect content details - -When you select content from the Addressables Profiler module, the Inspector displays detailed information about the content, as follows: - -![](images/profiler-inspector.png)
_Selected content in the Inspector_ - -|**Section**|**Description**| -|---|---| -|**Selection Details** (A)| Contains detailed information, including the source, load path, compression, and group of the asset.| -|**Help** (B)| Contains information including any hints for any settings that might not be intended.| -|**References** (C)|Contains information about references to and from other AssetBundles.| +--- +uid: addressables-profiler-module +--- + +# Addressables Profiler module + +The Addressables Profiler is a Unity Editor Profiler module that you can use to find out what content is loaded from Addressables. + +## Prerequisites + +* Basic Profiler usage supported from Unity 2021 or newer. To view detailed Profiler information 2022.2 or newer is required. All information in this documentation is for editor version 2022.2. +* [Build Reports](BuildLayoutReport.md) must be enabled and the runtime being profiled requires a build report. To enable build reports, go to the Editor preferences, select the [Addressables preferences](addressables-preferences.md), then enable **Debug Build Layout**. +* Collecting information about the running content requires build time data collection information for the debug build layout. These files are stored in the folder `/Library/com.unity.addressables/buildReports`. Each build you make creates a new build report file in this directory. When running the Profiler, any incoming Profiler data from the Profiler target is synced and looks for the build report file for that runtime in the `buildReports` folder. If the build report doesn't exist, such as if the project was built using a different machine, then the Profiler doesn't display the information for that data. Select **Find in file system** to opens a file select window, which can you can use to locate a build report file on disk elsewhere. +* The Unity Profiling Core API package is required for the Profiler to run. To install this package either install through the Package Manager or though the Addressables preferences window when enabling **Debug Build Layout**. +* The Profiler module doesn't support the Play Mode Scripts **Use Asset Database (Fastest)**. The content must be built and using **Use Existing Build** based Play Mode Scripts. + +## Open the Profiler module + +To open the Addressables Profiler: + +1. Open the Profiler window (__Window__ > __Analysis__ > __Profiler__). +1. In the top right of the Profiler window select the dropdown button labeled __Profiler Modules__. +1. Enable the option named __Addressable Assets__. + +## View the module + +The module view can be used to observe how many AssetBundles, assets, scenes, and catalogs are loaded at the frame in time. + +The following screenshot displays three assets and one Scene, from one catalog, and six AssetBundles: + +![](images/profiler-module.png) + +When you select a frame, the detail pane fills with information for that frame and displays a tree view for the loaded content. + +To change what content is displayed, select the detail pane toolbar dropdown button **View**. It has the following options: + +* __Groups__: Include groups in the tree view. +* __Asset Bundles__: Include AssetBundles in the tree view. +* __Assets__: Include assets in the tree view. +* __Objects__: Include the objects that are loaded within an asset. +* __Assets not loaded__: Display assets that are within a loaded bundle, but not actively loaded. + +The details pane has two regions. On the left side is the Tree View of the content, which displays loaded content and you can expand to display in depth content. On the right side is the Details Inspector, which displays detailed information for the content selected from the Tree View. + +![](images/profiler-details-pane.png) + +## Content Tree View + +You can enable or disable the Tree View columns based on your preferences. Context click on the Tree View header to display a list of the available columns. + +Each column displays information depending on the content in the row: + +|**Column**|**Description**| +|---|---| +| __Name__|Depending on the type, displays either:

- The Group name
-AssetBundle file name
- The address of the asset, or the asset path if the address isn't used
- Object name, or asset type for scenes. +|__Type__| The type of the asset or object.| +|__Handles__| Number of Addressables handles that actively hold onto the content. This is often referred to as Reference Count. During loading there is an additional handle to the content.| +|__Status__| The state of the content at the time, which can be:

- __Queued__: An AssetBundle is in the download queue.
- __Downloading__: An AssetBundle is being downloaded.
- __Loading__: The content is being loaded in the background.
- __Active__: The content is loaded and in use.
- __Released__: The content has been released and there are no more active handles to the content, but might still be in memory. Refer to [Memory management](MemoryManagement.md) for more information.| +|__%__| If the **Status** is **Downloading** or **Loading**, this displays the percentage progress of the download or load operation.| +|__Source__| Displays where the AssetBundle was loaded from:

- __Local__: Loaded from a local file on disk.
- __Cache__: Previously downloaded and cached to disk, and loading was from the cached file.
- __Download__: The AssetBundle hadn't been cached and needed to be downloaded.| +|__Refs By__| Number of elements that reference this content.| +|__Refs To__| Number of elements that this content references.| + +### Released assets + +When content is released from Addressables it might still be in memory until all content from the AssetBundle is released, and any other AssetBundle that has a dependency on any asset within the AssetBundle is also released. + +Released content is indicated by a faded, or grayed out font color in the Content Tree view. Refer to [Memory management](MemoryManagement.md) for more information on how Addressables manages memory. + +### Filter content + +You can use the search bar in the details pane to filter the content name. You can use search filter syntax to find other content: + +* __Handles__: `h` +* __Type__: `assetType`, `t` +* __Status__: `s` +* __RefsTo__: `rt`, `r` +* __RefsBy__: `rb`, `p` +* __Source__: `bundlesource`, `bs`, `b` + +Filter syntax is `:`, where the field is a numerical field, for example `handles:3`. The default equality is `=`. You can change the equality to greater than `>` or less than `<` by including the symbol before the number, for example `Handles:>2`. + +You can either use the column name without a space, or with the shorthand tag to filter. + +You can also use the type filter to filter by inclusion type. Use `explicit` where an asset is explicitly included in a group through Addressables, or `implicit`, where the asset was included in the AssetBundle because another included references to it. For example, `type:explicit`. + +## Inspect content details + +When you select content from the Addressables Profiler module, the Inspector displays detailed information about the content, as follows: + +![](images/profiler-inspector.png)
_Selected content in the Inspector_ + +|**Section**|**Description**| +|---|---| +|**Selection Details** (A)| Contains detailed information, including the source, load path, compression, and group of the asset.| +|**Help** (B)| Contains information including any hints for any settings that might not be intended.| +|**References** (C)|Contains information about references to and from other AssetBundles.| diff --git a/Documentation~/RemoteContentDistribution.md b/Documentation~/RemoteContentDistribution.md index fd49c828..d9ffa540 100644 --- a/Documentation~/RemoteContentDistribution.md +++ b/Documentation~/RemoteContentDistribution.md @@ -1,16 +1,16 @@ ---- -uid: addressables-remote-content-distribution ---- - -# Distribute remote content - -Information on how to distribute content remotely to reduce download sizes. - -|**Topic**|**Description**| -|---|---| -|[Distribute remote content overview](remote-content-intro.md)|Understand the options to distribute content remotely.| -|[Enable remote content](remote-content-enable.md)|Enable remote content builds.| -|[Remote content profiles](remote-content-profiles.md)|Set up profiles for remote content.| -|[Remote content AssetBundle caching](remote-content-assetbundle-cache.md)|Understand how AssetBundles are cached remotely.| -|[Pre-download remote content](remote-content-predownload.md)|Workflows for pre-downloading remote content.| -|[Use Addressables with Cloud Content Delivery](AddressablesCCD.md)|Use Addressables with the CCD service.| +--- +uid: addressables-remote-content-distribution +--- + +# Distribute remote content + +Information on how to distribute content remotely to reduce download sizes. + +|**Topic**|**Description**| +|---|---| +|[Distribute remote content overview](remote-content-intro.md)|Understand the options to distribute content remotely.| +|[Enable remote content](remote-content-enable.md)|Enable remote content builds.| +|[Remote content profiles](remote-content-profiles.md)|Set up profiles for remote content.| +|[Remote content AssetBundle caching](remote-content-assetbundle-cache.md)|Understand how AssetBundles are cached remotely.| +|[Pre-download remote content](remote-content-predownload.md)|Workflows for pre-downloading remote content.| +|[Use Addressables with Cloud Content Delivery](AddressablesCCD.md)|Use Addressables with the CCD service.| diff --git a/Documentation~/RuntimeAddressables.md b/Documentation~/RuntimeAddressables.md index f843c28f..f36c13c0 100644 --- a/Documentation~/RuntimeAddressables.md +++ b/Documentation~/RuntimeAddressables.md @@ -1,17 +1,17 @@ ---- -uid: addressable-runtime ---- - -# Use Addressables at runtime - -Once you have Addressable assets organized into groups and built into AssetBundles, you must load, instantiate, and release them at runtime. - -Addressables uses a reference counting system to make sure that assets are only kept in memory while they're needed. - -|**Topic**|**Description**| -|---|---| -|[Addressables initialization](InitializeAsync.md)|Understand how and when Addressables are initialized.| -|[Memory management overview](MemoryManagement.md)|Understand how Unity manages Addressables memory.| -|[Manage catalogs at runtime](LoadContentCatalogAsync.md)|How to manage the catalogs in your project at runtime.| -|[Get addresses at runtime](GetRuntimeAddress.md)|How to get and use addresses at runtime.| +--- +uid: addressable-runtime +--- + +# Use Addressables at runtime + +Once you have Addressable assets organized into groups and built into AssetBundles, you must load, instantiate, and release them at runtime. + +Addressables uses a reference counting system to make sure that assets are only kept in memory while they're needed. + +|**Topic**|**Description**| +|---|---| +|[Addressables initialization](InitializeAsync.md)|Understand how and when Addressables are initialized.| +|[Memory management overview](MemoryManagement.md)|Understand how Unity manages Addressables memory.| +|[Manage catalogs at runtime](LoadContentCatalogAsync.md)|How to manage the catalogs in your project at runtime.| +|[Get addresses at runtime](GetRuntimeAddress.md)|How to get and use addresses at runtime.| |[Modification events](ModificationEvents.md)|Understand modification events, which signal when data is manipulated.| \ No newline at end of file diff --git a/Documentation~/SamplesOverview.md b/Documentation~/SamplesOverview.md index 98c04506..d3b4a642 100644 --- a/Documentation~/SamplesOverview.md +++ b/Documentation~/SamplesOverview.md @@ -1,20 +1,20 @@ ---- -uid: samples-overview ---- - -# Addressables samples - -The Addressables package contains samples that you can download into your project. To access the samples go to **Window** > **Package Manager** > **Addressables**. - -These samples include examples on how to disable asset importing during a build, creating custom build and Play mode scripts, and providing an `AddressableUtility` class. - -When you download and import a sample, it's placed inside the `Assets/Samples/Addressables/{AddressablesVersionNumber}` path of your project. - -|**Sample**|**Description**| -|---|---| -|**Addressables Utility**|Contains a set of utility functions for Addressables. The script contains a static method `GetAddressFromAssetReference` which provides the Addressable address used to reference a given `AssetRefence` internally.| -|**ComponentReference**|Creates an AssetReference that's restricted to having a specific component. For more information see the ComponentReference sample project located in the [Addressables Samples](https://github.com/Unity-Technologies/Addressables-Sample) repository.| -|**Custom Build and Playmode Scripts**|Includes two [custom scripts](xref:addressables-api-build-player-content):

- A custom Play mode script located in `Editor/CustomPlayModeScript.cs` of the sample. This script works similarly to the Use Existing Build (requires built groups) play mode script already included. The methods added to accomplish this are `CreateCurrentSceneOnlyBuildSetup` and `RevertCurrentSceneSetup` on the `CustomBuildScript`.
- A custom build script located in `Editor/CustomBuildScript.cs` of the sample. This custom build script creates a build that only includes the currently open scene. A bootstrap scene is automatically created and a script is added that loads the built scene on startup.

For these examples, the build and load paths used by default are `[UnityEngine.AddressableAssets.Addressables.BuildPath]/[BuildTarget]` and `{UnityEngine.AddressableAssets.Addressables.RuntimePath}/[BuildTarget]` respectively.

The `ScriptableObject` of the class has already been created, but you can use the Create menu to make another `ScriptableObject`. For this `CustomPlayModeScript` the create menu path is **Addressables > Content Builders > Use CustomPlayMode Script**. By default, this creates a CustomPlayMode.asset ScriptableObject. The same goes for the `CustomBuildScript`.| -|**Disable Asset Import on Build**|Provides a script that disables asset importing during a player build. This improves build performance because `AssetBundles` are copied into StreamingAssets at build time. This sample is only relevant for Editor versions below 2021.2. In 2021.2+, the Editor provides the ability to include folders outside of `Assets/` into `StreamingAssets`.

When the sample is imported into the project, a player build without asset importing can be triggered by the new menu item **Build/Disabled Importer Build**. The build output is placed into `DisabledImporterBuildPath/{EditorUserBuildSettings.activeBuildTarget}/` by default. The sample class `DisableAssetImportOnBuild` can be edited to alter the build path.| -|**Import Existing Group**|Contains a tool that imports group assets, for example from a custom package, to the current project.

The tool is located under `Window/Asset Management/Addressables/Import Groups`. The window requires a path to the `AddressableAssetGroup.asset` scriptable object, a name for the group, and a folder for any schemas related to the imported `AddressableAssetGroup`.| +--- +uid: samples-overview +--- + +# Addressables samples + +The Addressables package contains samples that you can download into your project. To access the samples go to **Window** > **Package Manager** > **Addressables**. + +These samples include examples on how to disable asset importing during a build, creating custom build and Play mode scripts, and providing an `AddressableUtility` class. + +When you download and import a sample, it's placed inside the `Assets/Samples/Addressables/{AddressablesVersionNumber}` path of your project. + +|**Sample**|**Description**| +|---|---| +|**Addressables Utility**|Contains a set of utility functions for Addressables. The script contains a static method `GetAddressFromAssetReference` which provides the Addressable address used to reference a given `AssetRefence` internally.| +|**ComponentReference**|Creates an AssetReference that's restricted to having a specific component. For more information see the ComponentReference sample project located in the [Addressables Samples](https://github.com/Unity-Technologies/Addressables-Sample) repository.| +|**Custom Build and Playmode Scripts**|Includes two [custom scripts](xref:addressables-api-build-player-content):

- A custom Play mode script located in `Editor/CustomPlayModeScript.cs` of the sample. This script works similarly to the Use Existing Build (requires built groups) play mode script already included. The methods added to accomplish this are `CreateCurrentSceneOnlyBuildSetup` and `RevertCurrentSceneSetup` on the `CustomBuildScript`.
- A custom build script located in `Editor/CustomBuildScript.cs` of the sample. This custom build script creates a build that only includes the currently open scene. A bootstrap scene is automatically created and a script is added that loads the built scene on startup.

For these examples, the build and load paths used by default are `[UnityEngine.AddressableAssets.Addressables.BuildPath]/[BuildTarget]` and `{UnityEngine.AddressableAssets.Addressables.RuntimePath}/[BuildTarget]` respectively.

The `ScriptableObject` of the class has already been created, but you can use the Create menu to make another `ScriptableObject`. For this `CustomPlayModeScript` the create menu path is **Addressables > Content Builders > Use CustomPlayMode Script**. By default, this creates a CustomPlayMode.asset ScriptableObject. The same goes for the `CustomBuildScript`.| +|**Disable Asset Import on Build**|Provides a script that disables asset importing during a player build. This improves build performance because `AssetBundles` are copied into StreamingAssets at build time. This sample is only relevant for Editor versions below 2021.2. In 2021.2+, the Editor provides the ability to include folders outside of `Assets/` into `StreamingAssets`.

When the sample is imported into the project, a player build without asset importing can be triggered by the new menu item **Build/Disabled Importer Build**. The build output is placed into `DisabledImporterBuildPath/{EditorUserBuildSettings.activeBuildTarget}/` by default. The sample class `DisableAssetImportOnBuild` can be edited to alter the build path.| +|**Import Existing Group**|Contains a tool that imports group assets, for example from a custom package, to the current project.

The tool is located under `Window/Asset Management/Addressables/Import Groups`. The window requires a path to the `AddressableAssetGroup.asset` scriptable object, a name for the group, and a folder for any schemas related to the imported `AddressableAssetGroup`.| |**Prefab Spawner**|Provides a basic script that instantiates and destroys a prefab `AssetReference`. To use the sample, attach the provided script, `PrefabSpawnerSample`, to a `GameObject` in your scene. Assign an `AdressableAsset` to the `AssetReference` field of that script. If you're using the `Use Existing Build` playmode script, ensure that your Addressable content is built. Then, enter Play mode.| \ No newline at end of file diff --git a/Documentation~/SynchronousAddressables.md b/Documentation~/SynchronousAddressables.md index f822d762..eb74f64a 100644 --- a/Documentation~/SynchronousAddressables.md +++ b/Documentation~/SynchronousAddressables.md @@ -1,73 +1,77 @@ ---- -uid: synchronous-addressables ---- - -## Synchronous loading - -Synchronous Addressables APIs help to mirror Unity asset loading workflows. `AsyncOperationHandles` have a method called `WaitForCompletion()` that forces the [asynchronous operation](AddressableAssetsAsyncOperationHandle.md) to complete and return the `Result` of the operation. - -The result of `WaitForCompletion` is the `Result` of the asynchronous operation it's called on. If the operation fails, this returns `default(TObject)`. - -You can get a `default(TObject)` for a result when the operation doesn't fail. Asynchronous operations that auto release their `AsyncOperationHandle` instances on completion are such cases. `Addressables.InitializeAsync` and any API with a `autoReleaseHandle` parameter set to true return `default(TObject)` even if the operations succeeded. - -## Performance considerations - -Calling `WaitForCompletion` might have performance implications on your runtime when compared to `Resources.Load` or `Instantiate` calls directly. If the `AssetBundle` is local or has been downloaded before and cached, these performance hits are small. - -All active asset load operations are completed when `WaitForCompletion` is called on any asset load operation, because of how Unity handles asynchronous operations. To avoid unexpected stalls, use `WaitForCompletion` when you known the current operation count, and the you want all active operations to complete synchronously. - -Don't call `WaitForCompletion` on an operation that's going to fetch and download a remote `AssetBundle`. - -## Synchronous loading example - -```c# -void Start() -{ - //Basic use case of forcing a synchronous load of a GameObject - var op = Addressables.LoadAssetAsync("myGameObjectKey"); - GameObject go = op.WaitForCompletion(); - - //Do work... - - Addressables.Release(op); -} -``` - -## Scene limitations - -Unity can't complete scene loading synchronously. Calling `WaitForCompletion` on an operation returned from [`Addressables.LoadSceneAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadSceneAsync*) doesn't completely load the scene, even if `activateOnLoad `is set to `true`. It waits for dependencies and assets to complete but the scene activation must be done asynchronously. - -This can be done using the `sceneHandle`, or by the [`AsyncOperation`](xref:UnityEngine.AsyncOperation) from `ActivateAsync` on the `SceneInstance`: - -```c# -IEnumerator LoadScene(string myScene) -{ - var sceneHandle = Addressables.LoadSceneAsync(myScene, LoadSceneMode.Additive); - SceneInstance sceneInstance = sceneHandle.WaitForCompletion(); - yield return sceneInstance.ActivateAsync(); - - //Do work... the scene is now complete and integrated -} -``` - -Unity can't unload a scene synchronously. Calling `WaitForCompleted` on a scene unload doesn't unload the scene or any assets, and a warning is logged to the Console. - -Because of limitations with scene integration on the main thread through the `SceneManager` API, you can lock the Unity Editor or Player when calling `WaitForCompletion` to load scenes. This issue happens when loading two scenes in succession, with the second scene load request having `WaitForCompletion` called from its `AsyncOperationHandle`. - -Scene loading takes extra frames to fully integrate on the main thread, and `WaitForCompletion` locks the main thread, so you might have a situation where Addressables has been informed by the `SceneManager` that the first scene is fully loaded, even though it hasn't finished all operations. At this point, the scene is fully loaded, but the `SceneManager` attempts to call `UnloadUnusedAssets`, on the main thread, if the scene was loaded in `Single` mode. Then, the second scene load request locks the main thread with `WaitForCompletion`, but can't begin loading because `SceneManager` requires the `UnloadUnusedAssets` to complete before the next scene can begin loading. - -To avoid this deadlock, either load successive scenes asynchronously, or add a delay between scene load requests. - -## Custom operations - -Addressables supports custom `AsyncOperation` instances which support unique implementations of `InvokeWaitForCompletion`. This method can be overridden to implement custom synchronous operations. - -Custom operations work with `ChainOperation` and `GroupsOperation` instances. If you want to complete chained operations synchronously, make your custom operations implement `InvokeWaitForCompletion` and create a `ChainOperation` using your custom operations. Similarly, `GroupOperations` are well suited to make a collection of `AsyncOperations`, including custom operations, complete together. - -Both `ChainOperation` and `GroupOperation` have their own implementations of `InvokeWaitForCompletion` that relies on the `InvokeWaitForCompletion` implementations of the operations they depend on. - -## WebGL support - -WebGL doesn't support `WaitForCompletion`. On WebGL, a web request loads all files. On other platforms, a web request gets started on a background thread and the main thread spins in a tight loop while waiting for the web request to finish. This is how Addressables does it for `WaitForCompletion` when a web request is used. - -Because WebGL is single-threaded, the tight loop blocks the web request and the operation is never allowed to finish. If a web request finishes the same frame it was created, then `WaitForCompletion` wouldn't have any issue. However, this isn't guaranteed. +--- +uid: synchronous-addressables +--- + +## Synchronous loading + +Synchronous Addressables APIs help to mirror Unity asset loading workflows. `AsyncOperationHandles` have a method called `WaitForCompletion()` that forces the [asynchronous operation](AddressableAssetsAsyncOperationHandle.md) to complete and return the `Result` of the operation. + +The result of `WaitForCompletion` is the `Result` of the asynchronous operation it's called on. If the operation fails, this returns `default(TObject)`. + +You can get a `default(TObject)` for a result when the operation doesn't fail. Asynchronous operations that auto release their `AsyncOperationHandle` instances on completion are such cases. `Addressables.InitializeAsync` and any API with a `autoReleaseHandle` parameter set to true return `default(TObject)` even if the operations succeeded. + +## Performance considerations + +Calling `WaitForCompletion` might have performance implications on your runtime when compared to `Resources.Load` or `Instantiate` calls directly. If the `AssetBundle` is local or has been downloaded before and cached, these performance hits are small. + +All active asset load operations are completed when `WaitForCompletion` is called on any asset load operation, because of how Unity handles asynchronous operations. To avoid unexpected stalls, use `WaitForCompletion` when you known the current operation count, and the you want all active operations to complete synchronously. + +Don't call `WaitForCompletion` on an operation that's going to fetch and download a remote `AssetBundle`. + +## Synchronous loading example + +```c# +void Start() +{ + //Basic use case of forcing a synchronous load of a GameObject + var op = Addressables.LoadAssetAsync("myGameObjectKey"); + GameObject go = op.WaitForCompletion(); + + //Do work... + + Addressables.Release(op); +} +``` + +## Deadlocks caused by scene limitations + +Unity can't complete scene loading synchronously. Calling `WaitForCompletion` on an operation returned from [`Addressables.LoadSceneAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadSceneAsync*) doesn't completely load the scene, even if `activateOnLoad `is set to `true`. It waits for dependencies and assets to complete but the scene activation must be done asynchronously. + +This can be done using the `sceneHandle`, or by the [`AsyncOperation`](xref:UnityEngine.AsyncOperation) from `ActivateAsync` on the `SceneInstance`: + +```c# +IEnumerator LoadScene(string myScene) +{ + var sceneHandle = Addressables.LoadSceneAsync(myScene, LoadSceneMode.Additive); + SceneInstance sceneInstance = sceneHandle.WaitForCompletion(); + yield return sceneInstance.ActivateAsync(); + + //Do work... the scene is now complete and integrated +} +``` + +Unity can't unload a scene synchronously. Calling `WaitForCompleted` on a scene unload doesn't unload the scene or any assets, and a warning is logged to the Console. + +Because of limitations with scene integration on the main thread through the `SceneManager` API, you can lock the Unity Editor or Player when calling `WaitForCompletion` to load scenes. This issue happens when loading two scenes in succession, with the second scene load request having `WaitForCompletion` called from its `AsyncOperationHandle`. + +Scene loading takes extra frames to fully integrate on the main thread, and `WaitForCompletion` locks the main thread, so you might have a situation where Addressables has been informed by the `SceneManager` that the first scene is fully loaded, even though it hasn't finished all operations. At this point, the scene is fully loaded, but the `SceneManager` attempts to call `UnloadUnusedAssets`, on the main thread, if the scene was loaded in `Single` mode. Then, the second scene load request locks the main thread with `WaitForCompletion`, but can't begin loading because `SceneManager` requires the `UnloadUnusedAssets` to complete before the next scene can begin loading. + +To avoid this deadlock, either load successive scenes asynchronously, or add a delay between scene load requests. + +Another issue is calling `WaitForCompletion` on an asynchronous operation during `Awake` when a scene is not yet fully loaded. This can block the main thread and prevent other asynchronous operations (i.e. unloading a bundle) in progress from completing. To avoid this deadlock, call `WaitForCompletion` during `Start` instead. + +Note that Addressables has a callback registered to [`SceneManager.sceneUnloaded`](xref:UnityEngine.SceneManagement.SceneManager.sceneUnloaded(UnityEngine.Events.UnityAction`1)) that will release any unloaded addressable scenes. This can trigger scene bundle unloading if no other scenes from the bundle are loaded. + +## Custom operations + +Addressables supports custom `AsyncOperation` instances which support unique implementations of `InvokeWaitForCompletion`. This method can be overridden to implement custom synchronous operations. + +Custom operations work with `ChainOperation` and `GroupsOperation` instances. If you want to complete chained operations synchronously, make your custom operations implement `InvokeWaitForCompletion` and create a `ChainOperation` using your custom operations. Similarly, `GroupOperations` are well suited to make a collection of `AsyncOperations`, including custom operations, complete together. + +Both `ChainOperation` and `GroupOperation` have their own implementations of `InvokeWaitForCompletion` that relies on the `InvokeWaitForCompletion` implementations of the operations they depend on. + +## WebGL support + +WebGL doesn't support `WaitForCompletion`. On WebGL, a web request loads all files. On other platforms, a web request gets started on a background thread and the main thread spins in a tight loop while waiting for the web request to finish. This is how Addressables does it for `WaitForCompletion` when a web request is used. + +Because WebGL is single-threaded, the tight loop blocks the web request and the operation is never allowed to finish. If a web request finishes the same frame it was created, then `WaitForCompletion` wouldn't have any issue. However, this isn't guaranteed. diff --git a/Documentation~/TableOfContents.md b/Documentation~/TableOfContents.md index 338f1dd5..e96e2e73 100644 --- a/Documentation~/TableOfContents.md +++ b/Documentation~/TableOfContents.md @@ -1,99 +1,99 @@ -* [Addressables package](index.md) -* [Get started](AddressableAssetsGettingStarted.md) - * [Addressables overview](AddressableAssetsOverview.md) - * [Install Addressables](installation-guide.md) - * [Convert an existing project to use Addressables](convert-project-to-addressables.md) - * [Convert scene data](convert-scene-data.md) - * [Convert prefabs](convert-prefabs.md) - * [Convert assets in the Resources folder ](convert-resources-folder.md) - * [Convert AssetBundles](convert-asset-bundles.md) - * [Make an asset Addressable](get-started-make-addressable.md) - * [Addressables samples](SamplesOverview.md) -* [Manage Addressables](AddressableAssetsDevelopmentCycle.md) - * [Manage Addressables introduction](manage-addressables-intro.md) - * [Organize Addressable assets](organize-addressable-assets.md) - * [Groups overview](Groups.md) - * [Groups introduction](groups-intro.md) - * [Manage and create groups](groups-create.md) - * [Labels overview](Labels.md) - * [Create a group template](GroupTemplates.md) - * [Pack groups into AssetBundles](PackingGroupsAsBundles.md) - * [Addressables Groups window reference](GroupsWindow.md) - * [Group settings and schemas overview](GroupSchemas.md) - * [Content Packing & Loading schema reference](ContentPackingAndLoadingSchema.md) - * [Content Update Restriction schema reference](UpdateRestrictionSchema.md) - * [Profiles overview](AddressableAssetsProfiles.md) - * [Profiles introduction](profiles-introduction.md) - * [Create a profile](profiles-create.md) - * [Profile variables overview](ProfileVariables.md) - * [Set a build and load path](profiles-build-load-paths.md) - * [Addressables Profiles window reference](addressables-profiles-window.md) - * [Asset references overview](AssetReferences.md) - * [Asset references introduction](asset-reference-intro.md) - * [Create an AssetReference](asset-reference-create.md) - * [Load an AssetReference](LoadingAssetReferences.md) - * [Addressables Asset Settings reference](AddressableAssetSettings.md) - * [Addressables Preferences reference](addressables-preferences.md) -* [Build content](Builds.md) - * [Build content introduction](build-intro.md) - * [Build Addressables content with Player builds](build-player-builds.md) - * [Asset dependencies overview](AssetDependencies.md) - * [Create a build](BuildingContent.md) - * [Create a full build](builds-full-build.md) - * [Create an update build](builds-update-build.md) - * [Build scripting](BuildPlayerContent.md) - * [Start a build from a script](build-scripting-start-build.md) - * [Custom build scripting](build-scripting-custom.md) - * [Build while recompiling](build-scripting-recompiling.md) - * [Build sprite atlases](AddressablesAndSpriteAtlases.md) - * [Build shaders](BuildingShaders.md) - * [Build artifacts](BuildArtifacts.md) - * [Artifacts in the player](build-artifacts-included.md) - * [Content catalogs](build-content-catalogs.md) - * [Shared AssetBundles](build-shared-assetbundles.md) - * [Content update builds](ContentUpdateWorkflow.md) - * [Content update builds overview](content-update-builds-overview.md) - * [Build a content update](content-update-build-create.md) - * [Check for content updates at runtime](content-update-builds-check.md) - * [Content update examples](content-update-examples.md) - * [Content update build settings](content-update-build-settings.md) - * [Use continuous integration to build Addressables](ContinuousIntegration.md) -* [Distribute remote content](RemoteContentDistribution.md) - * [Distribute remote content overview](remote-content-intro.md) - * [Enable remote content](remote-content-enable.md) - * [Remote content profiles](remote-content-profiles.md) - * [Remote content AssetBundle caching](remote-content-assetbundle-cache.md) - * [Pre-download remote content](remote-content-predownload.md) - * [Use Addressables with Cloud Content Delivery](AddressablesCCD.md) -* [Use Addressables at runtime](RuntimeAddressables.md) - * [Use Addressables introduction](use-addresssables-introduction.md) - * [Addressables initialization](InitializeAsync.md) - * [Memory management overview](MemoryManagement.md) - * [AssetBundle memory overhead](memory-assetbundles.md) - * [Manage catalogs at runtime](LoadContentCatalogAsync.md) - * [Get addresses at runtime](GetRuntimeAddress.md) - * [Modification events](ModificationEvents.md) -* [Load Addressable assets](LoadingAddressableAssets.md) - * [Load Addressable assets introduction](load-addressable-assets.md) - * [Asynchronous loading](load-assets-asynchronous.md) - * [Asynchronous operation handles](AddressableAssetsAsyncOperationHandle.md) - * [Synchronous loading](SynchronousAddressables.md) - * [Load assets](load-assets.md) - * [Load assets by location](load-assets-location.md) - * [Load a scene](LoadingScenes.md) - * [Load AssetBundles](LoadingAssetBundles.md) - * [Safely edit loaded assets](safely-edit-loaded-asset.md) - * [Unload Addressable assets](UnloadingAddressableAssets.md) - * [Change resource URLs](TransformInternalId.md) - * [Preload dependencies](DownloadDependenciesAsync.md) - * [Load content from multiple projects](MultiProject.md) -* [Diagnostic tools](DiagnosticTools.md) - * [Addressables Profiler module](ProfilerModule.md) - * [Analyze tool](AnalyzeTool.md) - * [Build layout report](BuildLayoutReport.md) - * [Build profile log](BuildProfileLog.md) - * [Addressables Report](addressables-report.md) - * [Summary tab](AddressablesReportSummaryTab.md) - * [Explore tab](AddressablesReportExploreTab.md) - * [Potential Issues tab](AddressablesReportPotentialIssuesTab.md) - * [Inspector reference](addressables-report-inspector.md) +* [Addressables package](index.md) +* [Get started](AddressableAssetsGettingStarted.md) + * [Addressables overview](AddressableAssetsOverview.md) + * [Install Addressables](installation-guide.md) + * [Convert an existing project to use Addressables](convert-project-to-addressables.md) + * [Convert scene data](convert-scene-data.md) + * [Convert prefabs](convert-prefabs.md) + * [Convert assets in the Resources folder ](convert-resources-folder.md) + * [Convert AssetBundles](convert-asset-bundles.md) + * [Make an asset Addressable](get-started-make-addressable.md) + * [Addressables samples](SamplesOverview.md) +* [Manage Addressables](AddressableAssetsDevelopmentCycle.md) + * [Manage Addressables introduction](manage-addressables-intro.md) + * [Organize Addressable assets](organize-addressable-assets.md) + * [Groups overview](Groups.md) + * [Groups introduction](groups-intro.md) + * [Manage and create groups](groups-create.md) + * [Labels overview](Labels.md) + * [Create a group template](GroupTemplates.md) + * [Pack groups into AssetBundles](PackingGroupsAsBundles.md) + * [Addressables Groups window reference](GroupsWindow.md) + * [Group settings and schemas overview](GroupSchemas.md) + * [Content Packing & Loading schema reference](ContentPackingAndLoadingSchema.md) + * [Content Update Restriction schema reference](UpdateRestrictionSchema.md) + * [Profiles overview](AddressableAssetsProfiles.md) + * [Profiles introduction](profiles-introduction.md) + * [Create a profile](profiles-create.md) + * [Profile variables overview](ProfileVariables.md) + * [Set a build and load path](profiles-build-load-paths.md) + * [Addressables Profiles window reference](addressables-profiles-window.md) + * [Asset references overview](AssetReferences.md) + * [Asset references introduction](asset-reference-intro.md) + * [Create an AssetReference](asset-reference-create.md) + * [Load an AssetReference](LoadingAssetReferences.md) + * [Addressables Asset Settings reference](AddressableAssetSettings.md) + * [Addressables Preferences reference](addressables-preferences.md) +* [Build content](Builds.md) + * [Build content introduction](build-intro.md) + * [Build Addressables content with Player builds](build-player-builds.md) + * [Asset dependencies overview](AssetDependencies.md) + * [Create a build](BuildingContent.md) + * [Create a full build](builds-full-build.md) + * [Create an update build](builds-update-build.md) + * [Build scripting](BuildPlayerContent.md) + * [Start a build from a script](build-scripting-start-build.md) + * [Custom build scripting](build-scripting-custom.md) + * [Build while recompiling](build-scripting-recompiling.md) + * [Build sprite atlases](AddressablesAndSpriteAtlases.md) + * [Build shaders](BuildingShaders.md) + * [Build artifacts](BuildArtifacts.md) + * [Artifacts in the player](build-artifacts-included.md) + * [Content catalogs](build-content-catalogs.md) + * [Shared AssetBundles](build-shared-assetbundles.md) + * [Content update builds](ContentUpdateWorkflow.md) + * [Content update builds overview](content-update-builds-overview.md) + * [Build a content update](content-update-build-create.md) + * [Check for content updates at runtime](content-update-builds-check.md) + * [Content update examples](content-update-examples.md) + * [Content update build settings](content-update-build-settings.md) + * [Use continuous integration to build Addressables](ContinuousIntegration.md) +* [Distribute remote content](RemoteContentDistribution.md) + * [Distribute remote content overview](remote-content-intro.md) + * [Enable remote content](remote-content-enable.md) + * [Remote content profiles](remote-content-profiles.md) + * [Remote content AssetBundle caching](remote-content-assetbundle-cache.md) + * [Pre-download remote content](remote-content-predownload.md) + * [Use Addressables with Cloud Content Delivery](AddressablesCCD.md) +* [Use Addressables at runtime](RuntimeAddressables.md) + * [Use Addressables introduction](use-addresssables-introduction.md) + * [Addressables initialization](InitializeAsync.md) + * [Memory management overview](MemoryManagement.md) + * [AssetBundle memory overhead](memory-assetbundles.md) + * [Manage catalogs at runtime](LoadContentCatalogAsync.md) + * [Get addresses at runtime](GetRuntimeAddress.md) + * [Modification events](ModificationEvents.md) +* [Load Addressable assets](LoadingAddressableAssets.md) + * [Load Addressable assets introduction](load-addressable-assets.md) + * [Asynchronous loading](load-assets-asynchronous.md) + * [Asynchronous operation handles](AddressableAssetsAsyncOperationHandle.md) + * [Synchronous loading](SynchronousAddressables.md) + * [Load assets](load-assets.md) + * [Load assets by location](load-assets-location.md) + * [Load a scene](LoadingScenes.md) + * [Load AssetBundles](LoadingAssetBundles.md) + * [Safely edit loaded assets](safely-edit-loaded-asset.md) + * [Unload Addressable assets](UnloadingAddressableAssets.md) + * [Change resource URLs](TransformInternalId.md) + * [Preload dependencies](DownloadDependenciesAsync.md) + * [Load content from multiple projects](MultiProject.md) +* [Diagnostic tools](DiagnosticTools.md) + * [Addressables Profiler module](ProfilerModule.md) + * [Analyze tool](AnalyzeTool.md) + * [Build layout report](BuildLayoutReport.md) + * [Build profile log](BuildProfileLog.md) + * [Addressables Report](addressables-report.md) + * [Summary tab](AddressablesReportSummaryTab.md) + * [Explore tab](AddressablesReportExploreTab.md) + * [Potential Issues tab](AddressablesReportPotentialIssuesTab.md) + * [Inspector reference](addressables-report-inspector.md) diff --git a/Documentation~/TransformInternalId.md b/Documentation~/TransformInternalId.md index f9bcf411..c7c204e4 100644 --- a/Documentation~/TransformInternalId.md +++ b/Documentation~/TransformInternalId.md @@ -1,39 +1,39 @@ ---- -uid: addressables-api-transform-internal-id ---- - -# Change resource URLs - -You can modify the URLs that Addressables uses to load assets at runtime in the following ways: - -* [Static properties in a Profile variable](#static-profile-variables) -* [Implement an ID transform method](#id-transform-method) -* [Implement a WebRequestOverride method](#webrequest-override) - -## Static Profile variables - -When you define the [RemoteLoadPath Profile variable](xref:addressables-profiles) you can use a static property to specify all or part of the URL that your application loads remote content from, including catalogs, catalog hash files, and AssetBundles. Refer to [Profile variable syntax](xref:addressables-profile-variables) for information about specifying a property name in a Profile variable. - -The value of the static property must be set before Addressables initializes. Changing the value after initialization has no effect. - -## ID transform method - -You can assign a method to the [`Addressables.ResourceManager`](xref:UnityEngine.AddressableAssets.Addressables.ResourceManager) object's [`InternalIdTransformFunc`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation.InternalId) property to individually change the URLs that Addressables loads assets from. You must assign the method before the relevant operation starts, otherwise the default URL is used. - -Using `TransformInternalId` is useful for remote hosting. Given a single `IResourceLocation`, you can transform the ID to point towards a server specified at runtime. This is useful if the server IP address changes or if you use different URLs to give different variants of application assets. - -`ResourceManager` calls the `TransformInternalId` method when it looks up an asset, passing the [`IResourceLocation`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation) instance for the asset to your method. You can change the [`InternalId`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation.InternalId) property of the `IResourceLocation` and return the modified object to the `ResourceManager`. - -The following example illustrates how you can append a query string to all URLs for AssetBundles: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/IDTransformer.cs#doc_Transformer)] - -## WebRequest override - -You can assign a method to the `Addressable` object's [`WebRequestOverride`](xref:UnityEngine.AddressableAssets.Addressables.WebRequestOverride) property to individually change the [`UnityWebRequest`](xref:UnityEngine.Networking.UnityWebRequest) used to download files, such as an AssetBundle or catalog .json file. You must assign the method before the relevant operation starts, otherwise the default `UnityWebRequest` is used. - -The `ResourceManager` calls `WebRequestOverride` before [`UnityWebRequest.SendWebRequest`](xref:UnityEngine.Networking.UnityWebRequest.SendWebRequest) is called and passes the UnityWebRequest for the download to your method. - -The following example shows how you can append a query string to all URLs for AssetBundles and catalogs: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/WebRequestOverride.cs#doc_TransformerWebRequest)] +--- +uid: addressables-api-transform-internal-id +--- + +# Change resource URLs + +You can modify the URLs that Addressables uses to load assets at runtime in the following ways: + +* [Static properties in a Profile variable](#static-profile-variables) +* [Implement an ID transform method](#id-transform-method) +* [Implement a WebRequestOverride method](#webrequest-override) + +## Static Profile variables + +When you define the [RemoteLoadPath Profile variable](xref:addressables-profiles) you can use a static property to specify all or part of the URL that your application loads remote content from, including catalogs, catalog hash files, and AssetBundles. Refer to [Profile variable syntax](xref:addressables-profile-variables) for information about specifying a property name in a Profile variable. + +The value of the static property must be set before Addressables initializes. Changing the value after initialization has no effect. + +## ID transform method + +You can assign a method to the [`Addressables.ResourceManager`](xref:UnityEngine.AddressableAssets.Addressables.ResourceManager) object's [`InternalIdTransformFunc`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation.InternalId) property to individually change the URLs that Addressables loads assets from. You must assign the method before the relevant operation starts, otherwise the default URL is used. + +Using `TransformInternalId` is useful for remote hosting. Given a single `IResourceLocation`, you can transform the ID to point towards a server specified at runtime. This is useful if the server IP address changes or if you use different URLs to give different variants of application assets. + +`ResourceManager` calls the `TransformInternalId` method when it looks up an asset, passing the [`IResourceLocation`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation) instance for the asset to your method. You can change the [`InternalId`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation.InternalId) property of the `IResourceLocation` and return the modified object to the `ResourceManager`. + +The following example illustrates how you can append a query string to all URLs for AssetBundles: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/IDTransformer.cs#doc_Transformer)] + +## WebRequest override + +You can assign a method to the `Addressable` object's [`WebRequestOverride`](xref:UnityEngine.AddressableAssets.Addressables.WebRequestOverride) property to individually change the [`UnityWebRequest`](xref:UnityEngine.Networking.UnityWebRequest) used to download files, such as an AssetBundle or catalog .json file. You must assign the method before the relevant operation starts, otherwise the default `UnityWebRequest` is used. + +The `ResourceManager` calls `WebRequestOverride` before [`UnityWebRequest.SendWebRequest`](xref:UnityEngine.Networking.UnityWebRequest.SendWebRequest) is called and passes the UnityWebRequest for the download to your method. + +The following example shows how you can append a query string to all URLs for AssetBundles and catalogs: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/WebRequestOverride.cs#doc_TransformerWebRequest)] diff --git a/Documentation~/UnloadingAddressableAssets.md b/Documentation~/UnloadingAddressableAssets.md index f8252d6b..4c97fd9e 100644 --- a/Documentation~/UnloadingAddressableAssets.md +++ b/Documentation~/UnloadingAddressableAssets.md @@ -1,16 +1,16 @@ ---- -uid: addressables-unloading ---- - -# Unload Addressable assets - -The Addressables system uses reference counting to check whether an asset is in use. This means that you must release every asset that you load or instantiate when you're finished with it. Refer to [Memory Management](MemoryManagement.md) for more information. - -When you unload a scene, the AssetBundle it belongs to is unloaded. This unloads assets associated with the scene, including any GameObjects moved from the original scene to a different scene. - -Unity automatically calls `UnloadUnusedAssets` when it loads a scene using the [`LoadSceneMode.Single`](xref:UnityEngine.SceneManagement.LoadSceneMode.Single) mode. To prevent the scene and its assets from being unloaded, keep a reference to the scene load operation handle until you want to unload the scene manually. To do this, use [`ResourceManager.Acquire`](xref:UnityEngine.ResourceManagement.ResourceManager.Acquire(UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle)) on the load operation handle. - ->[!IMPORTANT] ->Conventional methods of preserving the assets such as [`Object.DontDestroyOnLoad`](xref:UnityEngine.Object.DontDestroyOnLoad(UnityEngine.Object)) or [`HideFlags.DontUnloadUnusedAsset`](xref:UnityEngine.HideFlags.DontUnloadUnusedAsset) don't work. - -Individual Addressables and their operation handles that you load separately from the scene aren't released. You must call [`Resources.UnloadUnusedAssets`](xref:UnityEngine.Resources.UnloadUnusedAssets) or [`UnloadAsset`](xref:UnityEngine.Resources.UnloadAsset(UnityEngine.Object)) to free these assets. The exception to this is that any Addressable assets that you instantiate using [`Addressables.InstantiateAsync`](xref:UnityEngine.AddressableAssets.Addressables.InstantiateAsync*) with `trackHandle` set to true, the default, are automatically released. +--- +uid: addressables-unloading +--- + +# Unload Addressable assets + +The Addressables system uses reference counting to check whether an asset is in use. This means that you must release every asset that you load or instantiate when you're finished with it. Refer to [Memory Management](MemoryManagement.md) for more information. + +When you unload a scene, the AssetBundle it belongs to is unloaded. This unloads assets associated with the scene, including any GameObjects moved from the original scene to a different scene. + +Unity automatically calls `UnloadUnusedAssets` when it loads a scene using the [`LoadSceneMode.Single`](xref:UnityEngine.SceneManagement.LoadSceneMode.Single) mode. To prevent the scene and its assets from being unloaded, keep a reference to the scene load operation handle until you want to unload the scene manually. To do this, use [`ResourceManager.Acquire`](xref:UnityEngine.ResourceManagement.ResourceManager.Acquire(UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle)) on the load operation handle. + +>[!IMPORTANT] +>Conventional methods of preserving the assets such as [`Object.DontDestroyOnLoad`](xref:UnityEngine.Object.DontDestroyOnLoad(UnityEngine.Object)) or [`HideFlags.DontUnloadUnusedAsset`](xref:UnityEngine.HideFlags.DontUnloadUnusedAsset) don't work. + +Individual Addressables and their operation handles that you load separately from the scene aren't released. You must call [`Resources.UnloadUnusedAssets`](xref:UnityEngine.Resources.UnloadUnusedAssets) or [`UnloadAsset`](xref:UnityEngine.Resources.UnloadAsset(UnityEngine.Object)) to free these assets. The exception to this is that any Addressable assets that you instantiate using [`Addressables.InstantiateAsync`](xref:UnityEngine.AddressableAssets.Addressables.InstantiateAsync*) with `trackHandle` set to true, the default, are automatically released. diff --git a/Documentation~/UpdateRestrictionSchema.md b/Documentation~/UpdateRestrictionSchema.md index 88e8faee..a3720dd6 100644 --- a/Documentation~/UpdateRestrictionSchema.md +++ b/Documentation~/UpdateRestrictionSchema.md @@ -1,14 +1,14 @@ ---- -uid: addressables-update-restriction-schema ---- - -# Content Update Restriction schema reference - -The Content Update Restriction schema determine how the [Check for Content Update Restrictions](xref:addressables-content-update-builds) tool treats assets in the group. To prepare your groups for a differential content update build rather than a full content build, on the [Addressables Groups window](xref:addressables-groups-window), go to **Tools** and run the **Check for Content Update Restrictions** command. The tool moves modified assets in any groups with the __Prevent Updates__ property enabled, to a new group. - -The **Prevent Updates** property acts in the following way: - -* **Enabled**: The tool doesn't move any assets. When you make the update build, if any assets in the bundle have changed, then the entire bundle is rebuilt. -* **Disabled**: If any assets in the bundle have changed, then the [Check for Content Update Restrictions](xref:addressables-content-update-builds) tool moves them to a new group created for the update. When you make the update build, the assets in the AssetBundles created from this new group override the versions found in the existing bundles. - -See [Content update builds](xref:addressables-content-update-builds) for more information. +--- +uid: addressables-update-restriction-schema +--- + +# Content Update Restriction schema reference + +The Content Update Restriction schema determine how the [Check for Content Update Restrictions](xref:addressables-content-update-builds) tool treats assets in the group. To prepare your groups for a differential content update build rather than a full content build, on the [Addressables Groups window](xref:addressables-groups-window), go to **Tools** and run the **Check for Content Update Restrictions** command. The tool moves modified assets in any groups with the __Prevent Updates__ property enabled, to a new group. + +The **Prevent Updates** property acts in the following way: + +* **Enabled**: The tool doesn't move any assets. When you make the update build, if any assets in the bundle have changed, then the entire bundle is rebuilt. +* **Disabled**: If any assets in the bundle have changed, then the [Check for Content Update Restrictions](xref:addressables-content-update-builds) tool moves them to a new group created for the update. When you make the update build, the assets in the AssetBundles created from this new group override the versions found in the existing bundles. + +See [Content update builds](xref:addressables-content-update-builds) for more information. diff --git a/Documentation~/addressables-preferences.md b/Documentation~/addressables-preferences.md index d94e3b8c..42b4a89a 100644 --- a/Documentation~/addressables-preferences.md +++ b/Documentation~/addressables-preferences.md @@ -1,12 +1,12 @@ -# Addressables preferences reference - -The Addressables package adds its own section to the Unity Editor [Preferences](xref:Preferences) window (**File > Settings** > **Preferences** > **Addressables**). The Addressables preferences include: - -|**Preference**|**Description**| -|---|---| -|__Debug Build Layout__| Enable this preference to make the build system produce the [build layout report](xref:addressables-build-layout-report). This preference is disabled by default because it increases the time need to create a build. The build report contains a detailed description of each AssetBundle produced by the build. Refer to [Diagnostic tools](DiagnosticTools.md) for a description of this and other analysis tools.| -|__Build Addressables on Player Build__

Only available in Unity 2021.2+|Choose whether Unity builds Addressables content as part of your Player build.

Building Addressables content together with the Player can be convenient, but increases build time. This effect is greater on large projects because Unity also rebuilds Addressables content that hasn't had any assets modified. If you don't change your Addressables content between most builds, then set this propert to __Do not Build Addressables content on Player Build__.

The options include:

- __Build Addressables content on Player Build__: Always build Addressables content when building the Player.
- __Do not Build Addressables content on Player Build__: Never build Addressables content when building the Player. If you change any Addressables content, you must rebuild it manually before building the Player.

These preferences override the global preference for the current project and affect all contributors who build the project.| - -## Additional resources - +# Addressables preferences reference + +The Addressables package adds its own section to the Unity Editor [Preferences](xref:Preferences) window (**File > Settings** > **Preferences** > **Addressables**). The Addressables preferences include: + +|**Preference**|**Description**| +|---|---| +|__Debug Build Layout__| Enable this preference to make the build system produce the [build layout report](xref:addressables-build-layout-report). This preference is disabled by default because it increases the time need to create a build. The build report contains a detailed description of each AssetBundle produced by the build. Refer to [Diagnostic tools](DiagnosticTools.md) for a description of this and other analysis tools.| +|__Build Addressables on Player Build__

Only available in Unity 2021.2+|Choose whether Unity builds Addressables content as part of your Player build.

Building Addressables content together with the Player can be convenient, but increases build time. This effect is greater on large projects because Unity also rebuilds Addressables content that hasn't had any assets modified. If you don't change your Addressables content between most builds, then set this propert to __Do not Build Addressables content on Player Build__.

The options include:

- __Build Addressables content on Player Build__: Always build Addressables content when building the Player.
- __Do not Build Addressables content on Player Build__: Never build Addressables content when building the Player. If you change any Addressables content, you must rebuild it manually before building the Player.

These preferences override the global preference for the current project and affect all contributors who build the project.| + +## Additional resources + * [Building Addressables content with Player builds](build-player-builds.md) \ No newline at end of file diff --git a/Documentation~/addressables-profiles-window.md b/Documentation~/addressables-profiles-window.md index 19b5b22c..b36c8121 100644 --- a/Documentation~/addressables-profiles-window.md +++ b/Documentation~/addressables-profiles-window.md @@ -1,25 +1,25 @@ -# Addressables Profiles window reference - -To manage the profiles in your project, use the [Addressables Profiles window](addressables-profiles-window.md) (menu: __Window > Asset Management > Addressables > Profiles__). - -![](images/addressables-profiles-window.png)
*The __Addressables Profiles__ window displaying the default profile.* - -Right-click a profile name to set it as the active profile, rename the profile, or delete it. - -The following default profile variables are available: - -|**Profile**|**Description**| -|---|---| -| __Local__| Set the variables for local content. You can choose from:

- **Built-In**
- **Cloud Content Delivery**
- **Custom**| -|__Local.BuildPath__

Can only edit if you select **Custom** as the variable| Define where to build the files containing assets you want to install locally with your application. By default, this path is inside your Project Library folder.| -|__Local.LoadPath__

Can only edit if you select **Custom** as the variable| Define where to load assets installed locally with your application. By default, this path is in the StreamingAssets folder. Addressables automatically includes local content built to the default location in StreamingAssets when you build a Player, but not from other locations.| -|__Remote__| Set the variables for remote content. You can choose from:

- **Built-In**
- **Cloud Content Delivery**
- **Custom**| -|__Remote.BuildPath__

Can only edit if you select **Custom** as the variable| Define where to build the files containing assets you plan to distribute remotely.| -|__Remote.LoadPath__

Can only edit if you select **Custom** as the variable| Define the URL from which to download remote content and catalogs.| -|__BuildTarget__| Set the name of the build target, such as Android or StandaloneWindows64.| - -> [!IMPORTANT] -> Usually, you shouldn't need to change the local build or load paths from their default values. If you do, you must manually copy the local build artifacts from your custom build location to the project's [StreamingAssets](xref:SpecialFolders) folder before making a Player build. Changing these paths also precludes building your Addressables as part of the Player build. - -Refer to [Builds](Builds.md) for more information about how Addressables uses profiles during content builds. - +# Addressables Profiles window reference + +To manage the profiles in your project, use the [Addressables Profiles window](addressables-profiles-window.md) (menu: __Window > Asset Management > Addressables > Profiles__). + +![](images/addressables-profiles-window.png)
*The __Addressables Profiles__ window displaying the default profile.* + +Right-click a profile name to set it as the active profile, rename the profile, or delete it. + +The following default profile variables are available: + +|**Profile**|**Description**| +|---|---| +| __Local__| Set the variables for local content. You can choose from:

- **Built-In**
- **Cloud Content Delivery**
- **Custom**| +|__Local.BuildPath__

Can only edit if you select **Custom** as the variable| Define where to build the files containing assets you want to install locally with your application. By default, this path is inside your Project Library folder.| +|__Local.LoadPath__

Can only edit if you select **Custom** as the variable| Define where to load assets installed locally with your application. By default, this path is in the StreamingAssets folder. Addressables automatically includes local content built to the default location in StreamingAssets when you build a Player, but not from other locations.| +|__Remote__| Set the variables for remote content. You can choose from:

- **Built-In**
- **Cloud Content Delivery**
- **Custom**| +|__Remote.BuildPath__

Can only edit if you select **Custom** as the variable| Define where to build the files containing assets you plan to distribute remotely.| +|__Remote.LoadPath__

Can only edit if you select **Custom** as the variable| Define the URL from which to download remote content and catalogs.| +|__BuildTarget__| Set the name of the build target, such as Android or StandaloneWindows64.| + +> [!IMPORTANT] +> Usually, you shouldn't need to change the local build or load paths from their default values. If you do, you must manually copy the local build artifacts from your custom build location to the project's [StreamingAssets](xref:SpecialFolders) folder before making a Player build. Changing these paths also precludes building your Addressables as part of the Player build. + +Refer to [Builds](Builds.md) for more information about how Addressables uses profiles during content builds. + diff --git a/Documentation~/addressables-report-inspector.md b/Documentation~/addressables-report-inspector.md index 4858055e..2378b3dc 100644 --- a/Documentation~/addressables-report-inspector.md +++ b/Documentation~/addressables-report-inspector.md @@ -1,36 +1,36 @@ ---- -uid: addressables-report-inspector-reference ---- - -# Addressables Report Inspector reference - -You can use the Inspector to view in depth information about any given asset or AssetBundle. When you select an asset or AssetBundle in [the Explore tab](AddressablesReportExploreTab.md) or [the Potential Issues tab](AddressablesReportPotentialIssuesTab.md) the Inspector panel displays information about the selected asset or AssetBundle. - -![](images/addressables-report-inspector.png) - -The Inspector panel has the following sections: - -* **Summary panel**: Displays information about an Asset or AssetBundle, such as its file size, its group, and any labels associated with it. Additionally, the summary panel has buttons that you can use to navigate to various places within both the Build Report and the Editor, depending on whether you select an Asset or an AssetBundle. -* **References panel**: Displays the chain of dependencies surrounding a given asset. - -## Summary panel - -Use the buttons in this panel to perform the following operations: - -* **Select in Editor**: Selects the asset in the Unity Editor. -* **Select in Group**: Selects the asset in the Groups view in the Explore window. This navigates to the Groups view if you're not currently in it. -* **Select in Bundle**: Selects the asset in the AssetBundles view in the Explore window. This navigates to the AssetBundles view if you're not currently in it. -* **Search in this view**: Searches the name of the asset in the search bar. - -## References panel - -![](images/addressables-report-inspector-references.png) - -The References panel has the following tabs: - -* **References To**: Contains a list of all the assets and AssetBundles that the selected item depends on. For example, if you have a material that references a shader, then the shader appears in this tab when you select the material in the Explore View. -* **Referenced By**: Contains a list of all the assets and AssetBundles that depend on the selected item. For example, if you have a material that references a shader, then the material that the shader references appears in this tab when you select the shader in the Explore View. - -Select the arrow next to an Asset or AssetBundle in the References panel to cycle through the dependencies of the top level asset. For example, in the image above, `Table` has a reference to the bundle `defaultlocalgroup_assets_all`. Selecting the arrow shows that the asset that generates this dependency is `TableMaterial`, and that the `defaultlocalgroup_assets_all` bundle also contains three other assets that aren't dependencies of `Table`. - -The question mark icon is displayed next to assets that aren't Addressable but are pulled into the bundle by another Addressable asset. Select it to highlight all the assets in the same bundle that reference that asset. +--- +uid: addressables-report-inspector-reference +--- + +# Addressables Report Inspector reference + +You can use the Inspector to view in depth information about any given asset or AssetBundle. When you select an asset or AssetBundle in [the Explore tab](AddressablesReportExploreTab.md) or [the Potential Issues tab](AddressablesReportPotentialIssuesTab.md) the Inspector panel displays information about the selected asset or AssetBundle. + +![](images/addressables-report-inspector.png) + +The Inspector panel has the following sections: + +* **Summary panel**: Displays information about an Asset or AssetBundle, such as its file size, its group, and any labels associated with it. Additionally, the summary panel has buttons that you can use to navigate to various places within both the Build Report and the Editor, depending on whether you select an Asset or an AssetBundle. +* **References panel**: Displays the chain of dependencies surrounding a given asset. + +## Summary panel + +Use the buttons in this panel to perform the following operations: + +* **Select in Editor**: Selects the asset in the Unity Editor. +* **Select in Group**: Selects the asset in the Groups view in the Explore window. This navigates to the Groups view if you're not currently in it. +* **Select in Bundle**: Selects the asset in the AssetBundles view in the Explore window. This navigates to the AssetBundles view if you're not currently in it. +* **Search in this view**: Searches the name of the asset in the search bar. + +## References panel + +![](images/addressables-report-inspector-references.png) + +The References panel has the following tabs: + +* **References To**: Contains a list of all the assets and AssetBundles that the selected item depends on. For example, if you have a material that references a shader, then the shader appears in this tab when you select the material in the Explore View. +* **Referenced By**: Contains a list of all the assets and AssetBundles that depend on the selected item. For example, if you have a material that references a shader, then the material that the shader references appears in this tab when you select the shader in the Explore View. + +Select the arrow next to an Asset or AssetBundle in the References panel to cycle through the dependencies of the top level asset. For example, in the image above, `Table` has a reference to the bundle `defaultlocalgroup_assets_all`. Selecting the arrow shows that the asset that generates this dependency is `TableMaterial`, and that the `defaultlocalgroup_assets_all` bundle also contains three other assets that aren't dependencies of `Table`. + +The question mark icon is displayed next to assets that aren't Addressable but are pulled into the bundle by another Addressable asset. Select it to highlight all the assets in the same bundle that reference that asset. diff --git a/Documentation~/addressables-report-window.md b/Documentation~/addressables-report-window.md index 640ba788..726af341 100644 --- a/Documentation~/addressables-report-window.md +++ b/Documentation~/addressables-report-window.md @@ -1,73 +1,73 @@ ---- - -uid: addressables-report-overview - ---- - -# Addressables Report window reference - -The Addressables Report is a tool that you can use to view information about the content built in an Addressables Build in depth. - -To open the Addressables Report window, go to **Window** > **Asset Management** > **Addressables** and select **Addressables Report**. - -## Prerequisites - -* You must use Unity Editor version 2022.2 or newer. If you want to use the Addressables report, but your current Editor version is below 2022.2, you can use a [build report](BuildLayoutReport.md) built on an earlier version of the Unity Editor and import it into a project uses an Editor version newer than 2022.2, provided that the build report is built on Addressables version 1.21.8 or newer. -* The Addressables Report also requires a [build report](BuildLayoutReport.md) generated by an Addressables build to function. To enable the generation of build reports, go to **Edit** > **Preferences** > **Addressables** and enable the **Debug Build Layout** property. -* By default, the Addressables Report opens automatically after every build. To disable this, go to **Edit** > **Preferences** > **Addressables** and disable **Open Addressables Report After Build** - -## Addressables Report window overview - -![](images/addressables-report-window.png)
_Addressables Report window_ - -The Addressables Report window has the following views: - -| __View__ | __Description__ | -|:---|:---| -| [Summary tab](#summary-tab) | Displays a high level overview of the Addressables build and its contents. | -| [Explore tab](#explore-tab)| Displays a detailed breakdown of all the content built as part of the Addressables build | -| [Potential Issues tab](AddressablesReportPotentialIssuesTab.md)| Scans the current build report for issues that might affect build performance or otherwise be undesirable. | - -Select the tabs along the top of the Addressables Report window to change views. - -The left sidebar panel contains the list of all the build reports currently detected within the project. Select a build report in the side bar to load that report in the Addressables Report window. - -The right sidebar is the [Inspector Panel](addressables-report-inspector.md), which you can use to view detailed information on an asset or AssetBundle while viewing information within the Explore or Potential Issues views. - -Use the search bar in the Build Report window to search within the Explore and Potential Issues tabs. This filters all assets in the current view by the text written in the search bar. - -## Summary tab - -The Summary tab displays information about the selected build report, along with information about any detected potential issues in the build. It includes the following sections: - -* **General Information:** Includes the locations of the catalogs created by the build, which profile the current build was built with, how long the build took, and the version of the Addressables package and the Unity Editor that the build was created with. -* **Potential Issues:** Contains a summary of the issues in the [Potential Issues tab](AddressablesReportPotentialIssuesTab.md) -* **Aggregate Information:** Displays the number of AssetBundles created as part of the build, the size of the bundles built, and the number of assets in the build. The number of assets includes assets that are referenced by an Addressable asset, but aren't marked as Addressable. These assets must be included in the build to allow for assets that depend on them to be loaded. - ->[!NOTE] -> If multiple Addressable assets in different bundles depend on the same non-Addressable asset, then that non-Addressable asset is duplicated in multiple bundles. For more information about duplicated assets, refer to [Duplicated Assets View](AddressablesReportPotentialIssuesTab.md). - -## Explore tab - -The Explore tab has detailed information about the selected build report. Use the **View By** dropdown to change the way that assets are organized in the build report. - -You can sort the Explore View in the following ways: - -|**View**|**Description**| -|---|---| -|**AssetBundles**| Displays all AssetBundles built as part of the Addressables build. Expand an AssetBundle to display the assets that bundle contains. This is the default view.| -|**Assets**| Displays all assets built as part of the Addressables build. Expanding an asset to display all assets and AssetBundles that depend on the expanded asset.| -|**Labels**| Displays all the assets built as part of the Addressables build, sorted by the label attached to the Asset. Expand an asset to display the assets and AssetBundles that depend on the expanded asset.| -|**Groups**| Displays all the AssetBundles built as part of the Addressables build, sorted by which [group](Groups.md) generated the bundle. If you use the **Pack Together By Label** or **Pack Separately** group settings, it's possible for multiple AssetBundles to be generated by a single group.| - -When you select an asset in the Explore Tab, its information is displayed in [the Inspector panel](addressables-report-inspector.md). - -## Potential Issues tab - -The Potential Issues tab scans the selected build report for any potential issues or problems that might have happened as part of your build. You can then view how these issues might have happened. It has the following view: - -* **Duplicated Assets View**: Displays a list of all of the non-Addressable assets that are duplicated between multiple bundles in your build. This happens when two addressable assets are in different bundles, but both reference a common asset that is not marked as addressable. - -To fix these issues, either move the Addressable assets into the same bundle, or make the asset Addressable. Either means of fixing it will have implications on your build dependencies. You should usually use whichever method minimizes the impact on having the asset duplicated. - -Selecting an asset in the Potential Issues Tab opens its information in [the Inspector panel](addressables-report-inspector.md). +--- + +uid: addressables-report-overview + +--- + +# Addressables Report window reference + +The Addressables Report is a tool that you can use to view information about the content built in an Addressables Build in depth. + +To open the Addressables Report window, go to **Window** > **Asset Management** > **Addressables** and select **Addressables Report**. + +## Prerequisites + +* You must use Unity Editor version 2022.2 or newer. If you want to use the Addressables report, but your current Editor version is below 2022.2, you can use a [build report](BuildLayoutReport.md) built on an earlier version of the Unity Editor and import it into a project uses an Editor version newer than 2022.2, provided that the build report is built on Addressables version 1.21.8 or newer. +* The Addressables Report also requires a [build report](BuildLayoutReport.md) generated by an Addressables build to function. To enable the generation of build reports, go to **Edit** > **Preferences** > **Addressables** and enable the **Debug Build Layout** property. +* By default, the Addressables Report opens automatically after every build. To disable this, go to **Edit** > **Preferences** > **Addressables** and disable **Open Addressables Report After Build** + +## Addressables Report window overview + +![](images/addressables-report-window.png)
_Addressables Report window_ + +The Addressables Report window has the following views: + +| __View__ | __Description__ | +|:---|:---| +| [Summary tab](#summary-tab) | Displays a high level overview of the Addressables build and its contents. | +| [Explore tab](#explore-tab)| Displays a detailed breakdown of all the content built as part of the Addressables build | +| [Potential Issues tab](AddressablesReportPotentialIssuesTab.md)| Scans the current build report for issues that might affect build performance or otherwise be undesirable. | + +Select the tabs along the top of the Addressables Report window to change views. + +The left sidebar panel contains the list of all the build reports currently detected within the project. Select a build report in the side bar to load that report in the Addressables Report window. + +The right sidebar is the [Inspector Panel](addressables-report-inspector.md), which you can use to view detailed information on an asset or AssetBundle while viewing information within the Explore or Potential Issues views. + +Use the search bar in the Build Report window to search within the Explore and Potential Issues tabs. This filters all assets in the current view by the text written in the search bar. + +## Summary tab + +The Summary tab displays information about the selected build report, along with information about any detected potential issues in the build. It includes the following sections: + +* **General Information:** Includes the locations of the catalogs created by the build, which profile the current build was built with, how long the build took, and the version of the Addressables package and the Unity Editor that the build was created with. +* **Potential Issues:** Contains a summary of the issues in the [Potential Issues tab](AddressablesReportPotentialIssuesTab.md) +* **Aggregate Information:** Displays the number of AssetBundles created as part of the build, the size of the bundles built, and the number of assets in the build. The number of assets includes assets that are referenced by an Addressable asset, but aren't marked as Addressable. These assets must be included in the build to allow for assets that depend on them to be loaded. + +>[!NOTE] +> If multiple Addressable assets in different bundles depend on the same non-Addressable asset, then that non-Addressable asset is duplicated in multiple bundles. For more information about duplicated assets, refer to [Duplicated Assets View](AddressablesReportPotentialIssuesTab.md). + +## Explore tab + +The Explore tab has detailed information about the selected build report. Use the **View By** dropdown to change the way that assets are organized in the build report. + +You can sort the Explore View in the following ways: + +|**View**|**Description**| +|---|---| +|**AssetBundles**| Displays all AssetBundles built as part of the Addressables build. Expand an AssetBundle to display the assets that bundle contains. This is the default view.| +|**Assets**| Displays all assets built as part of the Addressables build. Expanding an asset to display all assets and AssetBundles that depend on the expanded asset.| +|**Labels**| Displays all the assets built as part of the Addressables build, sorted by the label attached to the Asset. Expand an asset to display the assets and AssetBundles that depend on the expanded asset.| +|**Groups**| Displays all the AssetBundles built as part of the Addressables build, sorted by which [group](Groups.md) generated the bundle. If you use the **Pack Together By Label** or **Pack Separately** group settings, it's possible for multiple AssetBundles to be generated by a single group.| + +When you select an asset in the Explore Tab, its information is displayed in [the Inspector panel](addressables-report-inspector.md). + +## Potential Issues tab + +The Potential Issues tab scans the selected build report for any potential issues or problems that might have happened as part of your build. You can then view how these issues might have happened. It has the following view: + +* **Duplicated Assets View**: Displays a list of all of the non-Addressable assets that are duplicated between multiple bundles in your build. This happens when two addressable assets are in different bundles, but both reference a common asset that is not marked as addressable. + +To fix these issues, either move the Addressable assets into the same bundle, or make the asset Addressable. Either means of fixing it will have implications on your build dependencies. You should usually use whichever method minimizes the impact on having the asset duplicated. + +Selecting an asset in the Potential Issues Tab opens its information in [the Inspector panel](addressables-report-inspector.md). diff --git a/Documentation~/addressables-report.md b/Documentation~/addressables-report.md index 7c07189d..951c811f 100644 --- a/Documentation~/addressables-report.md +++ b/Documentation~/addressables-report.md @@ -1,27 +1,27 @@ ---- -uid: addressables-report ---- - -# Addressables Report - -The Addressables Report is a tool that you can use to view information about the content built in an Addressables Build in depth. - -To open the Addressables Report window, go to **Window** > **Asset Management** > **Addressables** and select **Addressables Report**. - -## Prerequisites - -* You must use Unity Editor version 2022.2 or newer. If you want to use the Addressables report, but your current Editor version is below 2022.2, you can use a [build report](BuildLayoutReport.md) built on an earlier version of the Unity Editor and import it into a project uses an Editor version newer than 2022.2, as long as the build report is built on a version of Addressables 1.21.8 or newer. -* The Addressables Report also requires a [build report](BuildLayoutReport.md) generated by an Addressables build to function. To enable the generation of build reports, go to **Edit > Preferences > Addressables** and enable **Debug Build Layout**. -* By default, the Addressables Report opens automatically after every build. To disable this, go to **Edit** > **Preferences** > **Addressables** and disable **Open Addressables Report After Build**. - - -![](images/addressables-report-window.png)
_Addressables Report window_ - -This section contains the following topics: - -|**Topic**|**Description**| -|---|---| -|**[The Summary tab](xref:addressables-report-summary)**| Displays basic information about the currently selected build report. | -|**[The Explore tab](xref:addressables-report-explore)**| Displays detailed information about the currently selected build report. | -|**[The Potential Issues tab](xref:addressables-report-potential-issues)**| Displays detailed information about any possible issues that the Addressables package detects in the currently selected build report. | -|**[Inspector Reference](xref:addressables-report-inspector-reference)**| Reference for the Addressables Report Inspector user interface. | +--- +uid: addressables-report +--- + +# Addressables Report + +The Addressables Report is a tool that you can use to view information about the content built in an Addressables Build in depth. + +To open the Addressables Report window, go to **Window** > **Asset Management** > **Addressables** and select **Addressables Report**. + +## Prerequisites + +* You must use Unity Editor version 2022.2 or newer. If you want to use the Addressables report, but your current Editor version is below 2022.2, you can use a [build report](BuildLayoutReport.md) built on an earlier version of the Unity Editor and import it into a project uses an Editor version newer than 2022.2, as long as the build report is built on a version of Addressables 1.21.8 or newer. +* The Addressables Report also requires a [build report](BuildLayoutReport.md) generated by an Addressables build to function. To enable the generation of build reports, go to **Edit > Preferences > Addressables** and enable **Debug Build Layout**. +* By default, the Addressables Report opens automatically after every build. To disable this, go to **Edit** > **Preferences** > **Addressables** and disable **Open Addressables Report After Build**. + + +![](images/addressables-report-window.png)
_Addressables Report window_ + +This section contains the following topics: + +|**Topic**|**Description**| +|---|---| +|**[The Summary tab](xref:addressables-report-summary)**| Displays basic information about the currently selected build report. | +|**[The Explore tab](xref:addressables-report-explore)**| Displays detailed information about the currently selected build report. | +|**[The Potential Issues tab](xref:addressables-report-potential-issues)**| Displays detailed information about any possible issues that the Addressables package detects in the currently selected build report. | +|**[Inspector Reference](xref:addressables-report-inspector-reference)**| Reference for the Addressables Report Inspector user interface. | diff --git a/Documentation~/api_index.md b/Documentation~/api_index.md index 5ae59b3b..8daaf4c6 100644 --- a/Documentation~/api_index.md +++ b/Documentation~/api_index.md @@ -1,47 +1,47 @@ ---- -uid: addressables-script-ref ---- - -# Addressables Script Reference - -This section of the documentation contains details of the scripting API that Unity provides for the Addressables package. - -The scripting reference is organized according to the classes available to scripts, which are described along with their methods, properties, and any other information relevant to their use. - -API are grouped by namespaces they belong to, and can be selected from the sidebar to the left. You can use the Filter control above the sidebar to filter the table of contents so that it only shows entries containing the string you enter. You can also use the Search control at the top of the window to perform a full-text search of the Addressables documentation. - -## Commonly used classes - -The following lists include the most commonly used classes you will encounter when using the Addressables API: - -In runtime code: - -* [Addressables]: contains the main API for interacting with the Addressables system at runtime, from initialization, to loading assets, to releasing them. -* [AsyncOperationHandle]: a handle for Addressables operations. Provides access to the assets loaded, operation progress, and other results. -* [AsyncOperationBase]: a base class for implementing your own operations. -* [AssetReference]: a type you can use in MonoBehaviours to easily reference Addressable assets via an Inspector window. -* [IResourceLocation]: an interface to objects that contain information needed to load an asset. -* [ResourceManager]: manages Addressable resources and operations. -* [CacheInitializationSettings]: a specialized object for initializing your cache settings. -* [InternalIdTransformFunc]: A function you can implement to dynamically transform asset URLs. - -In Unity Editor code: - -* [AddressableAssetSettings]: defines the Addressable settings. -* [AddressableAssetSettingsDefaultObject]: provides access to the asset containing your Addressables settings. -* [IHostingService]: an interface for creating your own hosting service implementations. -* [IDataBuilder]: an interface for creating your own build implementations. - - -[Addressables]: xref:UnityEngine.AddressableAssets.Addressables -[AsyncOperationHandle]: xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle -[AsyncOperationBase]: xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1 -[IResourceLocation]: xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation -[CacheInitializationSettings]: xref:UnityEditor.AddressableAssets.Settings.CacheInitializationSettings -[InternalIdTransformFunc]: xref:UnityEngine.ResourceManagement.ResourceManager.InternalIdTransformFunc -[AssetReference]: xref:UnityEngine.AddressableAssets.AssetReference -[AddressableAssetSettings]: xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings -[AddressableAssetSettingsDefaultObject]: xref:UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject -[IHostingService]: xref:UnityEditor.AddressableAssets.HostingServices.IHostingService -[IDataBuilder]: xref:UnityEditor.AddressableAssets.Build.IDataBuilder -[ResourceManager]: xref:UnityEngine.ResourceManagement.ResourceManager +--- +uid: addressables-script-ref +--- + +# Addressables Script Reference + +This section of the documentation contains details of the scripting API that Unity provides for the Addressables package. + +The scripting reference is organized according to the classes available to scripts, which are described along with their methods, properties, and any other information relevant to their use. + +API are grouped by namespaces they belong to, and can be selected from the sidebar to the left. You can use the Filter control above the sidebar to filter the table of contents so that it only shows entries containing the string you enter. You can also use the Search control at the top of the window to perform a full-text search of the Addressables documentation. + +## Commonly used classes + +The following lists include the most commonly used classes you will encounter when using the Addressables API: + +In runtime code: + +* [Addressables]: contains the main API for interacting with the Addressables system at runtime, from initialization, to loading assets, to releasing them. +* [AsyncOperationHandle]: a handle for Addressables operations. Provides access to the assets loaded, operation progress, and other results. +* [AsyncOperationBase]: a base class for implementing your own operations. +* [AssetReference]: a type you can use in MonoBehaviours to easily reference Addressable assets via an Inspector window. +* [IResourceLocation]: an interface to objects that contain information needed to load an asset. +* [ResourceManager]: manages Addressable resources and operations. +* [CacheInitializationSettings]: a specialized object for initializing your cache settings. +* [InternalIdTransformFunc]: A function you can implement to dynamically transform asset URLs. + +In Unity Editor code: + +* [AddressableAssetSettings]: defines the Addressable settings. +* [AddressableAssetSettingsDefaultObject]: provides access to the asset containing your Addressables settings. +* [IHostingService]: an interface for creating your own hosting service implementations. +* [IDataBuilder]: an interface for creating your own build implementations. + + +[Addressables]: xref:UnityEngine.AddressableAssets.Addressables +[AsyncOperationHandle]: xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle +[AsyncOperationBase]: xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase`1 +[IResourceLocation]: xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation +[CacheInitializationSettings]: xref:UnityEditor.AddressableAssets.Settings.CacheInitializationSettings +[InternalIdTransformFunc]: xref:UnityEngine.ResourceManagement.ResourceManager.InternalIdTransformFunc +[AssetReference]: xref:UnityEngine.AddressableAssets.AssetReference +[AddressableAssetSettings]: xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings +[AddressableAssetSettingsDefaultObject]: xref:UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject +[IHostingService]: xref:UnityEditor.AddressableAssets.HostingServices.IHostingService +[IDataBuilder]: xref:UnityEditor.AddressableAssets.Build.IDataBuilder +[ResourceManager]: xref:UnityEngine.ResourceManagement.ResourceManager diff --git a/Documentation~/asset-organization-strategy.md b/Documentation~/asset-organization-strategy.md index efe683c5..b195e392 100644 --- a/Documentation~/asset-organization-strategy.md +++ b/Documentation~/asset-organization-strategy.md @@ -1,12 +1,12 @@ ---- -uid: asset-organization-strategy ---- - -# Organize your Addressable assets - -It's important to choose the correct strategy for organizing assets in your project to make the best use of the Addressables package. This section highlights strategies for a variety of common project types. - -|**Topic**|**Description**| -|---|---| -|[Asset organization overview](asset-strategy-overview.md)| | +--- +uid: asset-organization-strategy +--- + +# Organize your Addressable assets + +It's important to choose the correct strategy for organizing assets in your project to make the best use of the Addressables package. This section highlights strategies for a variety of common project types. + +|**Topic**|**Description**| +|---|---| +|[Asset organization overview](asset-strategy-overview.md)| | |[Organize Addressables assets](organize-addressable-assets.md)| Different strategies you can use to organize your Addressable assets. | \ No newline at end of file diff --git a/Documentation~/asset-reference-create.md b/Documentation~/asset-reference-create.md index 51988308..346a3755 100644 --- a/Documentation~/asset-reference-create.md +++ b/Documentation~/asset-reference-create.md @@ -1,43 +1,43 @@ -# Create asset reference fields - -To add an [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) or one of its subclasses, to a `MonoBehaviour` or `ScriptableObject`, declare it as a serializable field in the class: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/DeclaringReferences.cs#doc_DeclaringReferences)] - -> [!NOTE] -> Before Unity 2020.1, the Inspector window couldn't display generic fields by default. In earlier versions of Unity, you must make your own non-generic subclass of `AssetReferenceT` instead. For more information, refer to [Create a concrete subclass](#create-a-concrete-subclass). - -## Load and release asset references - -The [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) class provides its own methods to load, instantiate, and release a referenced asset. You can also use an AssetReference instance as a key to any `Addressables` class method that loads assets. - -The following example instantiates an AssetReference as a child of the current GameObject and releases it when the parent is destroyed: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/InstantiateReference.cs#doc_InstantiateReference)] - -Refer to [Load an AssetReference](LoadingAssetReferences.md) for more information and examples about loading assets using AssetReferences. - -## Use labels with asset references - -Use the [`AssetReferenceUILabelRestriction`](xref:UnityEngine.AssetReferenceUILabelRestriction) attribute to restrict the assets you can assign to an `AssetReference` field to those with specific [labels](Labels.md). You can use this attribute reference and `AssetReference` subclasses to restrict assignment by both type and label. - -The following example prevents someone from assigning an Addressable asset to a reference that doesn't have either the label, `animals`, or the label, `characters`: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/DeclaringReferences.cs#doc_RestrictionAttribute)] - -This attribute only prevents assigning assets without the specified label using an Inspector in the Unity Editor. You can still assign an asset without the label to the field using a script. - -You can't drag non-Addressable assets to a field with the `AssetReferenceUILabelRestriction` attribute. - -## Create a concrete subclass - -If you can't use the generic form of the `AssetReference` class directly, such as in versions of Unity prior to Unity 2020.1 or when using the `CustomPropertyDrawer` attribute, you can create a concrete subclass. - -To create a concrete subclass, inherit from the [`AssetReferenceT`](xref:UnityEngine.AddressableAssets.AssetReferenceT`1) class and specify the asset type. You must also pass the GUID string to the base class constructor: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/DeclaringReferences.cs#doc_ConcreteSubclass)] - - -You can use your custom AssetReference subclass in another script the same way as other AssetReference types: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/DeclaringReferences.cs#doc_UseConcreteSubclass)] +# Create asset reference fields + +To add an [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) or one of its subclasses, to a `MonoBehaviour` or `ScriptableObject`, declare it as a serializable field in the class: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/DeclaringReferences.cs#doc_DeclaringReferences)] + +> [!NOTE] +> Before Unity 2020.1, the Inspector window couldn't display generic fields by default. In earlier versions of Unity, you must make your own non-generic subclass of `AssetReferenceT` instead. For more information, refer to [Create a concrete subclass](#create-a-concrete-subclass). + +## Load and release asset references + +The [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) class provides its own methods to load, instantiate, and release a referenced asset. You can also use an AssetReference instance as a key to any `Addressables` class method that loads assets. + +The following example instantiates an AssetReference as a child of the current GameObject and releases it when the parent is destroyed: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/InstantiateReference.cs#doc_InstantiateReference)] + +Refer to [Load an AssetReference](LoadingAssetReferences.md) for more information and examples about loading assets using AssetReferences. + +## Use labels with asset references + +Use the [`AssetReferenceUILabelRestriction`](xref:UnityEngine.AssetReferenceUILabelRestriction) attribute to restrict the assets you can assign to an `AssetReference` field to those with specific [labels](Labels.md). You can use this attribute reference and `AssetReference` subclasses to restrict assignment by both type and label. + +The following example prevents someone from assigning an Addressable asset to a reference that doesn't have either the label, `animals`, or the label, `characters`: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/DeclaringReferences.cs#doc_RestrictionAttribute)] + +This attribute only prevents assigning assets without the specified label using an Inspector in the Unity Editor. You can still assign an asset without the label to the field using a script. + +You can't drag non-Addressable assets to a field with the `AssetReferenceUILabelRestriction` attribute. + +## Create a concrete subclass + +If you can't use the generic form of the `AssetReference` class directly, such as in versions of Unity prior to Unity 2020.1 or when using the `CustomPropertyDrawer` attribute, you can create a concrete subclass. + +To create a concrete subclass, inherit from the [`AssetReferenceT`](xref:UnityEngine.AddressableAssets.AssetReferenceT`1) class and specify the asset type. You must also pass the GUID string to the base class constructor: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/DeclaringReferences.cs#doc_ConcreteSubclass)] + + +You can use your custom AssetReference subclass in another script the same way as other AssetReference types: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/DeclaringReferences.cs#doc_UseConcreteSubclass)] diff --git a/Documentation~/asset-reference-intro.md b/Documentation~/asset-reference-intro.md index 33ecf617..28eaf844 100644 --- a/Documentation~/asset-reference-intro.md +++ b/Documentation~/asset-reference-intro.md @@ -1,36 +1,36 @@ -# Asset reference introduction - -An [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) is a type that can reference an Addressable asset. - -Use the `AssetReference` class in a `MonoBehaviour` or `ScriptableObject`. When you add a serializable `AssetReference` field to one of these classes, you can assign a value to the field in an Inspector window. You can restrict the assets that can be assigned to a field by type and by label. - -![image alt text](images/assetreference-inspector.png)
*An Inspector window displaying several AssetReference fields* - -To assign a value, drag an asset to the field or select the object picker icon to open a dialog that lets you choose an Addressable asset. - -If you drag a non-Addressable asset to an `AssetReference` field, the system automatically makes the asset Addressable and adds it to your default Addressables group. Sprite and SpriteAtlas assets can have sub-objects. AssetReferences assigned these types of asset display an additional object picker that you can use to specify which sub-object to reference. - -For examples of using `AssetReference` types in a project refer to the [Basic AssetReference](https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Basic/Basic%20AssetReference), [Component Reference](https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Basic/ComponentReference), and [Sprite Land](https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Basic/Sprite%20Land) projects in the [Addressables-Sample](https://github.com/Unity-Technologies/Addressables-Sample) repository. - -> [!IMPORTANT] -> To be able to assign assets from a group to an AssetReference field, you must enable the __Include GUIDs in Catalog__ property in the group’s Advanced Options. The __Include GUIDs in Catalog__ option is enabled by default. For more information, refer to [Content Packing & Loading schema reference](ContentPackingAndLoadingSchema.md). - -## AssetReference types - -The Addressables API provides [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) subclasses for common types of assets. You can use the generic subclass, [`AssetReferenceT`](xref:UnityEngine.AddressableAssets.AssetReferenceT`1), to restrict an AssetReference field to other asset types. - -The types of AssetReference include: - -|**AssetReference type**|**Description**| -|---|---| -|[`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference)| Can reference any asset type| -|[`AssetReferenceT`](xref:UnityEngine.AddressableAssets.AssetReferenceT`1)| Can reference assets that are the same type as `TObject`| -|[`AssetReferenceTexture`](xref:UnityEngine.AddressableAssets.AssetReferenceTexture)| Can reference a `Texture` asset.| -|[`AssetReferenceTexture2D`](xref:UnityEngine.AddressableAssets.AssetReferenceTexture2D)| Can reference a `Texture2D` asset.| -|[`AssetReferenceTexture3D`](xref:UnityEngine.AddressableAssets.AssetReferenceTexture3D)| Can reference a `Texture3D` asset.| -|[`AssetReferenceGameObject`](xref:UnityEngine.AddressableAssets.AssetReferenceGameObject)| Can reference a `Prefab` asset.| -|[`AssetReferenceAtlasedSprite`](xref:UnityEngine.AddressableAssets.AssetReferenceAtlasedSprite)| Can reference a `SpriteAtlas` asset.| -|[`AssetReferenceSprite`](xref:UnityEngine.AddressableAssets.AssetReferenceSprite)| Can reference a single `Sprite` asset.| - -> [!NOTE] -> If you want to use a [`CustomPropertyDrawer`](xref:editor-PropertyDrawers) with a generic `AssetReferenceT`, or are using a version of Unity earlier than 2020.1, you must make a concrete subclass to support custom `AssetReference` types. +# Asset reference introduction + +An [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) is a type that can reference an Addressable asset. + +Use the `AssetReference` class in a `MonoBehaviour` or `ScriptableObject`. When you add a serializable `AssetReference` field to one of these classes, you can assign a value to the field in an Inspector window. You can restrict the assets that can be assigned to a field by type and by label. + +![image alt text](images/assetreference-inspector.png)
*An Inspector window displaying several AssetReference fields* + +To assign a value, drag an asset to the field or select the object picker icon to open a dialog that lets you choose an Addressable asset. + +If you drag a non-Addressable asset to an `AssetReference` field, the system automatically makes the asset Addressable and adds it to your default Addressables group. Sprite and SpriteAtlas assets can have sub-objects. AssetReferences assigned these types of asset display an additional object picker that you can use to specify which sub-object to reference. + +For examples of using `AssetReference` types in a project refer to the [Basic AssetReference](https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Basic/Basic%20AssetReference), [Component Reference](https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Basic/ComponentReference), and [Sprite Land](https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Basic/Sprite%20Land) projects in the [Addressables-Sample](https://github.com/Unity-Technologies/Addressables-Sample) repository. + +> [!IMPORTANT] +> To be able to assign assets from a group to an AssetReference field, you must enable the __Include GUIDs in Catalog__ property in the group’s Advanced Options. The __Include GUIDs in Catalog__ option is enabled by default. For more information, refer to [Content Packing & Loading schema reference](ContentPackingAndLoadingSchema.md). + +## AssetReference types + +The Addressables API provides [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) subclasses for common types of assets. You can use the generic subclass, [`AssetReferenceT`](xref:UnityEngine.AddressableAssets.AssetReferenceT`1), to restrict an AssetReference field to other asset types. + +The types of AssetReference include: + +|**AssetReference type**|**Description**| +|---|---| +|[`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference)| Can reference any asset type| +|[`AssetReferenceT`](xref:UnityEngine.AddressableAssets.AssetReferenceT`1)| Can reference assets that are the same type as `TObject`| +|[`AssetReferenceTexture`](xref:UnityEngine.AddressableAssets.AssetReferenceTexture)| Can reference a `Texture` asset.| +|[`AssetReferenceTexture2D`](xref:UnityEngine.AddressableAssets.AssetReferenceTexture2D)| Can reference a `Texture2D` asset.| +|[`AssetReferenceTexture3D`](xref:UnityEngine.AddressableAssets.AssetReferenceTexture3D)| Can reference a `Texture3D` asset.| +|[`AssetReferenceGameObject`](xref:UnityEngine.AddressableAssets.AssetReferenceGameObject)| Can reference a `Prefab` asset.| +|[`AssetReferenceAtlasedSprite`](xref:UnityEngine.AddressableAssets.AssetReferenceAtlasedSprite)| Can reference a `SpriteAtlas` asset.| +|[`AssetReferenceSprite`](xref:UnityEngine.AddressableAssets.AssetReferenceSprite)| Can reference a single `Sprite` asset.| + +> [!NOTE] +> If you want to use a [`CustomPropertyDrawer`](xref:editor-PropertyDrawers) with a generic `AssetReferenceT`, or are using a version of Unity earlier than 2020.1, you must make a concrete subclass to support custom `AssetReference` types. diff --git a/Documentation~/asset-strategy-overview.md b/Documentation~/asset-strategy-overview.md index 86eb2267..8574d0d5 100644 --- a/Documentation~/asset-strategy-overview.md +++ b/Documentation~/asset-strategy-overview.md @@ -1,15 +1,15 @@ -# Asset organization strategy overview - -To maximize the benefits of the Addressables package, you need to organize your assets in a way that makes sense for your project. Each project has unique requirements and one strategy won't works across all project types. - -This section outlines strategies for organizing Addressables assets for some common types of projects. - -## Scale implications as your project grows larger - -As your project grows larger, consider the following aspects of your assets and bundles: - -* Total bundle size: Historically Unity hasn't supported files larger than 4GB. This has been fixed in some recent editor versions, but there can still be issues. You should keep the content of a given bundle under this limit for best compatibility across all platforms. -* __Bundle layout at scale__: The memory and performance trade-offs between the number of AssetBundles produced by your content build and the size of those bundles can change as your project grows larger. -* __Bundle dependencies__: When an Addressable asset is loaded, all of its bundle dependencies are also loaded. Be aware of any references between assets when creating Addressable groups. Refer to [Asset and AssetBundle dependencies](xref:addressables-asset-dependencies) for more information. -* __Sub assets affecting UI performance__: There is no hard limit here, but if you have many assets, and those assets have many subassets, it might be best to disable sub-asset display. This option only affects how the data is displayed in the Groups window, and does not affect what you can and cannot load at runtime. The option is available in the groups window under __Tools__> __Show Sprite and Subobject Addresses__. Disabling this will make the UI more responsive. -* __Group hierarchy display__: Another UI-only option to help with scale is __Group Hierarchy with Dashes__. This is available within the inspector of the top level settings. With this enabled, groups that contain dashes `-` in their names will display as if the dashes represented folder hierarchy. This does not affect the actual group name, or the way things are built. For example, two groups called `x-y-z` and `x-y-w` would display as if inside a folder called `x`, there was a folder called `y`. Inside that folder were two groups, called `x-y-z` and `x-y-w`. This doesn't affect UI responsiveness, but simply makes it easier to browse a large collection of groups. +# Asset organization strategy overview + +To maximize the benefits of the Addressables package, you need to organize your assets in a way that makes sense for your project. Each project has unique requirements and one strategy won't works across all project types. + +This section outlines strategies for organizing Addressables assets for some common types of projects. + +## Scale implications as your project grows larger + +As your project grows larger, consider the following aspects of your assets and bundles: + +* Total bundle size: Historically Unity hasn't supported files larger than 4GB. This has been fixed in some recent editor versions, but there can still be issues. You should keep the content of a given bundle under this limit for best compatibility across all platforms. +* __Bundle layout at scale__: The memory and performance trade-offs between the number of AssetBundles produced by your content build and the size of those bundles can change as your project grows larger. +* __Bundle dependencies__: When an Addressable asset is loaded, all of its bundle dependencies are also loaded. Be aware of any references between assets when creating Addressable groups. Refer to [Asset and AssetBundle dependencies](xref:addressables-asset-dependencies) for more information. +* __Sub assets affecting UI performance__: There is no hard limit here, but if you have many assets, and those assets have many subassets, it might be best to disable sub-asset display. This option only affects how the data is displayed in the Groups window, and does not affect what you can and cannot load at runtime. The option is available in the groups window under __Tools__> __Show Sprite and Subobject Addresses__. Disabling this will make the UI more responsive. +* __Group hierarchy display__: Another UI-only option to help with scale is __Group Hierarchy with Dashes__. This is available within the inspector of the top level settings. With this enabled, groups that contain dashes `-` in their names will display as if the dashes represented folder hierarchy. This does not affect the actual group name, or the way things are built. For example, two groups called `x-y-z` and `x-y-w` would display as if inside a folder called `x`, there was a folder called `y`. Inside that folder were two groups, called `x-y-z` and `x-y-w`. This doesn't affect UI responsiveness, but simply makes it easier to browse a large collection of groups. diff --git a/Documentation~/build-artifacts-included.md b/Documentation~/build-artifacts-included.md index 9cf86e89..b36b1454 100644 --- a/Documentation~/build-artifacts-included.md +++ b/Documentation~/build-artifacts-included.md @@ -1,40 +1,40 @@ -# Artifacts included in the player - -During a player build, the Addressables system copies the following files from the `Library/com.unity.addressables/aa/` folder to the [StreamingAssets](xref:StreamingAssets) folder: - -* **Local AssetBundles**: These are `.bundle` files according to your group, profile, and platform settings. By default, these files are located in the [`BuildTarget`](xref:UnityEditor.EditorUserBuildSettings.activeBuildTarget) subfolder. To change the build location of the bundle files produced by a group, modify the [Build & Load Paths](xref:addressables-content-packing-and-loading-schema) setting. -* `settings.json`: Contains Addressables configuration data used at runtime. -* `catalog.json`: The content catalog used to locate and load assets at runtime if no newer remote catalog is available. For more information about catalogs, refer to [Content catalogs](build-content-catalogs.md). -* `AddressablesLink/link.xml`: Prevents the Unity linker from stripping types used by your assets. For more information about code stripping, refer to [Managed Code Stripping](xref:ManagedCodeStripping). In Unity version 2021.2 and later, this file temporarily copied the [`AddressableAssetSettings.ConfigFolder`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.ConfigFolder), or the `Assets/Addressables_Temp` folder if no settings file exists. - -For a full list of platform names, refer to [`AddressablesPlatform`](xref:UnityEngine.AddressableAssets.AddressablesPlatform). - -## Artifacts not included in the player - -The following artifacts aren't included in a built player. - -### Remote content -Files used for remote content should be uploaded to a hosting server. By default these files are located in the `ServerData` folder. - -The files are: - -* **Remote AssetBundles**: These are `.bundle` files according to your group, profile, and platform settings. By default, these files are located in the [`BuildTarget`](xref:UnityEditor.EditorUserBuildSettings.activeBuildTarget) subfolder. To change the build location of the bundle files produced by a group, modify the [Build & Load Paths](xref:addressables-content-packing-and-loading-schema) setting. -* `catalog_{timestamp or player version}.json`: A remote catalog which when downloaded overrides the local catalog. This file is only created if the __Build Remote Catalogs__ option in [Content update settings](xref:addressables-asset-settings) is enabled. To change the build location of this file modify the __Build & Load Paths__ schema in Content update settings. By default the filename includes the timestamp of the build. To use a version number instead, specify the value of the __Player Version Override__ in [Catalog settings](xref:addressables-asset-settings). For more information about catalogs, refer to [Content catalogs](build-content-catalogs.md). -* `catalog_{timestamp or player version}.hash`: A file used to check whether the remote catalog has changed since the last time a client app downloaded it. Just like the remote catalog file, this file is only created if the __Build Remote Catalogs__ option in [Content update settings](xref:addressables-asset-settings) is enabled. To change the build location of this file modify the __Build & Load Paths__ in Content update settings. By default the filename includes the timestamp of the build. To use a version number instead, specify the value of the __Player Version Override__ in [Catalog settings](xref:addressables-asset-settings). For more information about catalogs, refer to [Content catalogs](build-content-catalogs.md). - -### Content state file - -The `addressables_content_state.bin` file is used to make a [content update build](xref:addressables-content-update-builds). If you are supporting dynamic content updates, you must save this file after each full content build that you release. Otherwise, you can ignore this file. - -By default this file is located in `Assets/AddressableAssetsData/`. Refer to [`AddressablesPlatform`](xref:UnityEngine.AddressableAssets.AddressablesPlatform) for all platform names. To change the build location of the file specify the value of the __Content State Build Path__ in [Content update settings](xref:addressables-asset-settings). - -> [!NOTE] -> Check this file into version control and create a new branch each time a player build is released. - -### Diagnostic data - -Additional files can be created to collect data about the content build. - -The files are: -* `Library/com.unity.addressables/AddressablesBuildTEP.json`: build performance data. Refer to [Build profiling](xref:addressables-build-profile-log) for more information. +# Artifacts included in the player + +During a player build, the Addressables system copies the following files from the `Library/com.unity.addressables/aa/` folder to the [StreamingAssets](xref:StreamingAssets) folder: + +* **Local AssetBundles**: These are `.bundle` files according to your group, profile, and platform settings. By default, these files are located in the [`BuildTarget`](xref:UnityEditor.EditorUserBuildSettings.activeBuildTarget) subfolder. To change the build location of the bundle files produced by a group, modify the [Build & Load Paths](xref:addressables-content-packing-and-loading-schema) setting. +* `settings.json`: Contains Addressables configuration data used at runtime. +* `catalog.json`: The content catalog used to locate and load assets at runtime if no newer remote catalog is available. For more information about catalogs, refer to [Content catalogs](build-content-catalogs.md). +* `AddressablesLink/link.xml`: Prevents the Unity linker from stripping types used by your assets. For more information about code stripping, refer to [Managed Code Stripping](xref:ManagedCodeStripping). In Unity version 2021.2 and later, this file temporarily copied the [`AddressableAssetSettings.ConfigFolder`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.ConfigFolder), or the `Assets/Addressables_Temp` folder if no settings file exists. + +For a full list of platform names, refer to [`AddressablesPlatform`](xref:UnityEngine.AddressableAssets.AddressablesPlatform). + +## Artifacts not included in the player + +The following artifacts aren't included in a built player. + +### Remote content +Files used for remote content should be uploaded to a hosting server. By default these files are located in the `ServerData` folder. + +The files are: + +* **Remote AssetBundles**: These are `.bundle` files according to your group, profile, and platform settings. By default, these files are located in the [`BuildTarget`](xref:UnityEditor.EditorUserBuildSettings.activeBuildTarget) subfolder. To change the build location of the bundle files produced by a group, modify the [Build & Load Paths](xref:addressables-content-packing-and-loading-schema) setting. +* `catalog_{timestamp or player version}.json`: A remote catalog which when downloaded overrides the local catalog. This file is only created if the __Build Remote Catalogs__ option in [Content update settings](xref:addressables-asset-settings) is enabled. To change the build location of this file modify the __Build & Load Paths__ schema in Content update settings. By default the filename includes the timestamp of the build. To use a version number instead, specify the value of the __Player Version Override__ in [Catalog settings](xref:addressables-asset-settings). For more information about catalogs, refer to [Content catalogs](build-content-catalogs.md). +* `catalog_{timestamp or player version}.hash`: A file used to check whether the remote catalog has changed since the last time a client app downloaded it. Just like the remote catalog file, this file is only created if the __Build Remote Catalogs__ option in [Content update settings](xref:addressables-asset-settings) is enabled. To change the build location of this file modify the __Build & Load Paths__ in Content update settings. By default the filename includes the timestamp of the build. To use a version number instead, specify the value of the __Player Version Override__ in [Catalog settings](xref:addressables-asset-settings). For more information about catalogs, refer to [Content catalogs](build-content-catalogs.md). + +### Content state file + +The `addressables_content_state.bin` file is used to make a [content update build](xref:addressables-content-update-builds). If you are supporting dynamic content updates, you must save this file after each full content build that you release. Otherwise, you can ignore this file. + +By default this file is located in `Assets/AddressableAssetsData/`. Refer to [`AddressablesPlatform`](xref:UnityEngine.AddressableAssets.AddressablesPlatform) for all platform names. To change the build location of the file specify the value of the __Content State Build Path__ in [Content update settings](xref:addressables-asset-settings). + +> [!NOTE] +> Check this file into version control and create a new branch each time a player build is released. + +### Diagnostic data + +Additional files can be created to collect data about the content build. + +The files are: +* `Library/com.unity.addressables/AddressablesBuildTEP.json`: build performance data. Refer to [Build profiling](xref:addressables-build-profile-log) for more information. * `Library/com.unity.addressables/buildlayoutreport`: information about AssetBundles produced by the build. Refer to [Build layout report](xref:addressables-build-layout-report) for more information. \ No newline at end of file diff --git a/Documentation~/build-content-catalogs.md b/Documentation~/build-content-catalogs.md index 7e6f0538..6bf14d0a 100644 --- a/Documentation~/build-content-catalogs.md +++ b/Documentation~/build-content-catalogs.md @@ -1,27 +1,27 @@ -# Content catalogs - -Content catalogs are the data stores Addressables uses to look up an asset's physical location based on the keys provided to the system. Addressables builds a single catalog for all Addressable assets. The catalog is placed in the [StreamingAssets](xref:StreamingAssets) folder when you build your application player. The local catalog can access remote and local assets, but if you want to update content between full builds of your application, you must create a remote catalog. - -## Remote catalog - -The remote catalog is a separate copy of the catalog that you host along with your remote content. - -Ultimately, Addressables only uses one of these catalogs. A hash file contains the hash (a mathematical fingerprint) of the catalog. If a remote catalog is built and it has a different hash than the local catalog, it is downloaded, cached, and used in place of the built-in local catalog. When you produce a [content update build](ContentUpdateWorkflow.md), the hash is updated and the new remote catalog points to the changed versions of any updated assets. - -> [!NOTE] -> You must enable the remote catalog for the full player build that you publish. Otherwise, the Addressables system doesn't check for a remote catalog and can't detect any content updates. Refer to [Enabling the remote catalog](xref:addressables-remote-content-distribution) for more information. - -Although Addressables produces one content catalog per project, you can load catalogs created by other projects to load Addressable assets produced by those projects. This allows you to use separate projects to develop and build some of your assets, which can make iteration and team collaboration easier on large productions. See [Managing catalogs at runtime](xref:addressables-api-load-content-catalog-async) for information about loading catalogs. - -## Catalog settings - -There are the following settings used for catalogs: - -* [Catalog settings](xref:addressables-asset-settings): Options used to configure local and remote catalogs -* [Content update settings](xref:addressables-asset-settings): Options used to configure the remote catalog only - -To minimize the catalog size, use the following settings: - -* **Compress the local catalog**: If your primary concern is how big the catalog is in your build, there is an option in [Catalog settings](xref:addressables-asset-settings) called **Compress Local Catalog**. This option builds catalog that ships with your game into an AssetBundle. Compressing the catalog makes the file itself smaller, but note that this does increase catalog load time. - -There are several group settings that can help reduce the catalog size, such as __Internal Asset Naming Mode__. For more information refer to [Advanced Group settings](xref:addressables-content-packing-and-loading-schema). +# Content catalogs + +Content catalogs are the data stores Addressables uses to look up an asset's physical location based on the keys provided to the system. Addressables builds a single catalog for all Addressable assets. The catalog is placed in the [StreamingAssets](xref:StreamingAssets) folder when you build your application player. The local catalog can access remote and local assets, but if you want to update content between full builds of your application, you must create a remote catalog. + +## Remote catalog + +The remote catalog is a separate copy of the catalog that you host along with your remote content. + +Ultimately, Addressables only uses one of these catalogs. A hash file contains the hash (a mathematical fingerprint) of the catalog. If a remote catalog is built and it has a different hash than the local catalog, it is downloaded, cached, and used in place of the built-in local catalog. When you produce a [content update build](ContentUpdateWorkflow.md), the hash is updated and the new remote catalog points to the changed versions of any updated assets. + +> [!NOTE] +> You must enable the remote catalog for the full player build that you publish. Otherwise, the Addressables system doesn't check for a remote catalog and can't detect any content updates. Refer to [Enabling the remote catalog](xref:addressables-remote-content-distribution) for more information. + +Although Addressables produces one content catalog per project, you can load catalogs created by other projects to load Addressable assets produced by those projects. This allows you to use separate projects to develop and build some of your assets, which can make iteration and team collaboration easier on large productions. See [Managing catalogs at runtime](xref:addressables-api-load-content-catalog-async) for information about loading catalogs. + +## Catalog settings + +There are the following settings used for catalogs: + +* [Catalog settings](xref:addressables-asset-settings): Options used to configure local and remote catalogs +* [Content update settings](xref:addressables-asset-settings): Options used to configure the remote catalog only + +To minimize the catalog size, use the following settings: + +* **Compress the local catalog**: If your primary concern is how big the catalog is in your build, there is an option in [Catalog settings](xref:addressables-asset-settings) called **Compress Local Catalog**. This option builds catalog that ships with your game into an AssetBundle. Compressing the catalog makes the file itself smaller, but note that this does increase catalog load time. + +There are several group settings that can help reduce the catalog size, such as __Internal Asset Naming Mode__. For more information refer to [Advanced Group settings](xref:addressables-content-packing-and-loading-schema). diff --git a/Documentation~/build-intro.md b/Documentation~/build-intro.md index 2f25ae60..f8dd49a2 100644 --- a/Documentation~/build-intro.md +++ b/Documentation~/build-intro.md @@ -1,39 +1,39 @@ -# Build content introduction - -A content build processes Addressables [groups](groups-intro.md) to produce the [content catalog](build-content-catalogs.md), runtime settings, and the [AssetBundles](xref:AssetBundlesIntro) that contain your assets. Addressables uses these files to load content at runtime. - -You can configure the Addressables system to build your Addressables content as part of every Player build or you can build your content separately before making a Player build. Refer to [Building Addressables content with Player builds](build-player-builds.md) for more information about configuring these options. - -## Configure builds - -If you configure Unity to build your content as part of the Player build, use the __Build__ or __Build and Run__ buttons in the Unity Editor [Build Settings](xref:PublishingBuilds) window to start a build. You can also invoke the Editor on the command line, passing in one of the `-buildPlatformPlayer` options or use an API such as [`BuildPipeline.BuildPlayer`](xref:UnityEditor.BuildPipeline.BuildPlayer(UnityEditor.BuildPlayerOptions)) to start the build. In all cases, Unity builds your Addressables content as a pre-build step before building the Player. - -If you configure Unity to build your content separately, you must start the Addressables build using the __Build__ menu on the [Addressables Groups window](GroupsWindow.md) as described in [Making builds](xref:addressables-building-content). The next time you build the Player for your project, it uses the artifacts produced by the last Addressables content build run for the current platform. Refer to[Build scripting](xref:addressables-api-build-player-content) for information about automating your Addressables build process. - -## Content build types - -Your content build can produce two general categories of content: - -* __Local content__: Content that's included directly in your player build. The Addressables system manages local content automatically as long as you use the default build path for your local content. If you change the local build path, you must copy the artifacts from the local build path to the project's `Assets/StreamingAssets` folder before making a Player build. -* __Remote content__: Content that's downloaded from a URL after your application is installed. It's your responsibility to upload remote content to a hosting server so your application can access it the designated URL specified by a [`RemoteLoadPath`](xref:addressables-profiles). - -Refer to [Build artifacts](xref:addressables-build-artifacts) for more information about files produced by a content build. - -## Groups and profiles - -Your project's [group settings](xref:addressables-group-schemas) determine which category a group belongs to. The active [Profile](xref:addressables-profiles) determines the specific paths and URLs that the Addressables system uses to build and load the content. The [Addressable Asset settings](xref:addressables-asset-settings) also contain options that affect your content builds, such as whether to build remote content at all. - -## Start a build - -You can start builds from a script or from the __Groups__ window. - -Refer to [Create a build](BuildingContent.md) for more information about builds from the Groups window, or to [Build scripting](xref:addressables-api-build-player-content) for more information on how to extend building Addressable content through scripts. - -The Addressables system includes the following build scripts: - -* __Default Build Script__: Performs a full content build based on Group, Profile, and Addressables system settings. -* __Update a Previous Build__: Performs a differential content build to update an existing build. -* __Play mode scripts__: The Play mode scripts are technically build scripts and control how the Editor accesses your content in Play mode. Refer to [Play mode Scripts](xref:addressables-groups-window) for more information. - -The build scripts also provide a function to clear the cached files they create. You can run these functions from the __Build > Clean Build__ menu of the [Groups window](GroupsWindow.md). - +# Build content introduction + +A content build processes Addressables [groups](groups-intro.md) to produce the [content catalog](build-content-catalogs.md), runtime settings, and the [AssetBundles](xref:AssetBundlesIntro) that contain your assets. Addressables uses these files to load content at runtime. + +You can configure the Addressables system to build your Addressables content as part of every Player build or you can build your content separately before making a Player build. Refer to [Building Addressables content with Player builds](build-player-builds.md) for more information about configuring these options. + +## Configure builds + +If you configure Unity to build your content as part of the Player build, use the __Build__ or __Build and Run__ buttons in the Unity Editor [Build Settings](xref:PublishingBuilds) window to start a build. You can also invoke the Editor on the command line, passing in one of the `-buildPlatformPlayer` options or use an API such as [`BuildPipeline.BuildPlayer`](xref:UnityEditor.BuildPipeline.BuildPlayer(UnityEditor.BuildPlayerOptions)) to start the build. In all cases, Unity builds your Addressables content as a pre-build step before building the Player. + +If you configure Unity to build your content separately, you must start the Addressables build using the __Build__ menu on the [Addressables Groups window](GroupsWindow.md) as described in [Making builds](xref:addressables-building-content). The next time you build the Player for your project, it uses the artifacts produced by the last Addressables content build run for the current platform. Refer to[Build scripting](xref:addressables-api-build-player-content) for information about automating your Addressables build process. + +## Content build types + +Your content build can produce two general categories of content: + +* __Local content__: Content that's included directly in your player build. The Addressables system manages local content automatically as long as you use the default build path for your local content. If you change the local build path, you must copy the artifacts from the local build path to the project's `Assets/StreamingAssets` folder before making a Player build. +* __Remote content__: Content that's downloaded from a URL after your application is installed. It's your responsibility to upload remote content to a hosting server so your application can access it the designated URL specified by a [`RemoteLoadPath`](xref:addressables-profiles). + +Refer to [Build artifacts](xref:addressables-build-artifacts) for more information about files produced by a content build. + +## Groups and profiles + +Your project's [group settings](xref:addressables-group-schemas) determine which category a group belongs to. The active [Profile](xref:addressables-profiles) determines the specific paths and URLs that the Addressables system uses to build and load the content. The [Addressable Asset settings](xref:addressables-asset-settings) also contain options that affect your content builds, such as whether to build remote content at all. + +## Start a build + +You can start builds from a script or from the __Groups__ window. + +Refer to [Create a build](BuildingContent.md) for more information about builds from the Groups window, or to [Build scripting](xref:addressables-api-build-player-content) for more information on how to extend building Addressable content through scripts. + +The Addressables system includes the following build scripts: + +* __Default Build Script__: Performs a full content build based on Group, Profile, and Addressables system settings. +* __Update a Previous Build__: Performs a differential content build to update an existing build. +* __Play mode scripts__: The Play mode scripts are technically build scripts and control how the Editor accesses your content in Play mode. Refer to [Play mode Scripts](xref:addressables-groups-window) for more information. + +The build scripts also provide a function to clear the cached files they create. You can run these functions from the __Build > Clean Build__ menu of the [Groups window](GroupsWindow.md). + diff --git a/Documentation~/build-player-builds.md b/Documentation~/build-player-builds.md index 3ddc290e..c37a229b 100644 --- a/Documentation~/build-player-builds.md +++ b/Documentation~/build-player-builds.md @@ -1,20 +1,20 @@ -# Build Addressables content with Player builds - -When you modify Addressable assets during development, you must rebuild your Addressables content before you build the Player. You can run the Addressables content build as a separate step before building a Player or you can run both the Addressables content build and the Player build together. - -Building Addressables content together with the Player can be convenient, but increases build time, especially on large projects. This is because Unity rebuilds the Addressables content even when you haven't modified any assets. If you don't change your Addressables content between most builds, consider disabling this option. - -The __Build Addressables on Player Build__ setting in the Project [Addressable Asset Settings](xref:addressables-asset-settings#build) specifies which option to use for building Addressables content. You can choose the appropriate option for each project or defer to the [global Preferences setting](addressables-preferences.md). When you set a project-level setting, it applies to all contributors who build the project. The Preferences setting applies to all Unity Projects that don't set a specific value. - -> [!NOTE] -> Building Addressables on Player Build requires Unity 2021.2+. In earlier versions of Unity, you must build Addressables content as a separate step. - -## Build commands - -Access build commands from the __Build__ menu on the toolbar at the top of the [Groups window](GroupsWindow.md) (**Window > Asset Management > Addressables > Groups**). - -The menu provides the following items: - -* __New Build__: Choose a build script to run a full content build. The Addressables package includes one build script, __Default Build Script__. If you create custom build scripts, you can access them here. For more information, refer to [Build scripting](BuildPlayerContent.md). -* __Update a Previous Build__: Run a differential update based on an earlier build. An update build can produce smaller downloads when you support remote content distribution and publish updated content. Refer tp [Content update builds](ContentUpdateWorkflow.md) for more information. -* __Clean Build__: Choose a command to clean existing build cache files. Each build script can provide a clean up function, which you can invoke from this menu. +# Build Addressables content with Player builds + +When you modify Addressable assets during development, you must rebuild your Addressables content before you build the Player. You can run the Addressables content build as a separate step before building a Player or you can run both the Addressables content build and the Player build together. + +Building Addressables content together with the Player can be convenient, but increases build time, especially on large projects. This is because Unity rebuilds the Addressables content even when you haven't modified any assets. If you don't change your Addressables content between most builds, consider disabling this option. + +The __Build Addressables on Player Build__ setting in the Project [Addressable Asset Settings](xref:addressables-asset-settings#build) specifies which option to use for building Addressables content. You can choose the appropriate option for each project or defer to the [global Preferences setting](addressables-preferences.md). When you set a project-level setting, it applies to all contributors who build the project. The Preferences setting applies to all Unity Projects that don't set a specific value. + +> [!NOTE] +> Building Addressables on Player Build requires Unity 2021.2+. In earlier versions of Unity, you must build Addressables content as a separate step. + +## Build commands + +Access build commands from the __Build__ menu on the toolbar at the top of the [Groups window](GroupsWindow.md) (**Window > Asset Management > Addressables > Groups**). + +The menu provides the following items: + +* __New Build__: Choose a build script to run a full content build. The Addressables package includes one build script, __Default Build Script__. If you create custom build scripts, you can access them here. For more information, refer to [Build scripting](BuildPlayerContent.md). +* __Update a Previous Build__: Run a differential update based on an earlier build. An update build can produce smaller downloads when you support remote content distribution and publish updated content. Refer tp [Content update builds](ContentUpdateWorkflow.md) for more information. +* __Clean Build__: Choose a command to clean existing build cache files. Each build script can provide a clean up function, which you can invoke from this menu. diff --git a/Documentation~/build-scripting-custom.md b/Documentation~/build-scripting-custom.md index 099c7fab..ef3c1a40 100644 --- a/Documentation~/build-scripting-custom.md +++ b/Documentation~/build-scripting-custom.md @@ -1,31 +1,31 @@ -# Custom build scripting - -To configure a new custom script, add it to the [Build and Play Mode Scripts](xref:addressables-asset-settings) list. - -Custom scripts extend the [`BuildScriptBase`](xref:UnityEditor.AddressableAssets.Build.DataBuilders.BuildScriptBase) class or implement the [`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder) interface. There are several methods that you can override, such as `ClearCachedData` and `CanBuildData`. If extending the `BuildScriptBase` class, the most notable method to override is `BuildDataImplementation`. This is the method that's used to setup or build content. - -A custom script is either a Build Script or a Play Mode Script. This is determined by how the `CanBuildData` method is implemented. Build scripts can only build data of the type `AddressablesPlayerBuildResult`, so the method is implemented in this way: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/CustomBuildScript.cs#doc_CustomBuildScript)] - -This allows the script to be listed in the **Build** menu. - -Play Mode Scripts can only build data of the type `AddressablesPlayModeBuildResult`, so the method is implemented in this way: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/CustomBuildScript.cs#doc_CustomPlayModeScript)] - -This allows the script to be listed in the **Play Mode Scripts** menu. - -See the [Custom Build and Play Mode Scripts Sample](SamplesOverview.md) for an example. - -## Extend the default build script - -If you want to use the same basic build as the default build script [`BuildScriptPackedMode`](xref:UnityEditor.AddressableAssets.Build.DataBuilders.BuildScriptPackedMode), but want to treat specific groups or types of assets differently, you can extend and override the default build script. If the group or asset the build script is processing is one that you want to treat differently, you can run your own code. Otherwise, you can call the base class version of the function to use the default algorithm. - -Refer to the [Addressable variants project](https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Advanced/Addressable%20Variants) for an example. - -## Save the content state - -If you support [remote content distribution](xref:addressables-remote-content-distribution) and update your content between player releases, you must record the state of your Addressables groups at the time of the build. Recording the state lets you perform a differential build using the [Update a Previous Build](xref:addressables-content-update-builds) script. - +# Custom build scripting + +To configure a new custom script, add it to the [Build and Play Mode Scripts](xref:addressables-asset-settings) list. + +Custom scripts extend the [`BuildScriptBase`](xref:UnityEditor.AddressableAssets.Build.DataBuilders.BuildScriptBase) class or implement the [`IDataBuilder`](xref:UnityEditor.AddressableAssets.Build.IDataBuilder) interface. There are several methods that you can override, such as `ClearCachedData` and `CanBuildData`. If extending the `BuildScriptBase` class, the most notable method to override is `BuildDataImplementation`. This is the method that's used to setup or build content. + +A custom script is either a Build Script or a Play Mode Script. This is determined by how the `CanBuildData` method is implemented. Build scripts can only build data of the type `AddressablesPlayerBuildResult`, so the method is implemented in this way: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/CustomBuildScript.cs#doc_CustomBuildScript)] + +This allows the script to be listed in the **Build** menu. + +Play Mode Scripts can only build data of the type `AddressablesPlayModeBuildResult`, so the method is implemented in this way: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/CustomBuildScript.cs#doc_CustomPlayModeScript)] + +This allows the script to be listed in the **Play Mode Scripts** menu. + +See the [Custom Build and Play Mode Scripts Sample](SamplesOverview.md) for an example. + +## Extend the default build script + +If you want to use the same basic build as the default build script [`BuildScriptPackedMode`](xref:UnityEditor.AddressableAssets.Build.DataBuilders.BuildScriptPackedMode), but want to treat specific groups or types of assets differently, you can extend and override the default build script. If the group or asset the build script is processing is one that you want to treat differently, you can run your own code. Otherwise, you can call the base class version of the function to use the default algorithm. + +Refer to the [Addressable variants project](https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Advanced/Addressable%20Variants) for an example. + +## Save the content state + +If you support [remote content distribution](xref:addressables-remote-content-distribution) and update your content between player releases, you must record the state of your Addressables groups at the time of the build. Recording the state lets you perform a differential build using the [Update a Previous Build](xref:addressables-content-update-builds) script. + Refer to the implementation of [`BuildScriptPackedMode`](xref:UnityEditor.AddressableAssets.Build.DataBuilders.BuildScriptPackedMode) and [`ContentUpdateScript`](xref:UnityEditor.AddressableAssets.Build.ContentUpdateScript) for details. \ No newline at end of file diff --git a/Documentation~/build-scripting-recompiling.md b/Documentation~/build-scripting-recompiling.md index 5e6c597f..51954102 100644 --- a/Documentation~/build-scripting-recompiling.md +++ b/Documentation~/build-scripting-recompiling.md @@ -1,57 +1,57 @@ -# Build while recompiling - -If you have a pre-build step that triggers a domain reload, then you must take special care that the Addressables build itself does not start until after the domain reload is finished. - -Using methods such as setting scripting define symbols with [`PlayerSettings.SetScriptingDefineSymbolsForGroup`](https://docs.unity3d.com/ScriptReference/PlayerSettings.SetScriptingDefineSymbolsForGroup.html), or switching the active build target with [`EditorUserBuildSettings.SwitchActiveBuildTarget`](https://docs.unity3d.com/ScriptReference/EditorUserBuildSettings.SwitchActiveBuildTarget.html), triggers scripts to recompile and reload. The execution of the Unity Editor code continues with the currently loaded domain until the domain reloads and execution stops. Any [platform dependent compilation](https://docs.unity3d.com/Manual/PlatformDependentCompilation.html) or custom defines isn't set until after the domain reloads. This can lead to unexpected issues where code relies on these defines to build correctly, and can be easily missed. - -## Change scripts before building - -To switch platform, or modify Editor scripts in code and then continue with the defines set, a domain reload must be performed. In this case, the `-quit` argument should not be used or the Editor will exit immediately after execution of the invoked method. - -When the domain reloads, `InitializeOnLoad` is invoked. The code below demonstrates how to set scripting define symbols and react to those in the Editor code, building Addressables after the domain reload completes. The same process can be done for switching platforms and [platform dependent compilation](https://docs.unity3d.com/Manual/PlatformDependentCompilation.html). - -```c# -[InitializeOnLoad] -public class BuildWithScriptingDefinesExample -{ - static BuildWithScriptingDefinesExample() - { - bool toBuild = SessionState.GetBool("BuildAddressables", false); - SessionState.EraseBool("BuildAddressables"); - if (toBuild) - { - Debug.Log("Domain reload complete, building Addressables as requested"); - BuildAddressablesAndRevertDefines(); - } - } - - [MenuItem("Build/Addressables with script define")] - public static void BuildTest() - { -#if !MYDEFINEHERE - Debug.Log("Setting up SessionState to inform an Addressables build is requested on next Domain Reload"); - SessionState.SetBool("BuildAddressables", true); - string originalDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup); - string newDefines = string.IsNullOrEmpty(originalDefines) ? "MYDEFINEHERE" : originalDefines + ";MYDEFINEHERE"; - Debug.Log("Setting Scripting Defines, this will then start compiling and begin a domain reload of the Editor Scripts."); - PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, newDefines); -#endif - } - - static void BuildAddressablesAndRevertDefines() - { -#if MYDEFINEHERE - Debug.Log("Correct scripting defines set for desired build"); - AddressableAssetSettings.BuildPlayerContent(); - string originalDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup); - if (originalDefines.Contains(";MYDEFINEHERE")) - originalDefines = originalDefines.Replace(";MYDEFINEHERE", ""); - else - originalDefines = originalDefines.Replace("MYDEFINEHERE", ""); - PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, originalDefines); - AssetDatabase.SaveAssets(); -#endif - EditorApplication.Exit(0); - } -} -``` +# Build while recompiling + +If you have a pre-build step that triggers a domain reload, then you must take special care that the Addressables build itself does not start until after the domain reload is finished. + +Using methods such as setting scripting define symbols with [`PlayerSettings.SetScriptingDefineSymbolsForGroup`](https://docs.unity3d.com/ScriptReference/PlayerSettings.SetScriptingDefineSymbolsForGroup.html), or switching the active build target with [`EditorUserBuildSettings.SwitchActiveBuildTarget`](https://docs.unity3d.com/ScriptReference/EditorUserBuildSettings.SwitchActiveBuildTarget.html), triggers scripts to recompile and reload. The execution of the Unity Editor code continues with the currently loaded domain until the domain reloads and execution stops. Any [platform dependent compilation](https://docs.unity3d.com/Manual/PlatformDependentCompilation.html) or custom defines isn't set until after the domain reloads. This can lead to unexpected issues where code relies on these defines to build correctly, and can be easily missed. + +## Change scripts before building + +To switch platform, or modify Editor scripts in code and then continue with the defines set, a domain reload must be performed. In this case, the `-quit` argument should not be used or the Editor will exit immediately after execution of the invoked method. + +When the domain reloads, `InitializeOnLoad` is invoked. The code below demonstrates how to set scripting define symbols and react to those in the Editor code, building Addressables after the domain reload completes. The same process can be done for switching platforms and [platform dependent compilation](https://docs.unity3d.com/Manual/PlatformDependentCompilation.html). + +```c# +[InitializeOnLoad] +public class BuildWithScriptingDefinesExample +{ + static BuildWithScriptingDefinesExample() + { + bool toBuild = SessionState.GetBool("BuildAddressables", false); + SessionState.EraseBool("BuildAddressables"); + if (toBuild) + { + Debug.Log("Domain reload complete, building Addressables as requested"); + BuildAddressablesAndRevertDefines(); + } + } + + [MenuItem("Build/Addressables with script define")] + public static void BuildTest() + { +#if !MYDEFINEHERE + Debug.Log("Setting up SessionState to inform an Addressables build is requested on next Domain Reload"); + SessionState.SetBool("BuildAddressables", true); + string originalDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup); + string newDefines = string.IsNullOrEmpty(originalDefines) ? "MYDEFINEHERE" : originalDefines + ";MYDEFINEHERE"; + Debug.Log("Setting Scripting Defines, this will then start compiling and begin a domain reload of the Editor Scripts."); + PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, newDefines); +#endif + } + + static void BuildAddressablesAndRevertDefines() + { +#if MYDEFINEHERE + Debug.Log("Correct scripting defines set for desired build"); + AddressableAssetSettings.BuildPlayerContent(); + string originalDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup); + if (originalDefines.Contains(";MYDEFINEHERE")) + originalDefines = originalDefines.Replace(";MYDEFINEHERE", ""); + else + originalDefines = originalDefines.Replace("MYDEFINEHERE", ""); + PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, originalDefines); + AssetDatabase.SaveAssets(); +#endif + EditorApplication.Exit(0); + } +} +``` diff --git a/Documentation~/build-scripting-start-build.md b/Documentation~/build-scripting-start-build.md index 377499b9..338877f4 100644 --- a/Documentation~/build-scripting-start-build.md +++ b/Documentation~/build-scripting-start-build.md @@ -1,78 +1,78 @@ -# Start a build from a script - -To start a build from another script, call the [`AddressableAssetSettings.BuildPlayerContent`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.BuildPlayerContent*) method. - -Before starting the build, set the active [Profile](AddressableAssetsProfiles.md) and the active build script. You can also set a different [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings) object than the default. - -`BuildPlayerContent` takes into consideration the following information when performing the build: - -* [`AddressableAssetSettingsDefaultObject`](xref:UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject) -* [`ActivePlayerDataBuilder`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.ActivePlayerDataBuilder) -* The `addressables_content_state.bin` file. - -## Set the AddressableAssetSettings - -The settings defined by [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings) include the list of [groups](Groups.md) and the [profile](profiles-introduction.md) to use. - -To access the settings that displayed in the Editor (menu: __Window > Asset Management > Addressables > Settings__), use the static [`AddressableAssetSettingsDefaultObject.Settings`](xref:UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject.Settings) property. However, if desired, you can use a different settings object for a build. - -To load a custom settings object in a build: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/BuildLauncher.cs#getSettingsObject)] - -## Set the active profile - -A build started with `BuildContent` uses the variable settings of the active profile. To set the active profile as part of your customized build script, assign the ID of the desired profile to the [`activeProfileId`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.activeProfileId) field of the [`AddressableAssetSettingsDefaultObject.Settings`](xref:UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject.Settings) object. - -The [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings) object contains the list of profiles. Use the name of the desired profile to look up its ID value and then assign the ID to the `activeProfileId` variable: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/BuildLauncher.cs#setProfile)] - -## Set the active build script - -The `BuildContent` method launches the build based on the current [`ActivePlayerDataBuilder`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.ActivePlayerDataBuilder) setting. To use a specific build script, assign the index of the `IDataBuilder` object in the [`AddressableAssetSetting.DataBuilders`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.DataBuilders) list to the [`ActivePlayerDataBuilderIndex`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.ActivePlayerDataBuilderIndex) property. - -The build script must be a `ScriptableObject` that implements [`IDataBuilder`]((xref:UnityEditor.AddressableAssets.Build.IDataBuilder)) and you must add it to the [`DataBuilders`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.DataBuilders) list in the [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings) instance. Once added to the list, use the standard [`List.IndexOf`](xref:System.Collections.Generic.List`1.IndexOf*) method to get the index of the object. - -[!code-cs[sample](../Tests/Editor/DocExampleCode/BuildLauncher.cs#setBuilder)] - -## Launch a build - -After setting the profile and builder to use, you can launch the build: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/BuildLauncher.cs#buildAddressableContent)] - -To check for success, use `BuildPlayerContent(out AddressablesPlayerBuildResult result)`. `result.Error` contains any error message returned if the Addressables build failed. If s`tring.IsNullOrEmpty(result.Error)` is true, the build was successful. - -### Example script to launch build - -The following example adds a couple of menu commands to the **Window > Asset Management > Addressables** menu in the Editor. The first command builds the Addressable content using the preset profile and build script. The second command builds the Addressable content, and, if it succeeds, builds the Player. - -If your build script makes setting changes that require a domain reload, you should run the build script using Unity command line options, instead of running it interactively in the Editor. Refer to [Domain reloads](#domain-reloads) for more information. - -[!code-cs[sample](../Tests/Editor/DocExampleCode/BuildLauncher.cs#doc_BuildLauncher)] - -## Domain reloads - -If your scripted build process involves changing settings that trigger a domain reload before it makes an Addressables build, then you should script such builds to use [Unity's command line arguments](xref:CommandLineArguments) rather than running a script in the Editor. These types of settings include: - -* Changing the defined compiler symbols -* Changing platform target or target group - -When you run a script that triggers a domain reload interactively in the Editor, such as using a menu command, your Editor script finishes executing before the domain reload happens. Therefore, if you immediately start an Addressables build, both your code and imported assets are still in their original state. You must wait for the domain reload to complete before you start the content build. - -It's best practice to wait for the domain reload to finish when you run the build from the command line, because it can be difficult or impossible to carry out reliably in an interactive script. - -The following example script defines two functions that can be invoked when running Unity on the command line. The `ChangeSettings` example sets the specified define symbols. The `BuildContentAndPlayer` function runs the Addressables build and the Player build. - -[!code-cs[sample](../Tests/Editor/DocExampleCode/BatchBuild.cs#doc_BatchBuild)] - -To call these functions, use [Unity's command line arguments](xref:CommandLineArguments) in a terminal or command prompt or in a shell script: - -``` -D:\Unity\2020.3.0f1\Editor\Unity.exe -quit -batchMode -projectPath . -executeMethod BatchBuild.ChangeSettings -defines=FOO;BAR -buildTarget Android -D:\Unity\2020.3.0f1\Editor\Unity.exe -quit -batchMode -projectPath . -executeMethod BatchBuild.BuildContentAndPlayer -buildTarget Android -``` - -> [!NOTE] -> If you specify the platform target as a command line parameter, you can perform an Addressables build in the same command. However, if you wanted to change the platform in a script, you should do it in a separate command, such as the `ChangeSettings` function in this example. +# Start a build from a script + +To start a build from another script, call the [`AddressableAssetSettings.BuildPlayerContent`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.BuildPlayerContent*) method. + +Before starting the build, set the active [Profile](AddressableAssetsProfiles.md) and the active build script. You can also set a different [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings) object than the default. + +`BuildPlayerContent` takes into consideration the following information when performing the build: + +* [`AddressableAssetSettingsDefaultObject`](xref:UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject) +* [`ActivePlayerDataBuilder`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.ActivePlayerDataBuilder) +* The `addressables_content_state.bin` file. + +## Set the AddressableAssetSettings + +The settings defined by [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings) include the list of [groups](Groups.md) and the [profile](profiles-introduction.md) to use. + +To access the settings that displayed in the Editor (menu: __Window > Asset Management > Addressables > Settings__), use the static [`AddressableAssetSettingsDefaultObject.Settings`](xref:UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject.Settings) property. However, if desired, you can use a different settings object for a build. + +To load a custom settings object in a build: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/BuildLauncher.cs#getSettingsObject)] + +## Set the active profile + +A build started with `BuildContent` uses the variable settings of the active profile. To set the active profile as part of your customized build script, assign the ID of the desired profile to the [`activeProfileId`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.activeProfileId) field of the [`AddressableAssetSettingsDefaultObject.Settings`](xref:UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject.Settings) object. + +The [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings) object contains the list of profiles. Use the name of the desired profile to look up its ID value and then assign the ID to the `activeProfileId` variable: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/BuildLauncher.cs#setProfile)] + +## Set the active build script + +The `BuildContent` method launches the build based on the current [`ActivePlayerDataBuilder`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.ActivePlayerDataBuilder) setting. To use a specific build script, assign the index of the `IDataBuilder` object in the [`AddressableAssetSetting.DataBuilders`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.DataBuilders) list to the [`ActivePlayerDataBuilderIndex`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.ActivePlayerDataBuilderIndex) property. + +The build script must be a `ScriptableObject` that implements [`IDataBuilder`]((xref:UnityEditor.AddressableAssets.Build.IDataBuilder)) and you must add it to the [`DataBuilders`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.DataBuilders) list in the [`AddressableAssetSettings`](xref:UnityEditor.AddressableAssets.Settings.AddressableAssetSettings) instance. Once added to the list, use the standard [`List.IndexOf`](xref:System.Collections.Generic.List`1.IndexOf*) method to get the index of the object. + +[!code-cs[sample](../Tests/Editor/DocExampleCode/BuildLauncher.cs#setBuilder)] + +## Launch a build + +After setting the profile and builder to use, you can launch the build: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/BuildLauncher.cs#buildAddressableContent)] + +To check for success, use `BuildPlayerContent(out AddressablesPlayerBuildResult result)`. `result.Error` contains any error message returned if the Addressables build failed. If s`tring.IsNullOrEmpty(result.Error)` is true, the build was successful. + +### Example script to launch build + +The following example adds a couple of menu commands to the **Window > Asset Management > Addressables** menu in the Editor. The first command builds the Addressable content using the preset profile and build script. The second command builds the Addressable content, and, if it succeeds, builds the Player. + +If your build script makes setting changes that require a domain reload, you should run the build script using Unity command line options, instead of running it interactively in the Editor. Refer to [Domain reloads](#domain-reloads) for more information. + +[!code-cs[sample](../Tests/Editor/DocExampleCode/BuildLauncher.cs#doc_BuildLauncher)] + +## Domain reloads + +If your scripted build process involves changing settings that trigger a domain reload before it makes an Addressables build, then you should script such builds to use [Unity's command line arguments](xref:CommandLineArguments) rather than running a script in the Editor. These types of settings include: + +* Changing the defined compiler symbols +* Changing platform target or target group + +When you run a script that triggers a domain reload interactively in the Editor, such as using a menu command, your Editor script finishes executing before the domain reload happens. Therefore, if you immediately start an Addressables build, both your code and imported assets are still in their original state. You must wait for the domain reload to complete before you start the content build. + +It's best practice to wait for the domain reload to finish when you run the build from the command line, because it can be difficult or impossible to carry out reliably in an interactive script. + +The following example script defines two functions that can be invoked when running Unity on the command line. The `ChangeSettings` example sets the specified define symbols. The `BuildContentAndPlayer` function runs the Addressables build and the Player build. + +[!code-cs[sample](../Tests/Editor/DocExampleCode/BatchBuild.cs#doc_BatchBuild)] + +To call these functions, use [Unity's command line arguments](xref:CommandLineArguments) in a terminal or command prompt or in a shell script: + +``` +D:\Unity\2020.3.0f1\Editor\Unity.exe -quit -batchMode -projectPath . -executeMethod BatchBuild.ChangeSettings -defines=FOO;BAR -buildTarget Android +D:\Unity\2020.3.0f1\Editor\Unity.exe -quit -batchMode -projectPath . -executeMethod BatchBuild.BuildContentAndPlayer -buildTarget Android +``` + +> [!NOTE] +> If you specify the platform target as a command line parameter, you can perform an Addressables build in the same command. However, if you wanted to change the platform in a script, you should do it in a separate command, such as the `ChangeSettings` function in this example. diff --git a/Documentation~/build-shared-assetbundles.md b/Documentation~/build-shared-assetbundles.md index 139790dd..567b9aa2 100644 --- a/Documentation~/build-shared-assetbundles.md +++ b/Documentation~/build-shared-assetbundles.md @@ -1,17 +1,17 @@ -# Shared AssetBundles - -In addition to the bundles created from your `AddressableAssetGroups`, a build can produce specialized bundles called shared AssetBundles. These are the `unitybuiltinshaders` AssetBundle and the `MonoScript` AssetBundle. - -## Built in shaders AssetBundle - -Unity generates `unitybuiltinshaders` if any built-in shaders are used by assets included in the build. All Addressable assets that reference a built-in shader, such as the Standard Shader, do so by referencing this specialized shader AssetBundle. - -You can change the naming method of the built-in shader bundle with the __Shader Bundle Naming Prefix__ option in [Addressables Build settings](xref:addressables-asset-settings). - -## MonoScript AssetBundle - -To enable or disable the `MonoScript` AssetBundle change the __MonoScript Bundle Naming Prefix__ option in [Addressables Build settings](xref:addressables-asset-settings). The `MonoScript` bundle has naming options listed here, which are typically used in multi-project situations. It is used to build `MonoScript` behaviors into AssetBundles that can be referenced as a dependency. - -Shared AssetBundles derive their build options from the default `AddressableAssetGroup`. By default this group is named **Default Local Group (Default)** and uses local build and load paths. In this case the shared bundles cannot be updated as part of a Content Update, and can only be changed in a new player build. - -The Check for Content Update Restrictions tool fails to detect the changes to the bundle because it is only generated during the content build. Therefore, if you plan on making content changes to the shared bundles in the future, set the default group to use remote build and load paths and set its [Update Restriction](xref:addressables-content-update-builds) to **Can Change Post Release**. +# Shared AssetBundles + +In addition to the bundles created from your `AddressableAssetGroups`, a build can produce specialized bundles called shared AssetBundles. These are the `unitybuiltinshaders` AssetBundle and the `MonoScript` AssetBundle. + +## Built in shaders AssetBundle + +Unity generates `unitybuiltinshaders` if any built-in shaders are used by assets included in the build. All Addressable assets that reference a built-in shader, such as the Standard Shader, do so by referencing this specialized shader AssetBundle. + +You can change the naming method of the built-in shader bundle with the __Shader Bundle Naming Prefix__ option in [Addressables Build settings](xref:addressables-asset-settings). + +## MonoScript AssetBundle + +To enable or disable the `MonoScript` AssetBundle change the __MonoScript Bundle Naming Prefix__ option in [Addressables Build settings](xref:addressables-asset-settings). The `MonoScript` bundle has naming options listed here, which are typically used in multi-project situations. It is used to build `MonoScript` behaviors into AssetBundles that can be referenced as a dependency. + +Shared AssetBundles derive their build options from the default `AddressableAssetGroup`. By default this group is named **Default Local Group (Default)** and uses local build and load paths. In this case the shared bundles cannot be updated as part of a Content Update, and can only be changed in a new player build. + +The Check for Content Update Restrictions tool fails to detect the changes to the bundle because it is only generated during the content build. Therefore, if you plan on making content changes to the shared bundles in the future, set the default group to use remote build and load paths and set its [Update Restriction](xref:addressables-content-update-builds) to **Can Change Post Release**. diff --git a/Documentation~/builds-full-build.md b/Documentation~/builds-full-build.md index ae903ab9..621a86dc 100644 --- a/Documentation~/builds-full-build.md +++ b/Documentation~/builds-full-build.md @@ -1,71 +1,71 @@ -# Create a full build - -To create a full build: - -1. Configure your project's [group settings](GroupSchemas.md). -1. If you're distributing content remotely, configure the [Profile](profiles-introduction.md) and [Addressables system settings](AddressableAssetSettings.md) to enable remote content distribution. -3. Select the correct Profile. -4. Launch the build from the [Groups window](GroupsWindow.md). - -> [!TIP] -> If you encounter build or runtime loading issues during development, run the __Clean > All__ command from the __Build__ menu before you rebuild your content. - -## Set up build and load paths - -A [Profile](profiles-introduction.md) defines separate variables for the build and load paths of local versus remote content. You can create multiple profiles to use different paths for different kinds of builds. For example, you might have a profile to use while you develop your Project in the Unity Editor and another for when you publish your final content builds. - -For most projects, you only need multiple profiles when you support remote content distribution. You don't typically need to change the local paths at different stages of your development process. Most projects should build local content to the default local build path and load it from the default local load path (which resolves to the StreamingAssets folder). - -### Windows file path limit - -Windows has a file path limit of 260 characters. If the build path of your content ends up creating a path that meets or exceeds the limit on Windows, the build fails. - -You might run into a file path limit issue if your project is located in a directory that is close to the character limit. The Scriptable Build Pipeline creates AssetBundles in a temporary directory during the build. This temporary path is a subdirectory of your project and the process can generate a `string` longer than the Windows limit. -If the Addressables content build fails with a `Could not find a part of the path` error, and you're on Windows, this might be the cause. - -### Default local paths - -The local build path defaults to the path provided by `Addressables.BuildPath`, which is in the Library folder of your Unity project. Addressables appends a folder to the local build path based on your current platform build target setting. When you build for multiple platforms, the build places the artifacts for each platform in a different subfolder. - -Likewise, the local load path defaults to that provided by `Addressables.RuntimePath`, which resolves to the StreamingAssets folder. Again Addressables adds the platform build target to the path. - -When you build your local bundles to the default build path, then the build code temporarily copies the artifacts from the build path to the StreamingAssets folder when you build your player, and removes them after the build. - -> [!WARNING] -> If you build to, or load from custom local paths, then you must copy your build artifacts to the correct place in your project before making a player build and to make sure your application can access those artifacts at runtime. - -### Default remote paths - -Addressables sets the default remote build path to an arbitrarily chosen folder name, `ServerData`, which is created under your Project folder. The build adds the current platform target to the path as a subfolder to separate the unique artifacts for different platforms. - -The default remote load path is `http://localhost/` appended with the current profile BuildTarget variable. You must change this path to the base URL at which you plan to load your Addressable assets. - -Use different [profiles](profiles-introduction.md) to set up the remote load path as appropriate for the type of development, testing, or publishing you are doing. For example, you might have a profile that loads assets from a localhost server for general development builds, a profile that loads assets from a staging environment for QA builds, and one that loads assets from your Content Delivery Network (CDN) for release builds. - -> [!NOTE] -> When running your game in the Editor, you can use the __Use Asset Database__ Play mode Script to bypass loading assets through the remote or local load paths. This can be convenient, especially when you don't have a localhost server set up. However, it can hide group configuration and asset assignment mistakes. - -## Set up remote content builds - -To set up a remote content build: - -1. Navigate to your AdressablesSystemSetting asset (menu: __Window > Asset Management > Addressables > Settings__). -2. Under __Catalog__, enable the __Build Remote Catalog__ option. -The __BuildPath__ and __LoadPath__ settings for the catalog must be the same as those you use for your remote groups. In most cases, use the RemoteBuildPath and RemoteLoadPath profile variables. -3. For each group that you want to build as remote content, set the __BuildPath__ and __LoadPath__ to the RemoteBuildPath and RemoteLoadPath profile variables (or a custom value if desired). -4. Open the [Profiles window] (menu: __Window > Asset Management > Addressables > Profiles__). -5. Set the RemoteLoadPath variable to the URL where you plan to host your remote content. -If you require different URLs for different types of builds, create a new Profile for each build type. Refer to [Profiles] and [Hosting] for more information. - -Refer to [Remote content distribution](RemoteContentDistribution.md) for additional information. - -## Perform the build - -After you have your group and Addressables system settings configured, you can run a content build: - -1. Open the [Groups window](GroupsWindow.md) (menu: __Windows > Asset Management > Addressables > Groups__). -2. Select the desired profile from the __Profile__ menu on the toolbar. -3. Select the __Default Build Script__ from the __Build > New Build__ menu. (If you have created your own build scripts they will also be available from this menu.) - -The Default Build Script creates one or more AssetBundles for each group and saves them to either the local or the remote build path. - +# Create a full build + +To create a full build: + +1. Configure your project's [group settings](GroupSchemas.md). +1. If you're distributing content remotely, configure the [Profile](profiles-introduction.md) and [Addressables system settings](AddressableAssetSettings.md) to enable remote content distribution. +3. Select the correct Profile. +4. Launch the build from the [Groups window](GroupsWindow.md). + +> [!TIP] +> If you encounter build or runtime loading issues during development, run the __Clean > All__ command from the __Build__ menu before you rebuild your content. + +## Set up build and load paths + +A [Profile](profiles-introduction.md) defines separate variables for the build and load paths of local versus remote content. You can create multiple profiles to use different paths for different kinds of builds. For example, you might have a profile to use while you develop your Project in the Unity Editor and another for when you publish your final content builds. + +For most projects, you only need multiple profiles when you support remote content distribution. You don't typically need to change the local paths at different stages of your development process. Most projects should build local content to the default local build path and load it from the default local load path (which resolves to the StreamingAssets folder). + +### Windows file path limit + +Windows has a file path limit of 260 characters. If the build path of your content ends up creating a path that meets or exceeds the limit on Windows, the build fails. + +You might run into a file path limit issue if your project is located in a directory that is close to the character limit. The Scriptable Build Pipeline creates AssetBundles in a temporary directory during the build. This temporary path is a subdirectory of your project and the process can generate a `string` longer than the Windows limit. +If the Addressables content build fails with a `Could not find a part of the path` error, and you're on Windows, this might be the cause. + +### Default local paths + +The local build path defaults to the path provided by `Addressables.BuildPath`, which is in the Library folder of your Unity project. Addressables appends a folder to the local build path based on your current platform build target setting. When you build for multiple platforms, the build places the artifacts for each platform in a different subfolder. + +Likewise, the local load path defaults to that provided by `Addressables.RuntimePath`, which resolves to the StreamingAssets folder. Again Addressables adds the platform build target to the path. + +When you build your local bundles to the default build path, then the build code temporarily copies the artifacts from the build path to the StreamingAssets folder when you build your player, and removes them after the build. + +> [!WARNING] +> If you build to, or load from custom local paths, then you must copy your build artifacts to the correct place in your project before making a player build and to make sure your application can access those artifacts at runtime. + +### Default remote paths + +Addressables sets the default remote build path to an arbitrarily chosen folder name, `ServerData`, which is created under your Project folder. The build adds the current platform target to the path as a subfolder to separate the unique artifacts for different platforms. + +The default remote load path is `http://localhost/` appended with the current profile BuildTarget variable. You must change this path to the base URL at which you plan to load your Addressable assets. + +Use different [profiles](profiles-introduction.md) to set up the remote load path as appropriate for the type of development, testing, or publishing you are doing. For example, you might have a profile that loads assets from a localhost server for general development builds, a profile that loads assets from a staging environment for QA builds, and one that loads assets from your Content Delivery Network (CDN) for release builds. + +> [!NOTE] +> When running your game in the Editor, you can use the __Use Asset Database__ Play mode Script to bypass loading assets through the remote or local load paths. This can be convenient, especially when you don't have a localhost server set up. However, it can hide group configuration and asset assignment mistakes. + +## Set up remote content builds + +To set up a remote content build: + +1. Navigate to your AdressablesSystemSetting asset (menu: __Window > Asset Management > Addressables > Settings__). +2. Under __Catalog__, enable the __Build Remote Catalog__ option. +The __BuildPath__ and __LoadPath__ settings for the catalog must be the same as those you use for your remote groups. In most cases, use the RemoteBuildPath and RemoteLoadPath profile variables. +3. For each group that you want to build as remote content, set the __BuildPath__ and __LoadPath__ to the RemoteBuildPath and RemoteLoadPath profile variables (or a custom value if desired). +4. Open the [Profiles window] (menu: __Window > Asset Management > Addressables > Profiles__). +5. Set the RemoteLoadPath variable to the URL where you plan to host your remote content. +If you require different URLs for different types of builds, create a new Profile for each build type. Refer to [Profiles] and [Hosting] for more information. + +Refer to [Remote content distribution](RemoteContentDistribution.md) for additional information. + +## Perform the build + +After you have your group and Addressables system settings configured, you can run a content build: + +1. Open the [Groups window](GroupsWindow.md) (menu: __Windows > Asset Management > Addressables > Groups__). +2. Select the desired profile from the __Profile__ menu on the toolbar. +3. Select the __Default Build Script__ from the __Build > New Build__ menu. (If you have created your own build scripts they will also be available from this menu.) + +The Default Build Script creates one or more AssetBundles for each group and saves them to either the local or the remote build path. + diff --git a/Documentation~/builds-update-build.md b/Documentation~/builds-update-build.md index 037dd7c7..e059c52f 100644 --- a/Documentation~/builds-update-build.md +++ b/Documentation~/builds-update-build.md @@ -1,38 +1,38 @@ -# Create an update build - -When you distribute content remotely, you can perform a differential update of the previously published build to minimize the amount of data your users must download (compared to a full build). - -Once you have configured your remote groups properly and have a previous build which contains remote content, you can perform a content update build by: - -1. Open the [Groups window](GroupsWindow.md) (menu: __Windows > Asset Management > Addressables > Groups__). -2. Select the desired profile from the __Profile__ menu on the toolbar. -3. Select the __Update a Previous Build__ from the __Build__ menu. -4. Locate the `addressables_content_state.bin` file produced by the build you are updating. (The default location is in your `Assets/AddressableAssetsData/TargetPlatform` folder.) -5. Click __Open__ to start the update build. - -To update existing clients, copy the updated remote content to your hosting service (after appropriate testing). (An update build does include all of your local and remote content -- any player builds you create after a content update build will contain a complete set of Addressable assets.) - -Updating a previous build does not change the `addressables_content_state.bin` file. Use the same version of the file for future update builds (until you publish another full build created from the __New Build__ menu). - -See [Content Update Builds](ContentUpdateWorkflow.md) for information on how and when to use content update builds. - -## Minimize changes to bundles - -Content bundles can be large, and having to update the whole bundle for small changes can result in a large amount of data being updated for a small change to the MonoScript. - -Enabling the **MonoScript Bundle Naming Prefix** option in the [Addressables settings](xref:addressables-asset-settings) will build an AssetBundle that contains the MonoScript objects, separate to your serialized data. -If there are no changes to the serialized class data then only the MonoScript bundle will have changed and other bundles will not need to be updated. - -## Changes to scripts that require rebuilding Addressables - -Unity references classes in Addressables content using a MonoScript object. This object defines a class using the Assembly name, [Namespace](https://docs.unity3d.com/Manual/Namespaces.html), and either the class name or the referenced class. - -When loading content at runtime, Unity uses the MonoScript to load and create an instance of the runtime class from the player assemblies. - -Changes to MonoScripts need to be consistent between the Player and the built Addressables content. You must rebuild both the Player content and Addressables content to load the classes correctly. - -The following actions can result in changes to the MonoScript data: -- Moving the script file to a location that comes under another [assembly definition file](https://docs.unity3d.com/Manual/ScriptCompilationAssemblyDefinitionFiles.html) -- Changing the name of the assembly definition file containing the class -- Adding or Changing the class namespace -- Changing the class name +# Create an update build + +When you distribute content remotely, you can perform a differential update of the previously published build to minimize the amount of data your users must download (compared to a full build). + +Once you have configured your remote groups properly and have a previous build which contains remote content, you can perform a content update build by: + +1. Open the [Groups window](GroupsWindow.md) (menu: __Windows > Asset Management > Addressables > Groups__). +2. Select the desired profile from the __Profile__ menu on the toolbar. +3. Select the __Update a Previous Build__ from the __Build__ menu. +4. Locate the `addressables_content_state.bin` file produced by the build you are updating. (The default location is in your `Assets/AddressableAssetsData/TargetPlatform` folder.) +5. Click __Open__ to start the update build. + +To update existing clients, copy the updated remote content to your hosting service (after appropriate testing). (An update build does include all of your local and remote content -- any player builds you create after a content update build will contain a complete set of Addressable assets.) + +Updating a previous build does not change the `addressables_content_state.bin` file. Use the same version of the file for future update builds (until you publish another full build created from the __New Build__ menu). + +See [Content Update Builds](ContentUpdateWorkflow.md) for information on how and when to use content update builds. + +## Minimize changes to bundles + +Content bundles can be large, and having to update the whole bundle for small changes can result in a large amount of data being updated for a small change to the MonoScript. + +Enabling the **MonoScript Bundle Naming Prefix** option in the [Addressables settings](xref:addressables-asset-settings) will build an AssetBundle that contains the MonoScript objects, separate to your serialized data. +If there are no changes to the serialized class data then only the MonoScript bundle will have changed and other bundles will not need to be updated. + +## Changes to scripts that require rebuilding Addressables + +Unity references classes in Addressables content using a MonoScript object. This object defines a class using the Assembly name, [Namespace](https://docs.unity3d.com/Manual/Namespaces.html), and either the class name or the referenced class. + +When loading content at runtime, Unity uses the MonoScript to load and create an instance of the runtime class from the player assemblies. + +Changes to MonoScripts need to be consistent between the Player and the built Addressables content. You must rebuild both the Player content and Addressables content to load the classes correctly. + +The following actions can result in changes to the MonoScript data: +- Moving the script file to a location that comes under another [assembly definition file](https://docs.unity3d.com/Manual/ScriptCompilationAssemblyDefinitionFiles.html) +- Changing the name of the assembly definition file containing the class +- Adding or Changing the class namespace +- Changing the class name diff --git a/Documentation~/config.json b/Documentation~/config.json index caefc34b..b7a00830 100644 --- a/Documentation~/config.json +++ b/Documentation~/config.json @@ -1 +1 @@ -{ "DefineConstants": "UNITY_2021_2_OR_NEWER" } +{ "DefineConstants": "UNITY_2021_2_OR_NEWER" } diff --git a/Documentation~/content-update-build-create.md b/Documentation~/content-update-build-create.md index 60d3cff0..0661532d 100644 --- a/Documentation~/content-update-build-create.md +++ b/Documentation~/content-update-build-create.md @@ -1,45 +1,50 @@ -# Build a content update - -There are two tools you need to run to create a content update build: - -1. The [Check for Content Update Restrictions tool](#check-for-content-update-restrictions-tool) -2. The [Update a Previous Build script](#update-a-previous-build) - -The Check For Content Update Restrictions tool prepares your groups for a new content build. The Update a Previous Build script performs the build. - -The build generates a content catalog, a hash file, and AssetBundles. - -The generated content catalog has the same name as the catalog in the original application build, overwriting the old catalog and hash file. The application loads the hash file at runtime to decide if a new catalog is available. The system loads unmodified assets from existing bundles that shipped with the application or that the application has already downloaded. - -The system uses the content version string and location information from the addressables_content_state.bin file to create the AssetBundles. Asset bundles that don't contain updated content are written using the same file names as those in the build selected for the update. If an AssetBundle contains updated content, a new bundle is generated that contains the updated content, with a new file name so that it can coexist with the original on your content hosting service. Only AssetBundles with new file names must be copied to the location that hosts your content though you can safely upload them all. - -The system also builds AssetBundles for content that can't change, such as any local AssetBundles, but you don't need to upload them to the content hosting location, as no Addressables Asset entries reference them. - -You shouldn't change the build scripts between building a new player and making content updates, such as player code or Addressables. This might cause unpredictable behavior in your application. - -If you delete the local content bundles created by your Addressables build from the Project Library folder, attempts to load Assets in those bundles fail when you run your game or application in the Unity Editor and use the __Use Existing Build (requires built groups)__ Play mode script. - -## Update a Previous Build -Before you can build a content update, you need to run the __Update a Previous Build__ script. To run this script: - -1. Open the __Addressables Groups__ window in the Editor (__Window__ > __Asset Management__ > __Addressables__ > __Groups__). -2. From the __Build__ menu on the toolbar, run the __Update a Previous Build__ script. - -If you don't want the __Update a Previous Build__ script to run the [Check for Content Update Restrictions](#check-for-content-update-restrictions-tool) check automatically, run the tool manually before you begin your build. - -## Check for Content Update Restrictions tool - -The __Check for Content Update Restrictions__ tool prepares your group organization for a content update build. The tool examines the `addressables_content_state.bin` file and group settings. - ->[!IMPORTANT] -> Before you run the __Check for Content Update Restrictions__ tool, make a new branch with your version control system. The tool rearranges your asset groups in a way suited for updating content. Branching ensures that next time you ship a full player build, you can return to your preferred content arrangement. - -If you set a group's __Update Restrictions__ property to __Prevent Updates__ in the previous build, the tool gives you the option to move any changed assets to a new remote group. Apply the suggested changes, or revert changes to these assets, unless you have a specific reason not to. - -When you create the update build, the new catalog maps the changed assets to their new, remote AssetBundles, while still mapping the unchanged assets to their original AssetBundles. Checking for content update restrictions doesn't check groups with __Prevent Updates__ disabled. - -To run the tool: - -1. Open the __Addressables Groups__ window in the Unity Editor (__Window__ > __Asset Management__ > __Addressables__ > __Groups__). -2. In the groups window, run the __Check for Content Update Restrictions__ from the toolbar __Tools__ menu. -3. Review the group changes made by the tool, if desired. You can change the names of any new remote groups the tool created, but moving assets to different groups can have unintended consequences. +# Build a content update + +There are two tools you need to run to create a content update build: + +1. The [Check for Content Update Restrictions tool](#check-for-content-update-restrictions-tool) +2. The [Update a Previous Build script](#update-a-previous-build) + +The Check For Content Update Restrictions tool prepares your groups for a new content build. The Update a Previous Build script performs the build. + +The build generates a content catalog, a hash file, and AssetBundles. + +The generated content catalog has the same name as the catalog in the original application build, overwriting the old catalog and hash file. The application loads the hash file at runtime to decide if a new catalog is available. The system loads unmodified assets from existing bundles that shipped with the application or that the application has already downloaded. + +The system uses the content version string and location information from the addressables_content_state.bin file to create the AssetBundles. Asset bundles that don't contain updated content are written using the same file names as those in the build selected for the update. If an AssetBundle contains updated content, a new bundle is generated that contains the updated content, with a new file name so that it can coexist with the original on your content hosting service. Only AssetBundles with new file names must be copied to the location that hosts your content though you can safely upload them all. + +The system also builds AssetBundles for content that can't change, such as any local AssetBundles, but you don't need to upload them to the content hosting location, as no Addressables Asset entries reference them. + +You shouldn't change the build scripts between building a new player and making content updates, such as player code or Addressables. This might cause unpredictable behavior in your application. + +If you delete the local content bundles created by your Addressables build from the Project Library folder, attempts to load Assets in those bundles fail when you run your game or application in the Unity Editor and use the __Use Existing Build (requires built groups)__ Play mode script. + +## Update a Previous Build +Before you can build a content update, you need to run the __Update a Previous Build__ script. To run this script: + +1. Open the __Addressables Groups__ window in the Editor (__Window__ > __Asset Management__ > __Addressables__ > __Groups__). +2. From the __Build__ menu on the toolbar, run the __Update a Previous Build__ script. + +If you don't want the __Update a Previous Build__ script to run the [Check for Content Update Restrictions](#check-for-content-update-restrictions-tool) check automatically, run the tool manually before you begin your build. + +## Check for Content Update Restrictions tool + +The __Check for Content Update Restrictions__ tool prepares your group organization for a content update build. The tool examines the `addressables_content_state.bin` file and group settings. + +>[!IMPORTANT] +> Before you run the __Check for Content Update Restrictions__ tool, make a new branch with your version control system. The tool rearranges your asset groups in a way suited for updating content. Branching ensures that next time you ship a full player build, you can return to your preferred content arrangement. + +If you set a group's __Update Restrictions__ property to __Prevent Updates__ in the previous build, the tool gives you the option to move any changed assets to a new remote group. Apply the suggested changes, or revert changes to these assets, unless you have a specific reason not to. + +When you create the update build, the new catalog maps the changed assets to their new, remote AssetBundles, while still mapping the unchanged assets to their original AssetBundles. Checking for content update restrictions doesn't check groups with __Prevent Updates__ disabled. + +An asset is considered as changed based on the hash returned by [AssetDatabase.GetAssetDependencyHash]. This editor API has limitations and may not accurately reflect AssetBundle changes that are calculated at build time. For example it computes hash of the content of .cs files. This means that performing whitespace changes in a .cs file will result in a different hash, but the actual AssetBundle containing the file is unchanged. See [Changes to scripts that require rebuilding Addressables] for more information. + +To run the tool: + +1. Open the __Addressables Groups__ window in the Unity Editor (__Window__ > __Asset Management__ > __Addressables__ > __Groups__). +2. In the groups window, run the __Check for Content Update Restrictions__ from the toolbar __Tools__ menu. +3. Review the group changes made by the tool, if desired. You can change the names of any new remote groups the tool created, but moving assets to different groups can have unintended consequences. + +[AssetDatabase.GetAssetDependencyHash](xref:UnityEditor.AssetDatabase.GetAssetDependencyHash(System.String)) +[Changes to scripts that require rebuilding Addressables](builds-update-build.md##changes-to-scripts-that-require-rebuilding-addressabes) diff --git a/Documentation~/content-update-build-settings.md b/Documentation~/content-update-build-settings.md index 82e77dd0..8faedb20 100644 --- a/Documentation~/content-update-build-settings.md +++ b/Documentation~/content-update-build-settings.md @@ -1,68 +1,68 @@ -# Content update build settings - -To publish content updates, your application must already use a remote catalog and host its remote content on an accessible server. Refer to [Enabling remote distribution](xref:addressables-remote-content-distribution) for information about setting up content hosting and distribution. - -You should also consider how to set each group's __Update Restriction__ settings. These settings determine how the __Check for Content Update Restriction__ tool treats changed content in your groups. Choose appropriate settings to help minimize the download size of your content updates. - -For more information, refer to [Group Update Restriction settings](#group-update-restriction-settings). - -## Update a Previous Build setting - -The [Addressable Asset Settings](AddressableAssetSettings.md) also has a section for updating a previous build: - -![](images/update-a-previous-build.png) - -|**Setting**|**Description**| -|---|---| -| __Check For Update Issues__| Informs the system on whether to run the __Check For Content Update Restrictions__ check automatically, and how to handle any issues the system detects.| -|__Content State Build Path__| This location serves two purposes:

- Indicates where new Content Builds put the previous state file.
- This is the location that the __Update a Previous Build__ process attempts to pull the previous state file from automatically.| - -The __Content State Build Path__ can be a remote location, if you want to have a shared previous state file on a server. The system handles remote locations for the previous state file differently: - -* New content builds place the previous state file to the `ContentUpdateScript.PreviousContentStateFileCachePath`, which is `Library/com.unity.addressables/AddressablesBinFileDownload/` by default. -* Update a Previous Build downloads the remote previous state file to `ContentUpdateScript.PreviousContentStateFileCachePath` and then reads the file like normal. If the file doesn't exist at the remote location, but one has already been placed in the cache path, the system loads the local file. - -## Group Update Restriction settings - -For each group in your project, the __Update Restriction__ schema determines how a content update handles the group and its assets as follows: - -* __Prevent Updates__: When enabled, the system treats assets in that group as static content that you expect to update infrequently, if at all. Use this setting for all local content. - -Choose the setting based on the content type in a group and how often you expect to update that content between full player builds of your application. - -You can change content in a group no matter which setting you choose. The difference is how the __Check for Content Update Restrictions__ and __Update Previous Build__ tools treat the assets in the group and how the installed applications access the updated content. - -> [!IMPORTANT] -> Don't change the __Update Restriction__ setting of a group unless you are performing a full build. If you change your group settings before a content update, the Addressables system can't generate the correct changes needed for the update build. - -### Prevent Updates Enabled (static content) - -When you enable __Prevent Updates__, the __Check for Content Update Restrictions__ tool moves any changed assets to a new group, which is set to build and load from your remote paths. This is the same check that can be automatically integrated with Updating a Previous Build. Regardless of if you manually run the tool, or let __Update a Previous Build__ handle the check automatically, the content update sets up the remote catalog so that the changed assets are accessed from the new bundles, but the unchanged assets are still accessed from the original bundles. - -> [!NOTE] -> Although the update build produces versions of the original bundles without the changed assets, installed applications don't download these bundles unless the locally cached version is deleted for some reason. - -Organize content that you don't expect to update often into groups with the __Prevent Updates__ property enabled. You can safely set up these groups to produce fewer, larger bundles because your users usually won't need to download these bundles more than once. - -Enable the __Prevent Updates__ property for any groups that you intend to load from the local load path and for any groups that produce large, remote bundles. This only requires your users to download changed assets when assets in the group change. - -### Prevent Updates Disabled (dynamic content) - -When a group doesn't have __Prevent Updates__ enabled, then a content update rebuilds the entire bundle if any assets inside the group have changed. The __Update a Previous Build__ script sets up the catalog so that installed applications load all assets in the group from the new bundles. - -Organize content you expect to change often into groups with __Prevent Updates__ disabled. The Addressables system republishes all the assets in these groups when any single asset changes. To minimize the number of assets that need republishing, set up these groups to produce smaller bundles containing fewer assets. - -## Unique Bundle IDs setting - -If you want to update content at runtime rather than at application startup, use the __Unique Bundle IDs__ setting. Enabling this setting can make it easier to load updated AssetBundles in the middle of an application session, but can make builds slower and updates larger. - -With this setting enabled, you can load a changed version of an AssetBundle while the original bundle is still in memory. Building your AssetBundles with unique internal IDs makes it easier to update content at runtime without creating AssetBundle ID conflicts. - -However, when enabled, any AssetBundles containing assets that reference a changed asset must also be rebuilt. More bundles must be updated for a content update and all builds are slower. - -You typically only need to use unique bundle IDs when you update content catalogs after the Addressable system has already initialized and you have started loading assets. - -You can avoid AssetBundle loading conflicts and the need to enable unique IDs using one of the following methods: - -* Update the content catalog as part of Addressables initialization. By default, Addressables checks for a new catalog at initialization as long as you don't enable the [Only update catalogs manually](xref:addressables-asset-settings) option in Addressable Asset settings. Choosing this method does preclude updating your application content in mid-session. -* Unload all remote AssetBundles before updating the content catalog. Unloading all your remote bundles and assets also avoids bundle name conflicts, but could interrupt your user's session while they wait for the new content to load. +# Content update build settings + +To publish content updates, your application must already use a remote catalog and host its remote content on an accessible server. Refer to [Enabling remote distribution](xref:addressables-remote-content-distribution) for information about setting up content hosting and distribution. + +You should also consider how to set each group's __Update Restriction__ settings. These settings determine how the __Check for Content Update Restriction__ tool treats changed content in your groups. Choose appropriate settings to help minimize the download size of your content updates. + +For more information, refer to [Group Update Restriction settings](#group-update-restriction-settings). + +## Update a Previous Build setting + +The [Addressable Asset Settings](AddressableAssetSettings.md) also has a section for updating a previous build: + +![](images/update-a-previous-build.png) + +|**Setting**|**Description**| +|---|---| +| __Check For Update Issues__| Informs the system on whether to run the __Check For Content Update Restrictions__ check automatically, and how to handle any issues the system detects.| +|__Content State Build Path__| This location serves two purposes:

- Indicates where new Content Builds put the previous state file.
- This is the location that the __Update a Previous Build__ process attempts to pull the previous state file from automatically.| + +The __Content State Build Path__ can be a remote location, if you want to have a shared previous state file on a server. The system handles remote locations for the previous state file differently: + +* New content builds place the previous state file to the `ContentUpdateScript.PreviousContentStateFileCachePath`, which is `Library/com.unity.addressables/AddressablesBinFileDownload/` by default. +* Update a Previous Build downloads the remote previous state file to `ContentUpdateScript.PreviousContentStateFileCachePath` and then reads the file like normal. If the file doesn't exist at the remote location, but one has already been placed in the cache path, the system loads the local file. + +## Group Update Restriction settings + +For each group in your project, the __Update Restriction__ schema determines how a content update handles the group and its assets as follows: + +* __Prevent Updates__: When enabled, the system treats assets in that group as static content that you expect to update infrequently, if at all. Use this setting for all local content. + +Choose the setting based on the content type in a group and how often you expect to update that content between full player builds of your application. + +You can change content in a group no matter which setting you choose. The difference is how the __Check for Content Update Restrictions__ and __Update Previous Build__ tools treat the assets in the group and how the installed applications access the updated content. + +> [!IMPORTANT] +> Don't change the __Update Restriction__ setting of a group unless you are performing a full build. If you change your group settings before a content update, the Addressables system can't generate the correct changes needed for the update build. + +### Prevent Updates Enabled (static content) + +When you enable __Prevent Updates__, the __Check for Content Update Restrictions__ tool moves any changed assets to a new group, which is set to build and load from your remote paths. This is the same check that can be automatically integrated with Updating a Previous Build. Regardless of if you manually run the tool, or let __Update a Previous Build__ handle the check automatically, the content update sets up the remote catalog so that the changed assets are accessed from the new bundles, but the unchanged assets are still accessed from the original bundles. + +> [!NOTE] +> Although the update build produces versions of the original bundles without the changed assets, installed applications don't download these bundles unless the locally cached version is deleted for some reason. + +Organize content that you don't expect to update often into groups with the __Prevent Updates__ property enabled. You can safely set up these groups to produce fewer, larger bundles because your users usually won't need to download these bundles more than once. + +Enable the __Prevent Updates__ property for any groups that you intend to load from the local load path and for any groups that produce large, remote bundles. This only requires your users to download changed assets when assets in the group change. + +### Prevent Updates Disabled (dynamic content) + +When a group doesn't have __Prevent Updates__ enabled, then a content update rebuilds the entire bundle if any assets inside the group have changed. The __Update a Previous Build__ script sets up the catalog so that installed applications load all assets in the group from the new bundles. + +Organize content you expect to change often into groups with __Prevent Updates__ disabled. The Addressables system republishes all the assets in these groups when any single asset changes. To minimize the number of assets that need republishing, set up these groups to produce smaller bundles containing fewer assets. + +## Unique Bundle IDs setting + +If you want to update content at runtime rather than at application startup, use the __Unique Bundle IDs__ setting. Enabling this setting can make it easier to load updated AssetBundles in the middle of an application session, but can make builds slower and updates larger. + +With this setting enabled, you can load a changed version of an AssetBundle while the original bundle is still in memory. Building your AssetBundles with unique internal IDs makes it easier to update content at runtime without creating AssetBundle ID conflicts. + +However, when enabled, any AssetBundles containing assets that reference a changed asset must also be rebuilt. More bundles must be updated for a content update and all builds are slower. + +You typically only need to use unique bundle IDs when you update content catalogs after the Addressable system has already initialized and you have started loading assets. + +You can avoid AssetBundle loading conflicts and the need to enable unique IDs using one of the following methods: + +* Update the content catalog as part of Addressables initialization. By default, Addressables checks for a new catalog at initialization as long as you don't enable the [Only update catalogs manually](xref:addressables-asset-settings) option in Addressable Asset settings. Choosing this method does preclude updating your application content in mid-session. +* Unload all remote AssetBundles before updating the content catalog. Unloading all your remote bundles and assets also avoids bundle name conflicts, but could interrupt your user's session while they wait for the new content to load. diff --git a/Documentation~/content-update-builds-check.md b/Documentation~/content-update-builds-check.md index f6e111e5..5f479b51 100644 --- a/Documentation~/content-update-builds-check.md +++ b/Documentation~/content-update-builds-check.md @@ -1,29 +1,29 @@ -# Check for content updates at runtime - -You can add a custom script to periodically check whether there are new Addressables content updates. Use the following function call to start the update: - -```c# -[public static AsyncOperationHandle\\> CheckForCatalogUpdates(bool autoReleaseHandle = true)] -``` - -`List\` contains the list of modified locator IDs. You can filter this list to only update specific IDs, or pass it entirely into the UpdateCatalogs API. - -If there is new content, you can either present the user with a button to perform the update, or do it automatically. It's up to you to make sure that stale Assets are released. - -The list of catalogs can be null and if so, the following script updates all catalogs that need an update: - -```c# -[public static AsyncOperationHandle\\> UpdateCatalogs(IEnumerable\ catalogs = null, bool autoReleaseHandle = true)] -``` - -The return value is the list of updated locators. - -You might also want to remove any bundle cache entries that are no longer referenced as a result of updating the catalogs. If so, use this version of the `UpdateCatalogs` API instead where you can enable the additional parameter `autoCleanBundleCache` to remove any unneeded cache data: - -```c# -[public static AsyncOperationHandle\\> UpdateCatalogs(bool autoCleanBundleCache, IEnumerable\ catalogs = null, bool autoReleaseHandle = true)] -``` - -Refer to [AssetBundle caching](xref:addressables-remote-content-distribution) for additional information about the bundle cache. - +# Check for content updates at runtime + +You can add a custom script to periodically check whether there are new Addressables content updates. Use the following function call to start the update: + +```c# +[public static AsyncOperationHandle\\> CheckForCatalogUpdates(bool autoReleaseHandle = true)] +``` + +`List\` contains the list of modified locator IDs. You can filter this list to only update specific IDs, or pass it entirely into the UpdateCatalogs API. + +If there is new content, you can either present the user with a button to perform the update, or do it automatically. It's up to you to make sure that stale Assets are released. + +The list of catalogs can be null and if so, the following script updates all catalogs that need an update: + +```c# +[public static AsyncOperationHandle\\> UpdateCatalogs(IEnumerable\ catalogs = null, bool autoReleaseHandle = true)] +``` + +The return value is the list of updated locators. + +You might also want to remove any bundle cache entries that are no longer referenced as a result of updating the catalogs. If so, use this version of the `UpdateCatalogs` API instead where you can enable the additional parameter `autoCleanBundleCache` to remove any unneeded cache data: + +```c# +[public static AsyncOperationHandle\\> UpdateCatalogs(bool autoCleanBundleCache, IEnumerable\ catalogs = null, bool autoReleaseHandle = true)] +``` + +Refer to [AssetBundle caching](xref:addressables-remote-content-distribution) for additional information about the bundle cache. + Refer to [Unique Bundle IDs setting](content-update-build-settings.md) for additional information about updating content at runtime. \ No newline at end of file diff --git a/Documentation~/content-update-builds-overview.md b/Documentation~/content-update-builds-overview.md index a987cd34..21cb4aa1 100644 --- a/Documentation~/content-update-builds-overview.md +++ b/Documentation~/content-update-builds-overview.md @@ -1,57 +1,57 @@ -# Content update builds overview - -When you distribute content remotely, you can make content changes without needing to rebuild and republish your entire application. Content update builds enables you to publish remote bundles that only contain assets that you've changed since the last update. - -When the Addressables system initializes at runtime, it checks for an updated content catalog. If one exists, the system downloads the new catalog and, when it loads assets, downloads the newer versions of all your AssetBundles. - -> [!IMPORTANT] -> You must enable the [Build Remote Catalog](xref:addressables-asset-settings) option before you publish a player build if you want to have the option to publish incremental updates. Without a remote catalog, an installed application doesn't check for updates. - -However, when you rebuild all your content with a new [content catalog](build-content-catalogs.md), installed players must also download all the remote AssetBundles again, whether the assets in them have changed or not. If you have a large amount of content, then downloading everything again can take a long time and might impact player retention. To make this process more efficient, the Addressables package provides tools that you can run to identify changed assets and to produce a content update build. - -The following diagram illustrates how you can use the Addressables tools to produce smaller content updates that only require your players to download new or changed content: - -![](images/addressables-update-builds.png)
*The workflow for reducing the size of content updates* - -## Content update build workflow - -When you release your full application, you first build the Addressables content and then make a player build. The player build contains local AssetBundles and you upload the remote AssetBundles to the Content Delivery Network (CDN) or other hosting service. - -The default build script that produces the Addressables content build always creates the `addressables_content_state.bin` file, which is required to efficiently publish content-only updates. You must save this file for each published full application release on every platform. - -> [!IMPORTANT] -> Addressables uses the `addressables_content_state.bin` file to identify which assets you changed. You must preserve a copy of this file for each published build. Without the file, you can only create a full content build, not an update. - -Between full application releases, which require your users to download and install a new player build, you can make changes to your Addressable assets in the project. Because AssetBundles don't include code, don't make code changes in the version of your project that you use to develop your asset changes. You can change both local and remote assets. - -## Content update tools - -The Addressables package includes tools that you can use to reduce the size of updates to the content you distribute remotely. - -The content update tools include: - -* [Check for Content Update Restrictions tool](content-update-build-create.md#check-for-content-update-restrictions-tool): Prepares your group organization for a content update build based on group settings -* [Update a Previous Build script](): A build script that performs the content update build - -You must save the `addressables_content_state.bin` file produced by the Default Build Script for each build that you intend to update in the future. This file is updated every time you run the build script. Make sure that you save the version produced for the content build that you publish. Refer to [Settings](content-update-build-settings.md) for relevant Addressable settings that handle the use of the previous content state file. - -> [!IMPORTANT] -> On platforms that have their own patching systems or that don't support remote content distribution, do not use content update builds. Every build of your game should be a complete fresh content build. In this case you can discard or ignore the `addressables_content_state.bin` file that's generated after each build for the platform. - -When you want publish a content update, run the __Check Content Update Restrictions__ tool manually, or make sure the check is run as part of the update build process. This check examines the `addressables_content_state.bin` file and moves changed assets to a new remote group, according to the settings of the group they are in. - -## Build updated content - -To build the updated AssetBundles, run the __Update a Previous Build__ script. This tool also uses the `addressables_content_state.bin` file. It rebuilds all of your content, but produces a modified catalog that accesses unchanged content from their original AssetBundles and changed content from the new AssetBundles. - -The final step is to upload the updated content to your CDN. You can upload all the new AssetBundles produced or just those with changed names. Bundles that haven't changed use the same names as the originals and will overwrite them. - -You can make additional content updates following the same process. Always use the `addressables_content_state.bin` file from your original release. - -Refer to [Building content updates](content-update-build-create.md) for step-by-step instructions. - -## When to perform a full rebuild - -Addressables can only distribute content, not code. As such, a code change requires a fresh player build, and usually a fresh build of content. Although a new player build can sometimes reuse old, existing content from a CDN, you must analyze whether the type trees in the existing AssetBundles are compatible with your new code. - -Note that Addressables itself is code, so updating Addressables or the Unity version requires that you create a new player build and fresh content builds. +# Content update builds overview + +When you distribute content remotely, you can make content changes without needing to rebuild and republish your entire application. Content update builds enables you to publish remote bundles that only contain assets that you've changed since the last update. + +When the Addressables system initializes at runtime, it checks for an updated content catalog. If one exists, the system downloads the new catalog and, when it loads assets, downloads the newer versions of all your AssetBundles. + +> [!IMPORTANT] +> You must enable the [Build Remote Catalog](xref:addressables-asset-settings) option before you publish a player build if you want to have the option to publish incremental updates. Without a remote catalog, an installed application doesn't check for updates. + +However, when you rebuild all your content with a new [content catalog](build-content-catalogs.md), installed players must also download all the remote AssetBundles again, whether the assets in them have changed or not. If you have a large amount of content, then downloading everything again can take a long time and might impact player retention. To make this process more efficient, the Addressables package provides tools that you can run to identify changed assets and to produce a content update build. + +The following diagram illustrates how you can use the Addressables tools to produce smaller content updates that only require your players to download new or changed content: + +![](images/addressables-update-builds.png)
*The workflow for reducing the size of content updates* + +## Content update build workflow + +When you release your full application, you first build the Addressables content and then make a player build. The player build contains local AssetBundles and you upload the remote AssetBundles to the Content Delivery Network (CDN) or other hosting service. + +The default build script that produces the Addressables content build always creates the `addressables_content_state.bin` file, which is required to efficiently publish content-only updates. You must save this file for each published full application release on every platform. + +> [!IMPORTANT] +> Addressables uses the `addressables_content_state.bin` file to identify which assets you changed. You must preserve a copy of this file for each published build. Without the file, you can only create a full content build, not an update. + +Between full application releases, which require your users to download and install a new player build, you can make changes to your Addressable assets in the project. Because AssetBundles don't include code, don't make code changes in the version of your project that you use to develop your asset changes. You can change both local and remote assets. + +## Content update tools + +The Addressables package includes tools that you can use to reduce the size of updates to the content you distribute remotely. + +The content update tools include: + +* [Check for Content Update Restrictions tool](content-update-build-create.md#check-for-content-update-restrictions-tool): Prepares your group organization for a content update build based on group settings +* [Update a Previous Build script](): A build script that performs the content update build + +You must save the `addressables_content_state.bin` file produced by the Default Build Script for each build that you intend to update in the future. This file is updated every time you run the build script. Make sure that you save the version produced for the content build that you publish. Refer to [Settings](content-update-build-settings.md) for relevant Addressable settings that handle the use of the previous content state file. + +> [!IMPORTANT] +> On platforms that have their own patching systems or that don't support remote content distribution, do not use content update builds. Every build of your game should be a complete fresh content build. In this case you can discard or ignore the `addressables_content_state.bin` file that's generated after each build for the platform. + +When you want publish a content update, run the __Check Content Update Restrictions__ tool manually, or make sure the check is run as part of the update build process. This check examines the `addressables_content_state.bin` file and moves changed assets to a new remote group, according to the settings of the group they are in. + +## Build updated content + +To build the updated AssetBundles, run the __Update a Previous Build__ script. This tool also uses the `addressables_content_state.bin` file. It rebuilds all of your content, but produces a modified catalog that accesses unchanged content from their original AssetBundles and changed content from the new AssetBundles. + +The final step is to upload the updated content to your CDN. You can upload all the new AssetBundles produced or just those with changed names. Bundles that haven't changed use the same names as the originals and will overwrite them. + +You can make additional content updates following the same process. Always use the `addressables_content_state.bin` file from your original release. + +Refer to [Building content updates](content-update-build-create.md) for step-by-step instructions. + +## When to perform a full rebuild + +Addressables can only distribute content, not code. As such, a code change requires a fresh player build, and usually a fresh build of content. Although a new player build can sometimes reuse old, existing content from a CDN, you must analyze whether the type trees in the existing AssetBundles are compatible with your new code. + +Note that Addressables itself is code, so updating Addressables or the Unity version requires that you create a new player build and fresh content builds. diff --git a/Documentation~/content-update-examples.md b/Documentation~/content-update-examples.md index 1f78065c..ce76c277 100644 --- a/Documentation~/content-update-examples.md +++ b/Documentation~/content-update-examples.md @@ -1,121 +1,121 @@ -# Content update examples - -The following discussion walks through a hypothetical example to illustrate how Addressable content is handled during a content update. In this example, consider a shipped application built with the following Addressables groups: - -| Local_Static| Remote_Static | Remote_NonStatic | -|:---|:---|:---| -| AssetA| AssetL | AssetX | -| AssetB| AssetM | AssetY | -| AssetC| AssetN | AssetZ | - -`Local_Static` and `Remote_Static` are part of the Cannot Change Post Release groups. - -Since this version is live, existing players have `Local_Static` on their devices, and potentially have either or both of the remote bundles cached locally. - -If you modify one Asset from each group (AssetA, AssetL, and AssetX), then run __Check for Content Update Restrictions__, the results in your local Addressable settings are now: - -| Local_Static| Remote_Static | Remote_NonStatic | content_update_group (non-static) | -|:---|:---|:---|:---| -| | | AssetX | AssetA | -| AssetB| AssetM | AssetY | AssetL | -| AssetC| AssetN | AssetZ | | - -The prepare operation edits the Cannot Change Post Release groups, which may seem counterintuitive. However, the system builds the above layout, but discards the build results for any such groups. As such, you end up with the following from a player's perspective: - -| Local_Static| -|:---| -| AssetA| -| AssetB| -| AssetC| - -The `Local_Static` bundle is already on player devices, which you can't change. This old version of AssetA is no longer referenced. Instead, it is stuck on player devices as dead data. - -| Remote_Static| -|:---| -| AssetL| -| AssetM| -| AssetN| - - -The `Remote_Static` bundle is unchanged. If it is not already cached on a player's device, it will download when AssetM or AssetN is requested. Like AssetA, this old version of AssetL is no longer referenced. - -| Remote_NonStatic (old)| -|:---| -| AssetX| -| AssetY| -| AssetZ| - -The `Remote_NonStatic` bundle is now old. You can delete it from the server or leave it there; either way it will not be downloaded from this point forward. If cached, it remains on player devices indefinitely unless you remove it. See [AssetBundle caching](xref:addressables-remote-content-distribution) for more information. Like AssetA and AssetL, this old version of AssetX is no longer referenced. - -| Remote_NonStatic (new)| -|:---| -| AssetX| -| AssetY| -| AssetZ| - -The old `Remote_NonStatic` bundle is replaced with a new version, distinguished by its hash file. The modified version of AssetX is updated with this new bundle. - -| content_update_group| -|:---| -| AssetA| -| AssetL| - -The `content_update_group` bundle consists of the modified Assets that will be referenced moving forward. - -The example above has the following implications: - -* Any changed local Assets remain unused on the user's device forever. -* If the user already cached a non-static bundle, they will need to redownload the bundle, including the unchanged Assets (in this instance, for example, AssetY and AssetZ). Ideally, the user has not cached the bundle, in which case they simply need to download the new Remote_NonStatic bundle. -* If the user has already cached the `Static_Remote` bundle, they only need to download the updated asset (in this instance, AssetL via `content_update_group`). This is ideal in this case. If the user has not cached the bundle, they must download both the new AssetL via `content_update_group` and the now-defunct AssetL via the untouched `Remote_Static` bundle. Regardless of the initial cache state, at some point the user will have the defunct AssetL on their device, cached indefinitely despite never being accessed. - -The best setup for your remote content will depend on your specific use case. - -## Content update dependencies - -Directly changing an asset is not the only way to have it flagged as needing to be rebuilt as part of a content update. Changing an asset's dependencies is a less obvious factor that gets taken into account when building an update. - -As an example, consider the `Local_Static` group from the example above: - -| Local_Static| -|:---| -| AssetA| -| AssetB| -| AssetC| - -Suppose the assets in this group have a dependency chain that looks like this: AssetA depends on Dependency1, which depends on Dependency2, AssetB depends on Dependency2, and AssetC depends on Dependency3 and all three dependencies are a mix of Addressable and non-Addressable assets. - -If only Dependency1 is changed and Check For Content Update Restriction is run, the resulting project structure looks like: - -| Local_Static| content_update_group | -|:---|:---| -| | AssetA | -| AssetB| | -| AssetC| | - -If only Dependency2 is changed: - -| Local_Static| content_update_group | -|:---|:---| -| | AssetA | -| | AssetB | -| AssetC| | - -Finally, if only Dependency3 is changed: - -| Local_Static| content_update_group | -|:---|:---| -| AssetA| | -| AssetB| | -| | AssetC | - -This is because when a dependency is changed the entire dependency tree needs to be rebuilt. - -The following example has this dependency tree. AssetA depends on AssetB, which depends on Dependency2, AssetB depends on Dependency2, and AssetC depends on Dependency3. Now, if Dependency2 is changed, the project structure looks like the following: - -| Local_Static| content_update_group | -|:---|:---| -| | AssetA | -| | AssetB | -| AssetC| | - -This is because AssetA relies on AssetB and AssetB relies on Dependency2. Since the entire chain needs to be rebuilt both AssetA and AssetB will get put into the __content_update_group__. +# Content update examples + +The following discussion walks through a hypothetical example to illustrate how Addressable content is handled during a content update. In this example, consider a shipped application built with the following Addressables groups: + +| Local_Static| Remote_Static | Remote_NonStatic | +|:---|:---|:---| +| AssetA| AssetL | AssetX | +| AssetB| AssetM | AssetY | +| AssetC| AssetN | AssetZ | + +`Local_Static` and `Remote_Static` are part of the Cannot Change Post Release groups. + +Since this version is live, existing players have `Local_Static` on their devices, and potentially have either or both of the remote bundles cached locally. + +If you modify one Asset from each group (AssetA, AssetL, and AssetX), then run __Check for Content Update Restrictions__, the results in your local Addressable settings are now: + +| Local_Static| Remote_Static | Remote_NonStatic | content_update_group (non-static) | +|:---|:---|:---|:---| +| | | AssetX | AssetA | +| AssetB| AssetM | AssetY | AssetL | +| AssetC| AssetN | AssetZ | | + +The prepare operation edits the Cannot Change Post Release groups, which may seem counterintuitive. However, the system builds the above layout, but discards the build results for any such groups. As such, you end up with the following from a player's perspective: + +| Local_Static| +|:---| +| AssetA| +| AssetB| +| AssetC| + +The `Local_Static` bundle is already on player devices, which you can't change. This old version of AssetA is no longer referenced. Instead, it is stuck on player devices as dead data. + +| Remote_Static| +|:---| +| AssetL| +| AssetM| +| AssetN| + + +The `Remote_Static` bundle is unchanged. If it is not already cached on a player's device, it will download when AssetM or AssetN is requested. Like AssetA, this old version of AssetL is no longer referenced. + +| Remote_NonStatic (old)| +|:---| +| AssetX| +| AssetY| +| AssetZ| + +The `Remote_NonStatic` bundle is now old. You can delete it from the server or leave it there; either way it will not be downloaded from this point forward. If cached, it remains on player devices indefinitely unless you remove it. See [AssetBundle caching](xref:addressables-remote-content-distribution) for more information. Like AssetA and AssetL, this old version of AssetX is no longer referenced. + +| Remote_NonStatic (new)| +|:---| +| AssetX| +| AssetY| +| AssetZ| + +The old `Remote_NonStatic` bundle is replaced with a new version, distinguished by its hash file. The modified version of AssetX is updated with this new bundle. + +| content_update_group| +|:---| +| AssetA| +| AssetL| + +The `content_update_group` bundle consists of the modified Assets that will be referenced moving forward. + +The example above has the following implications: + +* Any changed local Assets remain unused on the user's device forever. +* If the user already cached a non-static bundle, they will need to redownload the bundle, including the unchanged Assets (in this instance, for example, AssetY and AssetZ). Ideally, the user has not cached the bundle, in which case they simply need to download the new Remote_NonStatic bundle. +* If the user has already cached the `Static_Remote` bundle, they only need to download the updated asset (in this instance, AssetL via `content_update_group`). This is ideal in this case. If the user has not cached the bundle, they must download both the new AssetL via `content_update_group` and the now-defunct AssetL via the untouched `Remote_Static` bundle. Regardless of the initial cache state, at some point the user will have the defunct AssetL on their device, cached indefinitely despite never being accessed. + +The best setup for your remote content will depend on your specific use case. + +## Content update dependencies + +Directly changing an asset is not the only way to have it flagged as needing to be rebuilt as part of a content update. Changing an asset's dependencies is a less obvious factor that gets taken into account when building an update. + +As an example, consider the `Local_Static` group from the example above: + +| Local_Static| +|:---| +| AssetA| +| AssetB| +| AssetC| + +Suppose the assets in this group have a dependency chain that looks like this: AssetA depends on Dependency1, which depends on Dependency2, AssetB depends on Dependency2, and AssetC depends on Dependency3 and all three dependencies are a mix of Addressable and non-Addressable assets. + +If only Dependency1 is changed and Check For Content Update Restriction is run, the resulting project structure looks like: + +| Local_Static| content_update_group | +|:---|:---| +| | AssetA | +| AssetB| | +| AssetC| | + +If only Dependency2 is changed: + +| Local_Static| content_update_group | +|:---|:---| +| | AssetA | +| | AssetB | +| AssetC| | + +Finally, if only Dependency3 is changed: + +| Local_Static| content_update_group | +|:---|:---| +| AssetA| | +| AssetB| | +| | AssetC | + +This is because when a dependency is changed the entire dependency tree needs to be rebuilt. + +The following example has this dependency tree. AssetA depends on AssetB, which depends on Dependency2, AssetB depends on Dependency2, and AssetC depends on Dependency3. Now, if Dependency2 is changed, the project structure looks like the following: + +| Local_Static| content_update_group | +|:---|:---| +| | AssetA | +| | AssetB | +| AssetC| | + +This is because AssetA relies on AssetB and AssetB relies on Dependency2. Since the entire chain needs to be rebuilt both AssetA and AssetB will get put into the __content_update_group__. diff --git a/Documentation~/convert-asset-bundles.md b/Documentation~/convert-asset-bundles.md index 55e8931b..62b69be7 100644 --- a/Documentation~/convert-asset-bundles.md +++ b/Documentation~/convert-asset-bundles.md @@ -1,14 +1,14 @@ -# Convert AssetBundles - -When you first open the **Addressables Groups** window, Unity offers to convert all AssetBundles into Addressables groups. This is the easiest way to migrate your AssetBundle setup to the Addressables system. You must still update your runtime code to load and release assets using the `Addressables` API. - -If you want to convert your AssetBundle setup manually, click the **Ignore** button. The process for manually migrating your AssetBundles to Addressables is similar to that described for scenes and the Resources folder: - -1. Make the assets Addressable by enabling the **Addressable** property on each asset’s Inspector window or by dragging the asset to a group in the Addressables Groups window. The Addressables system ignores existing AssetBundle and label settings for an asset. -2. Change any runtime code that loads assets using the AssetBundle or UnityWebRequestAssetBundle APIs to load them with the Addressables API. You don't need to explicitly load AssetBundle objects themselves or the dependencies of an asset; the Addressables system handles those aspects automatically. -3. Add code to release loaded assets when no longer needed. - ->[!NOTE] -> The default path for the address of an asset is its file path. If you use the path as the asset's address, you'd load the asset in the same manner as you would load from a bundle. The Addressable asset system handles the loading of the bundle and all its dependencies. - -If you chose the automatic conversion option or manually added your assets to equivalent Addressables groups, then, depending on your group settings, you end up with the same set of bundles containing the same assets. The bundle files themselves won't be identical. +# Convert AssetBundles + +When you first open the **Addressables Groups** window, Unity offers to convert all AssetBundles into Addressables groups. This is the easiest way to migrate your AssetBundle setup to the Addressables system. You must still update your runtime code to load and release assets using the `Addressables` API. + +If you want to convert your AssetBundle setup manually, click the **Ignore** button. The process for manually migrating your AssetBundles to Addressables is similar to that described for scenes and the Resources folder: + +1. Make the assets Addressable by enabling the **Addressable** property on each asset’s Inspector window or by dragging the asset to a group in the Addressables Groups window. The Addressables system ignores existing AssetBundle and label settings for an asset. +2. Change any runtime code that loads assets using the AssetBundle or UnityWebRequestAssetBundle APIs to load them with the Addressables API. You don't need to explicitly load AssetBundle objects themselves or the dependencies of an asset; the Addressables system handles those aspects automatically. +3. Add code to release loaded assets when no longer needed. + +>[!NOTE] +> The default path for the address of an asset is its file path. If you use the path as the asset's address, you'd load the asset in the same manner as you would load from a bundle. The Addressable asset system handles the loading of the bundle and all its dependencies. + +If you chose the automatic conversion option or manually added your assets to equivalent Addressables groups, then, depending on your group settings, you end up with the same set of bundles containing the same assets. The bundle files themselves won't be identical. diff --git a/Documentation~/convert-prefabs.md b/Documentation~/convert-prefabs.md index d08edcdb..d558cb83 100644 --- a/Documentation~/convert-prefabs.md +++ b/Documentation~/convert-prefabs.md @@ -1,8 +1,8 @@ -# Convert prefabs - -To convert a prefab into an Addressable asset, enable the __Addressables__ option in its Inspector window or drag it to a group in the [Addressables Groups](xref:addressables-groups) window. - -You don't always need to make prefabs Addressable when used in an Addressable scene. Addressables automatically includes prefabs that you add to the scene hierarchy as part of the data contained in the scene's AssetBundle. If you use a prefab in more than one scene, make the prefab into an Addressable asset so that the prefab data isn't duplicated in each scene that uses it. You must also make a prefab Addressable if you want to load and instantiate it dynamically at runtime. - -> [!NOTE] -> If you use a Prefab in a non-Addressable Scene, Unity copies the Prefab data into the built-in Scene data whether the Prefab is Addressable or not. +# Convert prefabs + +To convert a prefab into an Addressable asset, enable the __Addressables__ option in its Inspector window or drag it to a group in the [Addressables Groups](xref:addressables-groups) window. + +You don't always need to make prefabs Addressable when used in an Addressable scene. Addressables automatically includes prefabs that you add to the scene hierarchy as part of the data contained in the scene's AssetBundle. If you use a prefab in more than one scene, make the prefab into an Addressable asset so that the prefab data isn't duplicated in each scene that uses it. You must also make a prefab Addressable if you want to load and instantiate it dynamically at runtime. + +> [!NOTE] +> If you use a Prefab in a non-Addressable Scene, Unity copies the Prefab data into the built-in Scene data whether the Prefab is Addressable or not. diff --git a/Documentation~/convert-project-to-addressables.md b/Documentation~/convert-project-to-addressables.md index b077214e..292140b2 100644 --- a/Documentation~/convert-project-to-addressables.md +++ b/Documentation~/convert-project-to-addressables.md @@ -1,25 +1,25 @@ ---- -uid: convert-to-addressables ---- - -# Configure your project to use Addressables - -You can add Addressables to an existing Unity project by installing the Addressables package. Once you've installed the package, you need to assign addresses to your assets and refactor any runtime loading code. - -Although you can integrate Addressables at any stage in a project’s development, it's best practice to start using Addressables immediately in new projects to avoid unnecessary code refactoring and content planning changes later in development. - -## Convert to Addressables - -Content built using Addressables only references other assets built in that Addressables build. Content that's used or referenced to which is included within both Addressables, and the Player build through the __Scene data__ and __Resource folders__ is duplicated on disk and in memory if they're both loaded. Because of this limitation, you must convert all __Scene data__ and __Resource folders__ to the Addressables build system. This reduces the memory overhead because of duplication and means you can manage all content with Addressables. This also means that the content can be either local or remote, and you can update it through [content update](xref:addressables-content-update-builds) builds. - -To convert your project to Addressables, you need to perform different steps depending on how your current project references and loads assets: - -* __Prefabs__: Assets you create using GameObjects and components, and save outside a Scene. For information on how to upgrade prefab data to Addressables, refer to [Convert prefabs](convert-prefabs.md). -* __AssetBundles__: Assets you package in AssetBundles and load with the `AssetBundle` API. For information on how to upgrade AssetBundles to Addressables, refer to [Convert AssetBundles](convert-asset-bundles.md) -* __StreamingAssets__: Files you place in the `StreamingAssets` folder. Unity includes any files in the `StreamingAssets` folder in your built player application as is. - -## Files in StreamingAssets - -You can continue to load files from the `StreamingAssets` folder when you use the Addressables system. However, the files in this folder can't be Addressable nor can they reference other assets in your project. - -The Addressables system places its runtime configuration files and local AssetBundles in the StreamingAssets folder during a build. Addressables removes these files at the conclusion of the build process and you won’t see them in the Unity Editor. +--- +uid: convert-to-addressables +--- + +# Configure your project to use Addressables + +You can add Addressables to an existing Unity project by installing the Addressables package. Once you've installed the package, you need to assign addresses to your assets and refactor any runtime loading code. + +Although you can integrate Addressables at any stage in a project’s development, it's best practice to start using Addressables immediately in new projects to avoid unnecessary code refactoring and content planning changes later in development. + +## Convert to Addressables + +Content built using Addressables only references other assets built in that Addressables build. Content that's used or referenced to which is included within both Addressables, and the Player build through the __Scene data__ and __Resource folders__ is duplicated on disk and in memory if they're both loaded. Because of this limitation, you must convert all __Scene data__ and __Resource folders__ to the Addressables build system. This reduces the memory overhead because of duplication and means you can manage all content with Addressables. This also means that the content can be either local or remote, and you can update it through [content update](xref:addressables-content-update-builds) builds. + +To convert your project to Addressables, you need to perform different steps depending on how your current project references and loads assets: + +* __Prefabs__: Assets you create using GameObjects and components, and save outside a Scene. For information on how to upgrade prefab data to Addressables, refer to [Convert prefabs](convert-prefabs.md). +* __AssetBundles__: Assets you package in AssetBundles and load with the `AssetBundle` API. For information on how to upgrade AssetBundles to Addressables, refer to [Convert AssetBundles](convert-asset-bundles.md) +* __StreamingAssets__: Files you place in the `StreamingAssets` folder. Unity includes any files in the `StreamingAssets` folder in your built player application as is. + +## Files in StreamingAssets + +You can continue to load files from the `StreamingAssets` folder when you use the Addressables system. However, the files in this folder can't be Addressable nor can they reference other assets in your project. + +The Addressables system places its runtime configuration files and local AssetBundles in the StreamingAssets folder during a build. Addressables removes these files at the conclusion of the build process and you won’t see them in the Unity Editor. diff --git a/Documentation~/convert-resources-folder.md b/Documentation~/convert-resources-folder.md index af43270c..753aaca0 100644 --- a/Documentation~/convert-resources-folder.md +++ b/Documentation~/convert-resources-folder.md @@ -1,26 +1,26 @@ -# Convert the Resources folder - -If your project loads assets in Resources folders, you can migrate those assets to the Addressables system: - -1. Make the assets Addressable. To do this, either enable the **Addressable** option in each asset's Inspector window or drag the assets to groups in the [Addressables Groups](xref:addressables-groups) window. -1. Change any runtime code that loads assets using the [Resources](xref:UnityEngine.Resources) API to load them with the [Addressables](xref:UnityEngine.AddressableAssets.Addressables) API. -3. Add code to release loaded assets when no longer needed. - -If you keep all the assets that were previously in the Resources folder in one group, you can expect similar loading and memory performance. - -When you mark an asset in the Resources folder as Addressable, Unity automatically moves the asset to a new folder in your project named `Resources_moved`. The default address for a moved asset is the old path, omitting the folder name. For example, your loading code might change from: - -```c# -Resources.LoadAsync("desert/tank.prefab"); -``` -to: - -```c# -Addressables.LoadAssetAsync("desert/tank.prefab"); -``` - -You might have to implement some functionality of the `Resources` class differently after you change your project to use the Addressables system. - -For example, if you run a command like `Resources.LoadAll\("MyPrefabs");` to load assets from a `Resources/MyPrefabs/` folder, Unity loads all the assets, Unity loads all assets in `Resources/MyPrefabs/` that match the type `SampleType`. - -Because the Addressables system doesn't support this exact functionality, you need to change your workflow to accommodate the Addressables system. In this case, you can achieve a similar effect with [Addresssable labels](xref:addressables-labels). +# Convert the Resources folder + +If your project loads assets in Resources folders, you can migrate those assets to the Addressables system: + +1. Make the assets Addressable. To do this, either enable the **Addressable** option in each asset's Inspector window or drag the assets to groups in the [Addressables Groups](xref:addressables-groups) window. +1. Change any runtime code that loads assets using the [Resources](xref:UnityEngine.Resources) API to load them with the [Addressables](xref:UnityEngine.AddressableAssets.Addressables) API. +3. Add code to release loaded assets when no longer needed. + +If you keep all the assets that were previously in the Resources folder in one group, you can expect similar loading and memory performance. + +When you mark an asset in the Resources folder as Addressable, Unity automatically moves the asset to a new folder in your project named `Resources_moved`. The default address for a moved asset is the old path, omitting the folder name. For example, your loading code might change from: + +```c# +Resources.LoadAsync("desert/tank.prefab"); +``` +to: + +```c# +Addressables.LoadAssetAsync("desert/tank.prefab"); +``` + +You might have to implement some functionality of the `Resources` class differently after you change your project to use the Addressables system. + +For example, if you run a command like `Resources.LoadAll\("MyPrefabs");` to load assets from a `Resources/MyPrefabs/` folder, Unity loads all the assets, Unity loads all assets in `Resources/MyPrefabs/` that match the type `SampleType`. + +Because the Addressables system doesn't support this exact functionality, you need to change your workflow to accommodate the Addressables system. In this case, you can achieve a similar effect with [Addresssable labels](xref:addressables-labels). diff --git a/Documentation~/convert-scene-data.md b/Documentation~/convert-scene-data.md index a070cc5a..e76a143f 100644 --- a/Documentation~/convert-scene-data.md +++ b/Documentation~/convert-scene-data.md @@ -1,39 +1,39 @@ -# Convert scene data - -To convert scene data to Addressable, move the scenes out of the [Build Settings](xref:BuildSettings) list and make those scenes Addressable. You must have one scene in the list, which is the scene Unity loads at application startup. You can make a new scene for this that does nothing else than load your first Addressable scene. - -To convert your scenes: - -1. Create a new initialization scene. -1. Open the __Build Settings__ window (menu: __File > Build Settings__). -1. Add the initialization scene to the scene list. -1. Remove the other scenes from the list. -1. Select each scene in the project list and enable the Addressable option in its Inspector window. Or, you can drag scene assets to a group in the Addressables Groups window. Don't make your new initialization scene Addressable. -1. Update the code you use to load Scenes to use the [`Addressables`](xref:UnityEngine.AddressableAssets.Addressables) class scene loading methods rather than the `SceneManager` methods. - -You can now split your one, large Addressable Scene group into multiple groups. The best way to do that depends on the project goals. To proceed, you can move your Scenes into their own groups so that you can load and unload each of them independently of each other. You can avoid duplicating an asset referenced from two different bundles by making the asset itself Addressable. It's often better to move shared assets to their own group as well to reduce dependencies among AssetBundles. - -You can now split your one, large Addressable scene group into multiple groups. The best way to do that depends on the project goals. To proceed, you can move your scenes into their own groups so that you can load and unload each of them independently of each other. - -To avoid duplicating an asset referenced from two different bundles, make the asset Addressable. It's often better to move shared assets to their own group to reduce the amount of dependencies among your AssetBundles. - - -## Use Addressable assets in non-Addressable scenes - -For any scenes that you don't want to make Addressable, you can still use Addressable assets as part of the Scene data through [AssetReferences](xref:addressables-asset-references). - -When you add an AssetReference field to a custom MonoBehaviour or ScriptableObject class, you can assign an Addressable asset to the field in the Unity Editor in a similar way that you assign an asset as a direct reference. The main difference is that you need to add code to your class to load and release the asset assigned to the AssetReference field (whereas Unity loads direct references automatically when it instantiates your object in the Scene). - -> [!NOTE] -> You can't use Addressable assets for the fields of any UnityEngine components in a non-Addressable scene. For example, if you assign an Addressable mesh asset to a MeshFilter component in a non-Addressable Scene, Unity doesn't use the Addressable version of that mesh data for the Scene. Instead, Unity copies the mesh asset and includes two versions of the mesh in your application: one in the AssetBundle built for the Addressable group that contains the mesh, and one in the built-in Scene data of the non-Addressable scene. When used in an Addressable Scene, Unity doesn't copy the mesh data and always loads it from the AssetBundle. - -To replace direct references with AssetReferences in your custom classes, follow these steps: - -1. Replace your direct references to objects with asset references (for example, `public GameObject directRefMember;` becomes `public AssetReference assetRefMember;`). -1. Drag assets onto the appropriate component’s Inspector, as you would for a direct reference. -1. Add runtime code to load the assigned asset using the [`Addressables`](xref:UnityEngine.AddressableAssets.Addressables) API. -1. Add code to release the loaded asset when no longer needed. - -For more information about using AssetReference fields, refer to [Asset references](xref:addressables-asset-references). - +# Convert scene data + +To convert scene data to Addressable, move the scenes out of the [Build Settings](xref:BuildSettings) list and make those scenes Addressable. You must have one scene in the list, which is the scene Unity loads at application startup. You can make a new scene for this that does nothing else than load your first Addressable scene. + +To convert your scenes: + +1. Create a new initialization scene. +1. Open the __Build Settings__ window (menu: __File > Build Settings__). +1. Add the initialization scene to the scene list. +1. Remove the other scenes from the list. +1. Select each scene in the project list and enable the Addressable option in its Inspector window. Or, you can drag scene assets to a group in the Addressables Groups window. Don't make your new initialization scene Addressable. +1. Update the code you use to load Scenes to use the [`Addressables`](xref:UnityEngine.AddressableAssets.Addressables) class scene loading methods rather than the `SceneManager` methods. + +You can now split your one, large Addressable Scene group into multiple groups. The best way to do that depends on the project goals. To proceed, you can move your Scenes into their own groups so that you can load and unload each of them independently of each other. You can avoid duplicating an asset referenced from two different bundles by making the asset itself Addressable. It's often better to move shared assets to their own group as well to reduce dependencies among AssetBundles. + +You can now split your one, large Addressable scene group into multiple groups. The best way to do that depends on the project goals. To proceed, you can move your scenes into their own groups so that you can load and unload each of them independently of each other. + +To avoid duplicating an asset referenced from two different bundles, make the asset Addressable. It's often better to move shared assets to their own group to reduce the amount of dependencies among your AssetBundles. + + +## Use Addressable assets in non-Addressable scenes + +For any scenes that you don't want to make Addressable, you can still use Addressable assets as part of the Scene data through [AssetReferences](xref:addressables-asset-references). + +When you add an AssetReference field to a custom MonoBehaviour or ScriptableObject class, you can assign an Addressable asset to the field in the Unity Editor in a similar way that you assign an asset as a direct reference. The main difference is that you need to add code to your class to load and release the asset assigned to the AssetReference field (whereas Unity loads direct references automatically when it instantiates your object in the Scene). + +> [!NOTE] +> You can't use Addressable assets for the fields of any UnityEngine components in a non-Addressable scene. For example, if you assign an Addressable mesh asset to a MeshFilter component in a non-Addressable Scene, Unity doesn't use the Addressable version of that mesh data for the Scene. Instead, Unity copies the mesh asset and includes two versions of the mesh in your application: one in the AssetBundle built for the Addressable group that contains the mesh, and one in the built-in Scene data of the non-Addressable scene. When used in an Addressable Scene, Unity doesn't copy the mesh data and always loads it from the AssetBundle. + +To replace direct references with AssetReferences in your custom classes, follow these steps: + +1. Replace your direct references to objects with asset references (for example, `public GameObject directRefMember;` becomes `public AssetReference assetRefMember;`). +1. Drag assets onto the appropriate component’s Inspector, as you would for a direct reference. +1. Add runtime code to load the assigned asset using the [`Addressables`](xref:UnityEngine.AddressableAssets.Addressables) API. +1. Add code to release the loaded asset when no longer needed. + +For more information about using AssetReference fields, refer to [Asset references](xref:addressables-asset-references). + For more information about loading Addressable assets, refer to [Loading Addressable assets](xref:addressables-api-load-asset-async). \ No newline at end of file diff --git a/Documentation~/filter.yml b/Documentation~/filter.yml index ca39ccaf..e944f6d0 100644 --- a/Documentation~/filter.yml +++ b/Documentation~/filter.yml @@ -1,29 +1,29 @@ -apiRules: - - exclude: - uidRegex: Tests$ - - exclude: - uidRegex: .*Test.* - - exclude: - uidRegex: .*HideResourceFoldersScope.* - - exclude: - uidRegex: .*IgnoreFailingLogMessage.* - - exclude: - type: Namespace - uidRegex: GUI$ - - exclude: - type: Namespace - uidRegex: Unity.*\.Tests\..*$ - - exclude: - type: Namespace - uidRegex: DocExampleCode$ - # hiding samples from api docs - - exclude: - uidRegex: .*Global Namespace.AddressablesUtility.* - - exclude: - uidRegex: .*Global Namespace.ComponentReference.* - - exclude: - uidRegex: .*Global Namespace.DisableAssetImportOnBuild.* - - exclude: - uidRegex: .*Global Namespace.LoadSceneForCustomBuild.* - - exclude: - uidRegex: .*Global Namespace.PrefabSpawnerSample.* +apiRules: + - exclude: + uidRegex: Tests$ + - exclude: + uidRegex: .*Test.* + - exclude: + uidRegex: .*HideResourceFoldersScope.* + - exclude: + uidRegex: .*IgnoreFailingLogMessage.* + - exclude: + type: Namespace + uidRegex: GUI$ + - exclude: + type: Namespace + uidRegex: Unity.*\.Tests\..*$ + - exclude: + type: Namespace + uidRegex: DocExampleCode$ + # hiding samples from api docs + - exclude: + uidRegex: .*Global Namespace.AddressablesUtility.* + - exclude: + uidRegex: .*Global Namespace.ComponentReference.* + - exclude: + uidRegex: .*Global Namespace.DisableAssetImportOnBuild.* + - exclude: + uidRegex: .*Global Namespace.LoadSceneForCustomBuild.* + - exclude: + uidRegex: .*Global Namespace.PrefabSpawnerSample.* diff --git a/Documentation~/get-started-make-addressable.md b/Documentation~/get-started-make-addressable.md index e1cb1cdf..27058a38 100644 --- a/Documentation~/get-started-make-addressable.md +++ b/Documentation~/get-started-make-addressable.md @@ -1,23 +1,23 @@ -# Make an asset Addressable - -You can make an asset Addressable in the following ways: - -* Enable the __Addressable__ property in the asset's **Inspector** window. -* Assign the asset to an AssetReference field in the **Inspector** window. -* Drag the asset into a group on the [Addressables Groups](GroupsWindow.md) window. -* In the Project window, move the asset into a folder that's marked as Addressable. - - - -Once you make an asset Addressable, the Addressables system adds it to a default group, unless you place it in a specific group. Addressables packs assets in a group into [AssetBundles](xref:AssetBundlesIntro) according to your group settings when you make a [content build](xref:addressables-builds). You can load these assets using the [Addressables API](xref:addressables-api-load-asset-async). - -> [!NOTE] -> If you make an asset in the [Resources folder](xref:SpecialFolders) Addressable, Unity displays a prompt asking whether you want Unity to move the asset out of the Resources folder. You can move the asset to a different folder in your Project, but you can't store Addressable assets in the Resources folder. +# Make an asset Addressable + +You can make an asset Addressable in the following ways: + +* Enable the __Addressable__ property in the asset's **Inspector** window. +* Assign the asset to an AssetReference field in the **Inspector** window. +* Drag the asset into a group on the [Addressables Groups](GroupsWindow.md) window. +* In the Project window, move the asset into a folder that's marked as Addressable. + + + +Once you make an asset Addressable, the Addressables system adds it to a default group, unless you place it in a specific group. Addressables packs assets in a group into [AssetBundles](xref:AssetBundlesIntro) according to your group settings when you make a [content build](xref:addressables-builds). You can load these assets using the [Addressables API](xref:addressables-api-load-asset-async). + +> [!NOTE] +> If you make an asset in the [Resources folder](xref:SpecialFolders) Addressable, Unity displays a prompt asking whether you want Unity to move the asset out of the Resources folder. You can move the asset to a different folder in your Project, but you can't store Addressable assets in the Resources folder. diff --git a/Documentation~/groups-create.md b/Documentation~/groups-create.md index 90c7a998..e35b6d74 100644 --- a/Documentation~/groups-create.md +++ b/Documentation~/groups-create.md @@ -1,41 +1,41 @@ -# Manage and create groups - -To manage your groups and Addressables assets, open the Addressables Groups window by going to **Window** >**Asset Management** > **Addressables** > **Groups**. Refer to [Addressables Groups window](xref:addressables-groups-window) for details about the features of this window. - -## Create a group - -To create a group: - -1. Go to **Window** > **Asset Management** > **Addressables** and select **Groups** to open the Addressables Groups window. -1. Select **New** > **Packed Asset** to create a new group. If you've created your own [group templates](xref:group-templates), they are also displayed in the menu. -1. Context click the new group and select **Rename** to rename the group. -1. Open the context menu again and select **Inspect Group Settings**. -1. Adjust the group settings as desired. - -For groups that contain assets that you plan to distribute with your main application, the default settings are a reasonable starting point. For groups containing assets that you plan to distribute remotely, you must change the build and load paths to use the remote versions of the [Profile](xref:addressables-profiles) path variables. To build AssetBundles for remote distribution, you must also enable the __Build Remote Catalog__ option in the [Addressable System Settings](xref:addressables-asset-settings). - -Refer to [Group settings](xref:addressables-group-schemas) for more information about individual settings. - -## Add assets to a group - -Use one of the following methods to add an asset to a group: - -* Drag the assets from the Project window into the Group window and drop them into the desired group. -* Drag the assets from one group into another. -* Select the asset to open it in the Inspector window and enable the **Addressables** option. This adds the asset to the default group. Use the group context menu to change which group is the default group. -* Add the folder containing the assets to a group. All assets added to the folder are included in the group. - -> [!NOTE] -> If you add assets in a Resources folder to a group, the Addressables system first moves the assets to a non-Resource location. You can move the assets elsewhere, but you can't store Addressable assets in a Resources folder in your project. - -## Remove assets from a group - -Select one or more assets in the Groups window and right-click to open the context menu, then select **Remove Addressables**. You can also select the assets and press the Delete key to remove the assets from the group. - -## Add or remove labels - -Select one or more assets in the Groups window, then select the label field for one of the selected assets. - -To assign labels, enable or disable the checkboxes for the desired labels. - -To add, remove or rename your labels, select the __+__ button, then select __Manage Labels__. To only add a new label, select the __+__ button and then select __New Label__. Refer to [Labels](xref:addressables-labels) for more information on how to use labels. +# Manage and create groups + +To manage your groups and Addressables assets, open the Addressables Groups window by going to **Window** >**Asset Management** > **Addressables** > **Groups**. Refer to [Addressables Groups window](xref:addressables-groups-window) for details about the features of this window. + +## Create a group + +To create a group: + +1. Go to **Window** > **Asset Management** > **Addressables** and select **Groups** to open the Addressables Groups window. +1. Select **New** > **Packed Asset** to create a new group. If you've created your own [group templates](xref:group-templates), they are also displayed in the menu. +1. Context click the new group and select **Rename** to rename the group. +1. Open the context menu again and select **Inspect Group Settings**. +1. Adjust the group settings as desired. + +For groups that contain assets that you plan to distribute with your main application, the default settings are a reasonable starting point. For groups containing assets that you plan to distribute remotely, you must change the build and load paths to use the remote versions of the [Profile](xref:addressables-profiles) path variables. To build AssetBundles for remote distribution, you must also enable the __Build Remote Catalog__ option in the [Addressable System Settings](xref:addressables-asset-settings). + +Refer to [Group settings](xref:addressables-group-schemas) for more information about individual settings. + +## Add assets to a group + +Use one of the following methods to add an asset to a group: + +* Drag the assets from the Project window into the Group window and drop them into the desired group. +* Drag the assets from one group into another. +* Select the asset to open it in the Inspector window and enable the **Addressables** option. This adds the asset to the default group. Use the group context menu to change which group is the default group. +* Add the folder containing the assets to a group. All assets added to the folder are included in the group. + +> [!NOTE] +> If you add assets in a Resources folder to a group, the Addressables system first moves the assets to a non-Resource location. You can move the assets elsewhere, but you can't store Addressable assets in a Resources folder in your project. + +## Remove assets from a group + +Select one or more assets in the Groups window and right-click to open the context menu, then select **Remove Addressables**. You can also select the assets and press the Delete key to remove the assets from the group. + +## Add or remove labels + +Select one or more assets in the Groups window, then select the label field for one of the selected assets. + +To assign labels, enable or disable the checkboxes for the desired labels. + +To add, remove or rename your labels, select the __+__ button, then select __Manage Labels__. To only add a new label, select the __+__ button and then select __New Label__. Refer to [Labels](xref:addressables-labels) for more information on how to use labels. diff --git a/Documentation~/groups-intro.md b/Documentation~/groups-intro.md index e8362014..4c060c23 100644 --- a/Documentation~/groups-intro.md +++ b/Documentation~/groups-intro.md @@ -1,10 +1,10 @@ -# Groups introduction - -A group is the main organizational unit of the Addressables system. Create and manage your groups and the assets they contain with the [Addressables Groups window](xref:addressables-groups-window). - -To control how Unity handles assets during a content build, organize Addressables into groups and assign different settings to each group as required. Refer to [Organizing Addressable Assets](xref:addressables-assets-development-cycle) for information about how to organize your assets. - -When you begin a content build, the build scripts create AssetBundles that contain the assets in a group. The build determines the number of bundles to create and where to create them from both the [settings of the group](xref:addressables-group-schemas) and your overall [Addressables system settings](xref:addressables-asset-settings). Refer to [Builds](xref:addressables-builds) for more information. - -> [!NOTE] +# Groups introduction + +A group is the main organizational unit of the Addressables system. Create and manage your groups and the assets they contain with the [Addressables Groups window](xref:addressables-groups-window). + +To control how Unity handles assets during a content build, organize Addressables into groups and assign different settings to each group as required. Refer to [Organizing Addressable Assets](xref:addressables-assets-development-cycle) for information about how to organize your assets. + +When you begin a content build, the build scripts create AssetBundles that contain the assets in a group. The build determines the number of bundles to create and where to create them from both the [settings of the group](xref:addressables-group-schemas) and your overall [Addressables system settings](xref:addressables-asset-settings). Refer to [Builds](xref:addressables-builds) for more information. + +> [!NOTE] > Addressable Groups only exist in the Unity Editor. The Addressables runtime code doesn't use a group concept. However, you can assign a label to the assets in a group if you want to find and load all the assets that were part of that group. Refer to [Loading Addressable assets](xref:addressables-api-load-asset-async) for more information about selecting the assets to load using labels. \ No newline at end of file diff --git a/Documentation~/images/BuildReportInspectorRefsTo.png.meta b/Documentation~/images/BuildReportInspectorRefsTo.png.meta index 50555b87..61ee4499 100644 --- a/Documentation~/images/BuildReportInspectorRefsTo.png.meta +++ b/Documentation~/images/BuildReportInspectorRefsTo.png.meta @@ -1,3 +1,3 @@ -fileFormatVersion: 2 -guid: bbdcbaa918f9400b8cb1261fd69ed595 +fileFormatVersion: 2 +guid: bbdcbaa918f9400b8cb1261fd69ed595 timeCreated: 1680900080 \ No newline at end of file diff --git a/Documentation~/images/HowToOpenBuildReport.png.meta b/Documentation~/images/HowToOpenBuildReport.png.meta index d46fafa6..ae32ba8f 100644 --- a/Documentation~/images/HowToOpenBuildReport.png.meta +++ b/Documentation~/images/HowToOpenBuildReport.png.meta @@ -1,3 +1,3 @@ -fileFormatVersion: 2 -guid: 1f836c75c79948a6855d05ee2da6df1e +fileFormatVersion: 2 +guid: 1f836c75c79948a6855d05ee2da6df1e timeCreated: 1678912360 \ No newline at end of file diff --git a/Documentation~/index.md b/Documentation~/index.md index 2f58df5a..bd94ab87 100644 --- a/Documentation~/index.md +++ b/Documentation~/index.md @@ -1,25 +1,25 @@ ---- -uid: addressables-home ---- - -# Addressables package - -The Addressables package builds on Unity's [AssetBundles](xref:AssetBundlesIntro) system and provides a user interface to manage your AssetBundles. When you make an asset Addressable, you can use that asset's address to load it from anywhere. The Addressable system locates and returns the asset whether it's available in the local application or stored on a remote content delivery network. - -You can use this package to distribute content remotely, manage content loading at runtime, control where your application's assets are hosted, and manage dependencies between assets. - -| **Topic** | **Description** | -| :----------------------- | :-------------------------- | -| **[Get started](xref:addressables-getting-started)**| Install the Addressables package, learn key concepts and find samples.| -| **[Manage Addressables](xref:addressables-assets-development-cycle)**|Organize your assets into Groups and use Profiles to manage your Groups.| -| **[Build content](xref:addressables-builds)**|Process your Addressables Groups into a content catalog and create the AssetBundles that contain the assets.| -| **[Distribute remote content](xref:addressables-remote-content-distribution)**|Use remote hosting or Cloud Content Delivery (CCD) to load new assets or distribute new content.| -| **[Use Addressables at runtime](xref:addressable-runtime)**|Manage catalogs, memory, modification events, and use asset addresses while your application runs.| -| **[Load Addressable assets](xref:addressables-api-load-asset-async)**|How to load and unload Addressables assets, load across multiple Unity projects, load asynchronously, and manage pre-load dependencies.| -| **[Diagnostic tools](xref:addressables-diagnostic-tools)**|Use built in tools to asses the setup and performance of your Addressable assets.| - -## Additional resources - -- Unity's [Addressables: Planning and best practices](https://blog.unity.com/engine-platform/addressables-planning-and-best-practices) blog post. -- [AssetBundles documentation](xref:AssetBundlesIntro). -- [Why use Addressables?](https://learn.unity.com/tutorial/why-use-addressables?courseId=64255c01edbc2a268fb0b800#) - Unity Learn course. +--- +uid: addressables-home +--- + +# Addressables package + +The Addressables package builds on Unity's [AssetBundles](xref:AssetBundlesIntro) system and provides a user interface to manage your AssetBundles. When you make an asset Addressable, you can use that asset's address to load it from anywhere. The Addressable system locates and returns the asset whether it's available in the local application or stored on a remote content delivery network. + +You can use this package to distribute content remotely, manage content loading at runtime, control where your application's assets are hosted, and manage dependencies between assets. + +| **Topic** | **Description** | +| :----------------------- | :-------------------------- | +| **[Get started](xref:addressables-getting-started)**| Install the Addressables package, learn key concepts and find samples.| +| **[Manage Addressables](xref:addressables-assets-development-cycle)**|Organize your assets into Groups and use Profiles to manage your Groups.| +| **[Build content](xref:addressables-builds)**|Process your Addressables Groups into a content catalog and create the AssetBundles that contain the assets.| +| **[Distribute remote content](xref:addressables-remote-content-distribution)**|Use remote hosting or Cloud Content Delivery (CCD) to load new assets or distribute new content.| +| **[Use Addressables at runtime](xref:addressable-runtime)**|Manage catalogs, memory, modification events, and use asset addresses while your application runs.| +| **[Load Addressable assets](xref:addressables-api-load-asset-async)**|How to load and unload Addressables assets, load across multiple Unity projects, load asynchronously, and manage pre-load dependencies.| +| **[Diagnostic tools](xref:addressables-diagnostic-tools)**|Use built in tools to asses the setup and performance of your Addressable assets.| + +## Additional resources + +- Unity's [Addressables: Planning and best practices](https://blog.unity.com/engine-platform/addressables-planning-and-best-practices) blog post. +- [AssetBundles documentation](xref:AssetBundlesIntro). +- [Why use Addressables?](https://learn.unity.com/tutorial/why-use-addressables?courseId=64255c01edbc2a268fb0b800#) - Unity Learn course. diff --git a/Documentation~/installation-guide.md b/Documentation~/installation-guide.md index 3a5f0ecc..ee300499 100644 --- a/Documentation~/installation-guide.md +++ b/Documentation~/installation-guide.md @@ -1,17 +1,17 @@ -# Install Addressables - -To install the Addressables package in your project, use the [**Package Manager**](xref:Packages): - -1. Open the Package Manager (menu: __Window > Package Manager__). -1. Set the package list to display packages from the __Unity Registry__. -1. Select the Addressables package in the list. -1. Click __Install__ (at the bottom, right-hand side of the Package Manager window). - -To set up the Addressables system in your Project after installation, open the __Addressables Groups__ window and click __Create Addressables Settings__. - -![](images/install-settings.png)
*The **Addressables Groups window** before initializing the Addressables system in a Project* - -When you select __Create Addressables Settings__, the Addressables system creates a folder called `AddressableAssetsData` to store settings files and other assets the package uses to keep track of your Addressables setup. Add the files in this folder to your version control system. The Addressables package can create additional files as you change your Addressables configuration. For more information, refer to [Addressables Settings](AddressableAssetSettings.md). - -> [!NOTE] -> For instructions on installing a specific version of Addressables or for general information about managing the packages in a Project, refer to [Packages](xref:PackagesList). +# Install Addressables + +To install the Addressables package in your project, use the [**Package Manager**](xref:Packages): + +1. Open the Package Manager (menu: __Window > Package Manager__). +1. Set the package list to display packages from the __Unity Registry__. +1. Select the Addressables package in the list. +1. Click __Install__ (at the bottom, right-hand side of the Package Manager window). + +To set up the Addressables system in your Project after installation, open the __Addressables Groups__ window and click __Create Addressables Settings__. + +![](images/install-settings.png)
*The **Addressables Groups window** before initializing the Addressables system in a Project* + +When you select __Create Addressables Settings__, the Addressables system creates a folder called `AddressableAssetsData` to store settings files and other assets the package uses to keep track of your Addressables setup. Add the files in this folder to your version control system. The Addressables package can create additional files as you change your Addressables configuration. For more information, refer to [Addressables Settings](AddressableAssetSettings.md). + +> [!NOTE] +> For instructions on installing a specific version of Addressables or for general information about managing the packages in a Project, refer to [Packages](xref:PackagesList). diff --git a/Documentation~/load-addressable-assets.md b/Documentation~/load-addressable-assets.md index 59ee03c0..1c3caf52 100644 --- a/Documentation~/load-addressable-assets.md +++ b/Documentation~/load-addressable-assets.md @@ -1,45 +1,45 @@ -# Load Addressable assets introduction - -The [`Addressables`](xref:UnityEngine.AddressableAssets.Addressables) class provides methods to load Addressable assets. You can load assets one at a time or in batches. To identify the assets to load, you pass either a single key or a list of keys to the loading method. A key can be one of the following objects: - -* **Address**: A string containing the address you assigned to the asset -* **Label**: A string containing a label assigned to one or more assets -* **AssetReference object**: An instance of [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) -* [`IResourceLocation`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation) instance: An intermediate object that contains information to load an asset and its dependencies. - -## How Addressables loads assets - -When you call one of the asset loading methods, the Addressables system begins an asynchronous operation that carries out the following tasks: - -1. Looks up the resource locations for the specified keys, except `IResourceLocation` keys. -1. Gathers the list of dependencies -1. Downloads any remote AssetBundles that are required -1. Loads the AssetBundles into memory -1. Sets the [`Result`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Result) object of the operation to the loaded objects -1. Updates the [`Status`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Status) of the operation and calls any [`Completed`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) event listeners - -If the load operation succeeds, the `Status` is set to `Succeeded` and the loaded object or objects can be accessed from the [`Result`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Result) object. - -If an error occurs, the exception is copied to the [`OperationException`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.OperationException) member of the operation object and the `Status` is set to `Failed`. By default, the exception isn't thrown as part of the operation. However, you can assign a handler function to the [`ResourceManager.ExceptionHandler`](xref:UnityEngine.ResourceManagement.ResourceManager.ExceptionHandler) property to handle any exceptions. You can also enable the [Log Runtime Exceptions](xref:addressables-asset-settings) option in the Addressable system settings to record errors to the [Unity Console](xref:Console). - -When you call loading methods that load multiple Addressable assets, you can specify whether to abort the entire operation if any single load operation fails or whether to load the operation any assets it can. In both cases, the operation status is set to failed. Set the `releaseDependenciesOnFailure` parameter to `true` in the call to the loading method to abort the entire operation on any failure. - -Refer to [Operations](xref:addressables-async-operation-handling) for more information about asynchronous operations and writing asynchronous code in Unity scripts. - -## Match loaded assets to their keys - -The order that Unity loads individual assets isn't necessarily the same as the order of the keys in the list you pass to the loading method. - -If you need to associate an asset in a combined operation with the key used to load it, you can perform the operation in the following steps: - -1. Load the [`IResourceLocation`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation) instances with the list of asset keys. -1. Load the individual assets using their `IResourceLocation` instances as keys. - -The `IResourceLocation` object contains the key information so you can, for example, keep a dictionary to correlate the key to an asset. When you call a loading method, such as [`LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*), the operation first looks up the [`IResourceLocation`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation) instances that correspond to a key and then uses that to load the asset. When you load an asset using an `IResourceLocation`, the operation skips the first step, so performing the operation in two steps doesn't add significant additional work. - -The following example loads the assets for a list of keys and inserts them into a dictionary by their address ([`PrimaryKey`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation.PrimaryKey)). The example first loads the resource locations for the specified keys. When that operation is complete, it loads the asset for each location, using the `Completed` event to insert the individual operation handles into the dictionary. The operation handles can be used to instantiate the assets, and, when the assets are no longer needed, to release them. - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadLocation.cs#doc_Load)] - -The loading method creates a group operation with [`ResourceManager.CreateGenericGroupOperation`](xref:UnityEngine.ResourceManagement.ResourceManager.CreateGenericGroupOperation*). This allows the method to continue after all the loading operations have finished. In this case, the method dispatches a `Ready` event to notify other scripts that the loaded data can be used. - +# Load Addressable assets introduction + +The [`Addressables`](xref:UnityEngine.AddressableAssets.Addressables) class provides methods to load Addressable assets. You can load assets one at a time or in batches. To identify the assets to load, you pass either a single key or a list of keys to the loading method. A key can be one of the following objects: + +* **Address**: A string containing the address you assigned to the asset +* **Label**: A string containing a label assigned to one or more assets +* **AssetReference object**: An instance of [`AssetReference`](xref:UnityEngine.AddressableAssets.AssetReference) +* [`IResourceLocation`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation) instance: An intermediate object that contains information to load an asset and its dependencies. + +## How Addressables loads assets + +When you call one of the asset loading methods, the Addressables system begins an asynchronous operation that carries out the following tasks: + +1. Looks up the resource locations for the specified keys, except `IResourceLocation` keys. +1. Gathers the list of dependencies +1. Downloads any remote AssetBundles that are required +1. Loads the AssetBundles into memory +1. Sets the [`Result`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Result) object of the operation to the loaded objects +1. Updates the [`Status`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Status) of the operation and calls any [`Completed`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) event listeners + +If the load operation succeeds, the `Status` is set to `Succeeded` and the loaded object or objects can be accessed from the [`Result`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Result) object. + +If an error occurs, the exception is copied to the [`OperationException`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.OperationException) member of the operation object and the `Status` is set to `Failed`. By default, the exception isn't thrown as part of the operation. However, you can assign a handler function to the [`ResourceManager.ExceptionHandler`](xref:UnityEngine.ResourceManagement.ResourceManager.ExceptionHandler) property to handle any exceptions. You can also enable the [Log Runtime Exceptions](xref:addressables-asset-settings) option in the Addressable system settings to record errors to the [Unity Console](xref:Console). + +When you call loading methods that load multiple Addressable assets, you can specify whether to abort the entire operation if any single load operation fails or whether to load the operation any assets it can. In both cases, the operation status is set to failed. Set the `releaseDependenciesOnFailure` parameter to `true` in the call to the loading method to abort the entire operation on any failure. + +Refer to [Operations](xref:addressables-async-operation-handling) for more information about asynchronous operations and writing asynchronous code in Unity scripts. + +## Match loaded assets to their keys + +The order that Unity loads individual assets isn't necessarily the same as the order of the keys in the list you pass to the loading method. + +If you need to associate an asset in a combined operation with the key used to load it, you can perform the operation in the following steps: + +1. Load the [`IResourceLocation`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation) instances with the list of asset keys. +1. Load the individual assets using their `IResourceLocation` instances as keys. + +The `IResourceLocation` object contains the key information so you can, for example, keep a dictionary to correlate the key to an asset. When you call a loading method, such as [`LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*), the operation first looks up the [`IResourceLocation`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation) instances that correspond to a key and then uses that to load the asset. When you load an asset using an `IResourceLocation`, the operation skips the first step, so performing the operation in two steps doesn't add significant additional work. + +The following example loads the assets for a list of keys and inserts them into a dictionary by their address ([`PrimaryKey`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation.PrimaryKey)). The example first loads the resource locations for the specified keys. When that operation is complete, it loads the asset for each location, using the `Completed` event to insert the individual operation handles into the dictionary. The operation handles can be used to instantiate the assets, and, when the assets are no longer needed, to release them. + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadLocation.cs#doc_Load)] + +The loading method creates a group operation with [`ResourceManager.CreateGenericGroupOperation`](xref:UnityEngine.ResourceManagement.ResourceManager.CreateGenericGroupOperation*). This allows the method to continue after all the loading operations have finished. In this case, the method dispatches a `Ready` event to notify other scripts that the loaded data can be used. + diff --git a/Documentation~/load-assets-asynchronous.md b/Documentation~/load-assets-asynchronous.md index 4f61315c..c356c686 100644 --- a/Documentation~/load-assets-asynchronous.md +++ b/Documentation~/load-assets-asynchronous.md @@ -1,13 +1,13 @@ -# Asynchronous loading - -The Addressables system API is asynchronous and returns an [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) to use to manage operation progress and completion. - -Addressables is designed to be content location agnostic. The content might need to be downloaded first or use other methods that can take a long time. To force synchronous execution, refer to [Synchronous Addressables](xref:synchronous-addressables) for more information. - -When loading an asset for the first time, the handle is complete after a minimum of one frame. If the content has already loaded, execution times might differ between the various asynchronous loading options shown below. You can wait until the load has completed as follows: - -* [Coroutine](xref:UnityEngine.Coroutine): Always delayed at a minimum of one frame before execution continues. -* [`Completed` callback](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed): A minimum of one frame if the content hasn't already loaded, otherwise the callback is invoked in the same frame. -* Awaiting [`AsyncOperationHandle.Task`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Task): A minimum of one frame if the content hasn't already loaded, otherwise the execution continues in the same frame. - -[!code-cs[sample](../Tests/Editor/DocExampleCode/AsynchronousLoading.cs#doc_asyncload)] +# Asynchronous loading + +The Addressables system API is asynchronous and returns an [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) to use to manage operation progress and completion. + +Addressables is designed to be content location agnostic. The content might need to be downloaded first or use other methods that can take a long time. To force synchronous execution, refer to [Synchronous Addressables](xref:synchronous-addressables) for more information. + +When loading an asset for the first time, the handle is complete after a minimum of one frame. If the content has already loaded, execution times might differ between the various asynchronous loading options shown below. You can wait until the load has completed as follows: + +* [Coroutine](xref:UnityEngine.Coroutine): Always delayed at a minimum of one frame before execution continues. +* [`Completed` callback](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed): A minimum of one frame if the content hasn't already loaded, otherwise the callback is invoked in the same frame. +* Awaiting [`AsyncOperationHandle.Task`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Task): A minimum of one frame if the content hasn't already loaded, otherwise the execution continues in the same frame. + +[!code-cs[sample](../Tests/Editor/DocExampleCode/AsynchronousLoading.cs#doc_asyncload)] diff --git a/Documentation~/load-assets-location.md b/Documentation~/load-assets-location.md index d8f65ec4..9cad620b 100644 --- a/Documentation~/load-assets-location.md +++ b/Documentation~/load-assets-location.md @@ -1,17 +1,17 @@ -# Load assets by location - -When you load an Addressable asset by address, label, or AssetReference, the Addressables system first looks up the resource locations for the assets and uses the [`IResourceLocation`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation) instances to download the required AssetBundles and any dependencies. To perform the asset load operation, get the `IResourceLocation` objects with [`LoadResourceLocationsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadResourceLocationsAsync*) and then use those objects as keys to load or instantiate the assets. - -`IResourceLocation` objects contain the information needed to load one or more assets. - -The `LoadResourceLocationsAsync` method never fails. If it can't resolve the specified keys to the locations of any assets, it returns an empty list. You can restrict the types of asset locations returned by the method by specifying a specific type in the `type` parameter. - -The following example loads locations for all assets labeled with `knight` or `villager`: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadLocation.cs#doc_LoadLocations)] - -## Load locations of sub-objects - -Unity generates locations for `SubObjects` at runtime to reduce the size of the content catalogs and improve runtime performance. When you call [`LoadResourceLocationsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadResourceLocationsAsync*) with the key of an asset with sub-objects and don't specify a type, then the method generates `IResourceLocation` instances for all the sub-objects and the main object. Likewise, if you don't specify which sub-object to use for an AssetReference that points to an asset with sub-objects, then the system generates `IResourceLocation` instances for every sub-object. - -For example, if you load the locations for an FBX asset, with the address, `myFBXObject`, you might get locations for three assets: a GameObject, a mesh, and a material. If, instead, you specify the type in the address, `myFBXObject[Mesh]`, you only get the mesh object. You can also specify the type using the `type` parameter of the `LoadResourceLocationsAsync` method. +# Load assets by location + +When you load an Addressable asset by address, label, or AssetReference, the Addressables system first looks up the resource locations for the assets and uses the [`IResourceLocation`](xref:UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation) instances to download the required AssetBundles and any dependencies. To perform the asset load operation, get the `IResourceLocation` objects with [`LoadResourceLocationsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadResourceLocationsAsync*) and then use those objects as keys to load or instantiate the assets. + +`IResourceLocation` objects contain the information needed to load one or more assets. + +The `LoadResourceLocationsAsync` method never fails. If it can't resolve the specified keys to the locations of any assets, it returns an empty list. You can restrict the types of asset locations returned by the method by specifying a specific type in the `type` parameter. + +The following example loads locations for all assets labeled with `knight` or `villager`: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadLocation.cs#doc_LoadLocations)] + +## Load locations of sub-objects + +Unity generates locations for `SubObjects` at runtime to reduce the size of the content catalogs and improve runtime performance. When you call [`LoadResourceLocationsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadResourceLocationsAsync*) with the key of an asset with sub-objects and don't specify a type, then the method generates `IResourceLocation` instances for all the sub-objects and the main object. Likewise, if you don't specify which sub-object to use for an AssetReference that points to an asset with sub-objects, then the system generates `IResourceLocation` instances for every sub-object. + +For example, if you load the locations for an FBX asset, with the address, `myFBXObject`, you might get locations for three assets: a GameObject, a mesh, and a material. If, instead, you specify the type in the address, `myFBXObject[Mesh]`, you only get the mesh object. You can also specify the type using the `type` parameter of the `LoadResourceLocationsAsync` method. diff --git a/Documentation~/load-assets.md b/Documentation~/load-assets.md index 8310a6e7..12769ee3 100644 --- a/Documentation~/load-assets.md +++ b/Documentation~/load-assets.md @@ -1,29 +1,29 @@ -# Load assets - -You can use `LoadAssetAsync` or `LoadAssetsAsync` to load one, or multiple assets at runtime. - -## Load a single asset - -Use the [`LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*) method to load a single Addressable asset, typically with an address as the key: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadSingle.cs#doc_Load)] - -You can use a label or other key type when you call `LoadAssetAsync`, not just an address. However, if the key resolves to more than one asset, only the first asset found is loaded. For example, if you call this method with a label applied to several assets, Addressables returns whichever one of those assets that happens to be located first. - -## Load multiple assets - -Use the [`LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*) method to load more than one Addressable asset in a single operation. When using this method, you can specify a single key, such as a label, or a list of keys. - -When you specify multiple keys, you can specify a [merge mode](xref:UnityEngine.AddressableAssets.Addressables.MergeMode) to set how the assets that match each key are combined: - -* `Union`: Include assets that match any key -* `Intersection`: Include assets that match every key -* `UseFirst`: Include assets only from the first key that resolves to a valid location - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadMultiple.cs#doc_Load)] - -To specify how to handle loading errors, use the `releaseDependenciesOnFailure` parameter. If `true`, then the operation fails if it encounters an error loading any single asset. The operation and any assets that loaded are released. - -If `false`, then the operation loads any objects that it can and doesn't release the operation. If it fails, the operation still completes with a status of `Failed`. Also, the list of assets returned has null values where the failed assets would otherwise appear. - -Set `releaseDependenciesOnFailure` to true when loading a group of assets that must be loaded as a set to be used. For example, if you load the assets for a game level, you might fail the operation as a whole rather than load only some of the required assets. +# Load assets + +You can use `LoadAssetAsync` or `LoadAssetsAsync` to load one, or multiple assets at runtime. + +## Load a single asset + +Use the [`LoadAssetAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*) method to load a single Addressable asset, typically with an address as the key: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadSingle.cs#doc_Load)] + +You can use a label or other key type when you call `LoadAssetAsync`, not just an address. However, if the key resolves to more than one asset, only the first asset found is loaded. For example, if you call this method with a label applied to several assets, Addressables returns whichever one of those assets that happens to be located first. + +## Load multiple assets + +Use the [`LoadAssetsAsync`](xref:UnityEngine.AddressableAssets.Addressables.LoadAssetsAsync*) method to load more than one Addressable asset in a single operation. When using this method, you can specify a single key, such as a label, or a list of keys. + +When you specify multiple keys, you can specify a [merge mode](xref:UnityEngine.AddressableAssets.Addressables.MergeMode) to set how the assets that match each key are combined: + +* `Union`: Include assets that match any key +* `Intersection`: Include assets that match every key +* `UseFirst`: Include assets only from the first key that resolves to a valid location + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadMultiple.cs#doc_Load)] + +To specify how to handle loading errors, use the `releaseDependenciesOnFailure` parameter. If `true`, then the operation fails if it encounters an error loading any single asset. The operation and any assets that loaded are released. + +If `false`, then the operation loads any objects that it can and doesn't release the operation. If it fails, the operation still completes with a status of `Failed`. Also, the list of assets returned has null values where the failed assets would otherwise appear. + +Set `releaseDependenciesOnFailure` to true when loading a group of assets that must be loaded as a set to be used. For example, if you load the assets for a game level, you might fail the operation as a whole rather than load only some of the required assets. diff --git a/Documentation~/manage-addressables-intro.md b/Documentation~/manage-addressables-intro.md index f9e72767..03144c2d 100644 --- a/Documentation~/manage-addressables-intro.md +++ b/Documentation~/manage-addressables-intro.md @@ -1,44 +1,44 @@ -# Manage Addressables introduction - -Familiarize yourself with how assets create dependencies on other assets before you decide how you want to manage the assets in your project. For more information about dependencies, refer to [Asset dependencies overview](xref:addressables-asset-dependencies). - -For more information on strategies to consider when deciding how to organize your assets, refer to [Organizing Addressable assets](xref:addressables-assets-development-cycle). - -## Organize Addressables with groups - -Addressable [groups](xref:addressables-groups) are the main unit of organization that you use to manage Addressable assets. Use the Addressables Groups window to create Addressables groups, move assets between groups, and assign addresses and labels to assets. - -When you first install and set up the Addressables package, it creates a default group for Addressable assets. The Addressables system assigns any assets you mark as Addressable to this group by default. At the start of a project, you might find it acceptable to keep your assets in this single group. As you add more content, you should create additional groups so that you have better control over which resources your application loads and keeps in memory at any given time. - -Key group settings include: - -* **Build path**: Where to save your content after a content build. -* **Load path**: Where your application looks for built content at runtime. -* **Bundle mode**: How to package the content in the group into a bundle. You can choose the following options: - * One bundle containing all group assets - * A bundle for each entry in the group (useful if you mark entire folders as Addressable and want their contents built together) - * A bundle for each unique combination of labels assigned to group assets -* **Content update restriction**: Setting this value allows you to publish smaller content updates. Refer to [Content update builds](xref:addressables-content-update-builds) for more information. If you always publish full builds to update your app and don't download content from a remote source, you can ignore this setting. - -Alongside group settings, you can use the following to control how Addressables work in a project: - -* [Addressable asset settings](xref:addressables-asset-settings): The project-level settings of the Addressable assets. -* [Profiles](xref:addressables-profiles): Defines collections of build path settings that you can swap between, depending on the purpose of a build. This is most useful if you plan to distribute content remotely. -* [Labels](xref:addressables-labels): Edit the Addressable asset labels used in your project. -* [Play mode scripts](xref:addressables-groups-window): Choose how the Addressables system loads assets when you enter Play mode in the Editor. - -> [!NOTE] -> You can use Profile variables to set the build and load paths. Refer to [Profiles](AddressableAssetsProfiles.md) for more information. - -You can also control how Unity packs groups of assets into AssetBundles. You can keep groups together in one AssetBundle, separate groups into different bundles, or pack together assets that share a label. Refer to [Pack groups into AssetBundles](xref:addressables-packing-groups) for more information. - -## Manage assets through the Editor - -[AssetReferences](xref:addressables-asset-references) offer a user interface (UI) compatible way to use Addressable assets. You can include `AssetReference` fields in `MonoBehaviour` and `ScriptableObject` classes. Then, you can assign assets to them in the Unity Editor either by dragging an Addressable asset into the `AssetReference` field in the Inspector window, or using the object picker dialog. - -## Tools - -The Addressables system provides the following additional tools to help development: - -* [Build layout report](xref:addressables-build-layout-report): provides a description of the AssetBundles produced by a build. -* [Build profile log](xref:addressables-build-profile-log): provides a log of information about the performance of the build process. +# Manage Addressables introduction + +Familiarize yourself with how assets create dependencies on other assets before you decide how you want to manage the assets in your project. For more information about dependencies, refer to [Asset dependencies overview](xref:addressables-asset-dependencies). + +For more information on strategies to consider when deciding how to organize your assets, refer to [Organizing Addressable assets](xref:addressables-assets-development-cycle). + +## Organize Addressables with groups + +Addressable [groups](xref:addressables-groups) are the main unit of organization that you use to manage Addressable assets. Use the Addressables Groups window to create Addressables groups, move assets between groups, and assign addresses and labels to assets. + +When you first install and set up the Addressables package, it creates a default group for Addressable assets. The Addressables system assigns any assets you mark as Addressable to this group by default. At the start of a project, you might find it acceptable to keep your assets in this single group. As you add more content, you should create additional groups so that you have better control over which resources your application loads and keeps in memory at any given time. + +Key group settings include: + +* **Build path**: Where to save your content after a content build. +* **Load path**: Where your application looks for built content at runtime. +* **Bundle mode**: How to package the content in the group into a bundle. You can choose the following options: + * One bundle containing all group assets + * A bundle for each entry in the group (useful if you mark entire folders as Addressable and want their contents built together) + * A bundle for each unique combination of labels assigned to group assets +* **Content update restriction**: Setting this value allows you to publish smaller content updates. Refer to [Content update builds](xref:addressables-content-update-builds) for more information. If you always publish full builds to update your app and don't download content from a remote source, you can ignore this setting. + +Alongside group settings, you can use the following to control how Addressables work in a project: + +* [Addressable asset settings](xref:addressables-asset-settings): The project-level settings of the Addressable assets. +* [Profiles](xref:addressables-profiles): Defines collections of build path settings that you can swap between, depending on the purpose of a build. This is most useful if you plan to distribute content remotely. +* [Labels](xref:addressables-labels): Edit the Addressable asset labels used in your project. +* [Play mode scripts](xref:addressables-groups-window): Choose how the Addressables system loads assets when you enter Play mode in the Editor. + +> [!NOTE] +> You can use Profile variables to set the build and load paths. Refer to [Profiles](AddressableAssetsProfiles.md) for more information. + +You can also control how Unity packs groups of assets into AssetBundles. You can keep groups together in one AssetBundle, separate groups into different bundles, or pack together assets that share a label. Refer to [Pack groups into AssetBundles](xref:addressables-packing-groups) for more information. + +## Manage assets through the Editor + +[AssetReferences](xref:addressables-asset-references) offer a user interface (UI) compatible way to use Addressable assets. You can include `AssetReference` fields in `MonoBehaviour` and `ScriptableObject` classes. Then, you can assign assets to them in the Unity Editor either by dragging an Addressable asset into the `AssetReference` field in the Inspector window, or using the object picker dialog. + +## Tools + +The Addressables system provides the following additional tools to help development: + +* [Build layout report](xref:addressables-build-layout-report): provides a description of the AssetBundles produced by a build. +* [Build profile log](xref:addressables-build-profile-log): provides a log of information about the performance of the build process. diff --git a/Documentation~/memory-assetbundles.md b/Documentation~/memory-assetbundles.md index 7d602081..fcc3ced2 100644 --- a/Documentation~/memory-assetbundles.md +++ b/Documentation~/memory-assetbundles.md @@ -1,63 +1,63 @@ -# AssetBundle memory overhead - -When you load an AssetBundle, Unity allocates memory to store the bundle's internal data, and memory for the assets contained in the bundle. The main types of internal data for a loaded AssetBundle include: - -* **Loading cache**: Stores recently accessed pages of an AssetBundle file. Use [`AssetBundle.memoryBudgetKB`](xref:UnityEngine.AssetBundle.memoryBudgetKB) to control its size. -* [TypeTrees](#typetrees): Defines the serialized layout of objects. -* [Table of contents](#table-of-contents): Lists the assets in a bundle. -* [Preload table](#preload-table): Lists the dependencies of each asset. - -When you organize Addressable groups and AssetBundles, you must make trade-offs between the size and the number of AssetBundles you create and load. Fewer, larger bundles can minimize the total memory usage of your AssetBundles. However, using many small bundles can minimize the peak memory usage because Unity can easily unload assets and AssetBundles. - -The size of an AssetBundle on disk isn't the same as its size at runtime. However, you can use the disk size as a guide to the memory overhead of the AssetBundles in a build. You can get bundle size and other information to help analyze AssetBundles from the [Build Layout Report](xref:addressables-build-layout-report). - -## TypeTrees - -A TypeTree describes the field layout of one of the data types in your project. - -Each serialized file in an AssetBundle has a TypeTree for each object type within the file. You can use TypeTree information to load objects that are deserialized slightly differently from the way they were serialized. TypeTree information isn't shared between AssetBundles and each bundle has a complete set of TypeTrees for the objects it contains. - -Unity loads all the TypeTrees when it loads the AssetBundle, and holds it in memory for the lifetime of the AssetBundle. The memory overhead associated with TypeTrees is proportional to the number of unique types in the serialized file and the complexity of those types. - -### Reduce TypeTree memory - -You can reduce the memory requirements of AssetBundle TypeTrees in the following ways: - -* Keep assets of the same types together in the same bundles. -* Disable TypeTrees, excludes TypeTree information from a bundle, and makes the AssetBundles smaller. However, without TypeTree information, when you load older bundles with a newer version of Unity or make script changes in your project, you might get serialization errors or undefined behavior. -* Use simple data types to reduce TypeTree complexity. - -To test the impact that TypeTrees have on the size of AssetBundles, build them with and without TypeTrees disabled and compare their sizes. Use [`BuildAssetBundleOptions.DisableWriteTypeTree`](xref:UnityEditor.BuildAssetBundleOptions.DisableWriteTypeTree) to disable TypeTrees in your AssetBundles. - ->[!NOTE] ->Some platforms require TypeTrees and ignore the `DisableWriteTypeTree` setting. Additionally, not all platforms support TypeTrees. - -If you disable TypeTrees in a project, always rebuild local Addressable groups before building a new player. If your project distributes content remotely, use the same version (including patch number) of Unity that you used to produce the player and don't make minor code changes. If you're using multiple player versions, updates, and versions of Unity, you might not find the memory savings from disabling TypeTrees to be worth the trouble. - -## Table of contents - -The table of contents is a map in the bundle that you can use to look up each explicitly included asset by name. It scales linearly with the number of assets and the length of the string names by which they are mapped. - -The size of the table of contents data is based on the total number of assets. To minimize the amount of memory dedicated to holding table of content data, minimize the number of AssetBundles loaded at a given time. - -## Preload table - -The preload table is a list of all the other objects that an asset references. Unity uses the preload table to load these referenced objects when you load an asset from the AssetBundle. - -For example, a prefab has a preload entry for each of its components and any other assets it might reference such as materials or textures. Each preload entry is 64 bits and can reference objects in other AssetBundles. - -When an asset references another asset that in turn references other assets, the preload table can become large because it contains the entries needed to load both assets. If two assets both reference a third asset, then the preload tables of both assets contain entries to load the third asset, whether the referenced asset is Addressable or in the same AssetBundle. - -For example, a project has two assets in an AssetBundle (`PrefabA` and `PrefabB`) and both of these prefabs reference a third prefab (`PrefabC`), which is large and has several components and references to other assets. This AssetBundle has two preload tables, one for `PrefabA` and one for `PrefabB`. Those tables contain entries for all the objects of their respective prefab, but also entries for all the objects in `PrefabC` and any objects that `PrefabC` references. The information required to load `PrefabC` ends up duplicated in both `PrefabA` and `PrefabB`. This happens whether `PrefabC` is explicitly added to an AssetBundle or not. - -Depending on how you organize the assets in a project, the preload tables in AssetBundles might be large and contain many duplicate entries. This is true if you have several loadable assets that all reference a complex asset, such as `PrefabC` in the example. If you decide that the memory overhead from the preload table is a problem, you can structure the loadable assets in your project so that they have fewer complex loading dependencies. - -## Loading AssetBundle dependencies - -Loading an Addressable asset also loads all the AssetBundles containing its dependencies. An AssetBundle dependency happens when an asset in one bundle references an asset in another bundle. For example, when a material references a texture. For more information refer to [Asset and AssetBundle dependencies](xref:addressables-asset-dependencies). - -Addressables calculates dependencies between bundles at the bundle level. If one asset references an object in another bundle, then the entire bundle has a dependency on that bundle. This means that even if you load an asset in the first bundle that has no dependencies of its own, the second AssetBundle is still loaded into memory. - -For example,`BundleA` contains Addressable assets `RootAsset1` and `RootAsset2`. `RootAsset2` references `DependencyAsset3`, which is in `BundleB`. Even though `RootAsset1` has no reference to `BundleB`, `BundleB` is still a dependency of `RootAsset1` because `RootAsset1` is in `BundleA`, which has a reference to `BundleB`. - -To avoid loading more bundles than you need, keep the dependencies between AssetBundles as simple as possible. You can use the [Build Layout Report](xref:addressables-build-layout-report) to check dependencies. +# AssetBundle memory overhead + +When you load an AssetBundle, Unity allocates memory to store the bundle's internal data, and memory for the assets contained in the bundle. The main types of internal data for a loaded AssetBundle include: + +* **Loading cache**: Stores recently accessed pages of an AssetBundle file. Use [`AssetBundle.memoryBudgetKB`](xref:UnityEngine.AssetBundle.memoryBudgetKB) to control its size. +* [TypeTrees](#typetrees): Defines the serialized layout of objects. +* [Table of contents](#table-of-contents): Lists the assets in a bundle. +* [Preload table](#preload-table): Lists the dependencies of each asset. + +When you organize Addressable groups and AssetBundles, you must make trade-offs between the size and the number of AssetBundles you create and load. Fewer, larger bundles can minimize the total memory usage of your AssetBundles. However, using many small bundles can minimize the peak memory usage because Unity can easily unload assets and AssetBundles. + +The size of an AssetBundle on disk isn't the same as its size at runtime. However, you can use the disk size as a guide to the memory overhead of the AssetBundles in a build. You can get bundle size and other information to help analyze AssetBundles from the [Build Layout Report](xref:addressables-build-layout-report). + +## TypeTrees + +A TypeTree describes the field layout of one of the data types in your project. + +Each serialized file in an AssetBundle has a TypeTree for each object type within the file. You can use TypeTree information to load objects that are deserialized slightly differently from the way they were serialized. TypeTree information isn't shared between AssetBundles and each bundle has a complete set of TypeTrees for the objects it contains. + +Unity loads all the TypeTrees when it loads the AssetBundle, and holds it in memory for the lifetime of the AssetBundle. The memory overhead associated with TypeTrees is proportional to the number of unique types in the serialized file and the complexity of those types. + +### Reduce TypeTree memory + +You can reduce the memory requirements of AssetBundle TypeTrees in the following ways: + +* Keep assets of the same types together in the same bundles. +* Disable TypeTrees, excludes TypeTree information from a bundle, and makes the AssetBundles smaller. However, without TypeTree information, when you load older bundles with a newer version of Unity or make script changes in your project, you might get serialization errors or undefined behavior. +* Use simple data types to reduce TypeTree complexity. + +To test the impact that TypeTrees have on the size of AssetBundles, build them with and without TypeTrees disabled and compare their sizes. Use [`BuildAssetBundleOptions.DisableWriteTypeTree`](xref:UnityEditor.BuildAssetBundleOptions.DisableWriteTypeTree) to disable TypeTrees in your AssetBundles. + +>[!NOTE] +>Some platforms require TypeTrees and ignore the `DisableWriteTypeTree` setting. Additionally, not all platforms support TypeTrees. + +If you disable TypeTrees in a project, always rebuild local Addressable groups before building a new player. If your project distributes content remotely, use the same version (including patch number) of Unity that you used to produce the player and don't make minor code changes. If you're using multiple player versions, updates, and versions of Unity, you might not find the memory savings from disabling TypeTrees to be worth the trouble. + +## Table of contents + +The table of contents is a map in the bundle that you can use to look up each explicitly included asset by name. It scales linearly with the number of assets and the length of the string names by which they are mapped. + +The size of the table of contents data is based on the total number of assets. To minimize the amount of memory dedicated to holding table of content data, minimize the number of AssetBundles loaded at a given time. + +## Preload table + +The preload table is a list of all the other objects that an asset references. Unity uses the preload table to load these referenced objects when you load an asset from the AssetBundle. + +For example, a prefab has a preload entry for each of its components and any other assets it might reference such as materials or textures. Each preload entry is 64 bits and can reference objects in other AssetBundles. + +When an asset references another asset that in turn references other assets, the preload table can become large because it contains the entries needed to load both assets. If two assets both reference a third asset, then the preload tables of both assets contain entries to load the third asset, whether the referenced asset is Addressable or in the same AssetBundle. + +For example, a project has two assets in an AssetBundle (`PrefabA` and `PrefabB`) and both of these prefabs reference a third prefab (`PrefabC`), which is large and has several components and references to other assets. This AssetBundle has two preload tables, one for `PrefabA` and one for `PrefabB`. Those tables contain entries for all the objects of their respective prefab, but also entries for all the objects in `PrefabC` and any objects that `PrefabC` references. The information required to load `PrefabC` ends up duplicated in both `PrefabA` and `PrefabB`. This happens whether `PrefabC` is explicitly added to an AssetBundle or not. + +Depending on how you organize the assets in a project, the preload tables in AssetBundles might be large and contain many duplicate entries. This is true if you have several loadable assets that all reference a complex asset, such as `PrefabC` in the example. If you decide that the memory overhead from the preload table is a problem, you can structure the loadable assets in your project so that they have fewer complex loading dependencies. + +## Loading AssetBundle dependencies + +Loading an Addressable asset also loads all the AssetBundles containing its dependencies. An AssetBundle dependency happens when an asset in one bundle references an asset in another bundle. For example, when a material references a texture. For more information refer to [Asset and AssetBundle dependencies](xref:addressables-asset-dependencies). + +Addressables calculates dependencies between bundles at the bundle level. If one asset references an object in another bundle, then the entire bundle has a dependency on that bundle. This means that even if you load an asset in the first bundle that has no dependencies of its own, the second AssetBundle is still loaded into memory. + +For example,`BundleA` contains Addressable assets `RootAsset1` and `RootAsset2`. `RootAsset2` references `DependencyAsset3`, which is in `BundleB`. Even though `RootAsset1` has no reference to `BundleB`, `BundleB` is still a dependency of `RootAsset1` because `RootAsset1` is in `BundleA`, which has a reference to `BundleB`. + +To avoid loading more bundles than you need, keep the dependencies between AssetBundles as simple as possible. You can use the [Build Layout Report](xref:addressables-build-layout-report) to check dependencies. diff --git a/Documentation~/organize-addressable-assets.md b/Documentation~/organize-addressable-assets.md index 26b349b2..d63f8dd6 100644 --- a/Documentation~/organize-addressable-assets.md +++ b/Documentation~/organize-addressable-assets.md @@ -1,74 +1,74 @@ -# Organize Addressable assets - -The best way to organize your assets depends on the specific requirements of each project. Aspects to consider when planning how to manage your assets in a project include: - -* **Logical organization**: Keep assets in logical categories to make it easier to understand your organization and discover items that are out of place. -* **Runtime performance**: Performance bottlenecks can happen if your AssetBundles grow in size, or if you have many AssetBundles. -* **Runtime memory management**: Keep assets together that you use together to help lower peak memory requirements. -* **Scale**: Some ways of organizing assets might work well in small games, but not large ones, and vice versa. -* **Platform characteristics**: The characteristics and requirements of a platform can be a large consideration in how to organize your assets. Some examples: - * Platforms that offer abundant virtual memory can handle large bundle sizes better than those with limited virtual memory. - * Some platforms don't support downloading content, ruling out remote distribution of assets entirely. - * Some platforms don't support AssetBundle caching, so putting assets in local bundles, when possible, is more efficient. -* **Distribution**: Whether you distribute your content remotely or not means that you must separate your remote content from your local content. -* **How often assets are updated**: Keep assets that you expect to update often separate from those that you don't intend to update often. -* **Version control**: The more people who work on the same assets and asset groups, the greater the chance for version control conflicts to happen in a project. - -## Common strategies - -Typical strategies for organizing assets include: - -* **Concurrent usage**: Group assets that you load at the same time together, such as all the assets for a given level. This strategy is often the most effective in the long term and can help reduce peak memory use in a project. -* **Logical entity**: Group assets belonging to the same logical entity together. For example, user interface (UI) layout assets, textures, sound effects. Or character models and animations. -* **Type**: Group assets of the same type together. For example, music files, textures. - -Depending on the needs of your project, one of these strategies might make more sense than the others. For example, in a game with many levels, organizing according to concurrent usage might be the most efficient both from a project management and from a runtime memory performance standpoint. - -At the same time, you might use different strategies for different types of assets. For example, you might group your UI assets for menu screens together in a level-based game that otherwise groups its level data separately. You might also pack a group that has the assets for a level into bundles that contain a particular asset type. - -Refer to [Preparing Assets for AssetBundles](xref:AssetBundles-Preparing) for additional information. - -## Strategies for common platforms - -The Addressables system creates AssetBundles based on the [Groups](Groups.md) you create. Your choices about the size and number of those AssetBundles, and when you choose to load and unload them, can have a significant impact on your project's install time, load time, and performance. -For this reason, it's important to choose a strategy that takes into account the metrics that might affect your project the most, when organizing your Addressables assets into Groups. - -The information below describes some of these metrics, how they differ by platform, and how to optimize your strategy accordingly. - -While there is no single solution that works for all projects, you should always try to limit AssetBundles to only contain assets that you expect to unload together. This is important to consider because your application can’t unload an asset that isn’t needed anymore if the application still needs any other asset in the same AssetBundle. - -## Mobile apps - -The key performance metrics to consider when you target mobile devices are app installation size, load times and download speed. Smaller builds take less time to download and install, so it’s important to minimize the size of your app. Mobile apps also need to perform well on low-powered devices at runtime. - -### Reduce app size - -Smaller final builds download faster and use less of the device’s storage after installation. Both are important to consider on low-powered mobile devices because a faster download and install time can improve user retention. - -You can use remote content distribution to deliver some of your content after a user installs your app. Keep as much content as possible remote to reduce the initial download and installation size of your app. - -You can use the Build report window to measure the impact of features on the size. - -### Choose an appropriate bundled content size - -The size of your AssetBundles affects how fast they load and unload.. For a mobile app where you might need to load many different levels in one play session, a larger number of smaller bundles can ensure that each bundle loads faster. - -There’s a small performance impact for every AssetBundle you load because each one increases the size of the catalog. Using too many small AssetBundles can create a large catalog that has a greater performance impact than using fewer large AssetBundles. Check the size of the catalog in the [Streaming assets](https://docs.unity3d.com/2022.3/Documentation/Manual/StreamingAssets.html) folder for a variety of bundle sizes to decide on the best balance of size and number of bundles for your mobile app. - -## Desktop applications - -For desktop devices, download times are usually less important than runtime performance and loading times. A larger application on higher-end devices can justify a long download time, but not poor performance at runtime or long delays while content loads. - -### Reduce loading times - -For projects where you can use more runtime memory, you can preload AssetBundles that your project will need in the future. You can do this during existing waiting times (loading screens, transitions between content) or when the application starts. This increases the loading time once, but reduces or eliminates any load times in future for the preloaded AssetBundles. - -### Optimize runtime performance - -Desktop platforms have fewer constraints around device memory and storage. To take advantage of this, use group settings that don’t compress your AssetBundles. Uncompressed AssetBundles provide faster loading at runtime and more efficient patches, but increase application size. - -## XR platforms - -Requirements and constraints for XR platforms are often similar to mobile platforms. A key difference is in how important a consistent frame rate at runtime is. Any stuttering or reduction in frame rate in an XR application can cause discomfort for your user. - -To help compensate for this, minimize the loading that your XR application needs to do at runtime. Preload AssetBundles wherever possible in the same way as described in the [Reduce loading times](#reduce-loading-times) section earlier on this page. +# Organize Addressable assets + +The best way to organize your assets depends on the specific requirements of each project. Aspects to consider when planning how to manage your assets in a project include: + +* **Logical organization**: Keep assets in logical categories to make it easier to understand your organization and discover items that are out of place. +* **Runtime performance**: Performance bottlenecks can happen if your AssetBundles grow in size, or if you have many AssetBundles. +* **Runtime memory management**: Keep assets together that you use together to help lower peak memory requirements. +* **Scale**: Some ways of organizing assets might work well in small games, but not large ones, and vice versa. +* **Platform characteristics**: The characteristics and requirements of a platform can be a large consideration in how to organize your assets. Some examples: + * Platforms that offer abundant virtual memory can handle large bundle sizes better than those with limited virtual memory. + * Some platforms don't support downloading content, ruling out remote distribution of assets entirely. + * Some platforms don't support AssetBundle caching, so putting assets in local bundles, when possible, is more efficient. +* **Distribution**: Whether you distribute your content remotely or not means that you must separate your remote content from your local content. +* **How often assets are updated**: Keep assets that you expect to update often separate from those that you don't intend to update often. +* **Version control**: The more people who work on the same assets and asset groups, the greater the chance for version control conflicts to happen in a project. + +## Common strategies + +Typical strategies for organizing assets include: + +* **Concurrent usage**: Group assets that you load at the same time together, such as all the assets for a given level. This strategy is often the most effective in the long term and can help reduce peak memory use in a project. +* **Logical entity**: Group assets belonging to the same logical entity together. For example, user interface (UI) layout assets, textures, sound effects. Or character models and animations. +* **Type**: Group assets of the same type together. For example, music files, textures. + +Depending on the needs of your project, one of these strategies might make more sense than the others. For example, in a game with many levels, organizing according to concurrent usage might be the most efficient both from a project management and from a runtime memory performance standpoint. + +At the same time, you might use different strategies for different types of assets. For example, you might group your UI assets for menu screens together in a level-based game that otherwise groups its level data separately. You might also pack a group that has the assets for a level into bundles that contain a particular asset type. + +Refer to [Preparing Assets for AssetBundles](xref:AssetBundles-Preparing) for additional information. + +## Strategies for common platforms + +The Addressables system creates AssetBundles based on the [Groups](Groups.md) you create. Your choices about the size and number of those AssetBundles, and when you choose to load and unload them, can have a significant impact on your project's install time, load time, and performance. +For this reason, it's important to choose a strategy that takes into account the metrics that might affect your project the most, when organizing your Addressables assets into Groups. + +The information below describes some of these metrics, how they differ by platform, and how to optimize your strategy accordingly. + +While there is no single solution that works for all projects, you should always try to limit AssetBundles to only contain assets that you expect to unload together. This is important to consider because your application can’t unload an asset that isn’t needed anymore if the application still needs any other asset in the same AssetBundle. + +## Mobile apps + +The key performance metrics to consider when you target mobile devices are app installation size, load times and download speed. Smaller builds take less time to download and install, so it’s important to minimize the size of your app. Mobile apps also need to perform well on low-powered devices at runtime. + +### Reduce app size + +Smaller final builds download faster and use less of the device’s storage after installation. Both are important to consider on low-powered mobile devices because a faster download and install time can improve user retention. + +You can use remote content distribution to deliver some of your content after a user installs your app. Keep as much content as possible remote to reduce the initial download and installation size of your app. + +You can use the Build report window to measure the impact of features on the size. + +### Choose an appropriate bundled content size + +The size of your AssetBundles affects how fast they load and unload.. For a mobile app where you might need to load many different levels in one play session, a larger number of smaller bundles can ensure that each bundle loads faster. + +There’s a small performance impact for every AssetBundle you load because each one increases the size of the catalog. Using too many small AssetBundles can create a large catalog that has a greater performance impact than using fewer large AssetBundles. Check the size of the catalog in the [Streaming assets](https://docs.unity3d.com/2022.3/Documentation/Manual/StreamingAssets.html) folder for a variety of bundle sizes to decide on the best balance of size and number of bundles for your mobile app. + +## Desktop applications + +For desktop devices, download times are usually less important than runtime performance and loading times. A larger application on higher-end devices can justify a long download time, but not poor performance at runtime or long delays while content loads. + +### Reduce loading times + +For projects where you can use more runtime memory, you can preload AssetBundles that your project will need in the future. You can do this during existing waiting times (loading screens, transitions between content) or when the application starts. This increases the loading time once, but reduces or eliminates any load times in future for the preloaded AssetBundles. + +### Optimize runtime performance + +Desktop platforms have fewer constraints around device memory and storage. To take advantage of this, use group settings that don’t compress your AssetBundles. Uncompressed AssetBundles provide faster loading at runtime and more efficient patches, but increase application size. + +## XR platforms + +Requirements and constraints for XR platforms are often similar to mobile platforms. A key difference is in how important a consistent frame rate at runtime is. Any stuttering or reduction in frame rate in an XR application can cause discomfort for your user. + +To help compensate for this, minimize the loading that your XR application needs to do at runtime. Preload AssetBundles wherever possible in the same way as described in the [Reduce loading times](#reduce-loading-times) section earlier on this page. diff --git a/Documentation~/profiles-build-load-paths.md b/Documentation~/profiles-build-load-paths.md index 24ae3676..74485f17 100644 --- a/Documentation~/profiles-build-load-paths.md +++ b/Documentation~/profiles-build-load-paths.md @@ -1,10 +1,10 @@ -# Set a build and load path - -Once you set up the necessary [variables](ProfileVariables.md) in your profile, you can select the build and load paths for an asset group based on those specified variables. - -To set build and load paths: - -1. Select an Addressable Assets group from the __Project__ window. -2. In the group’s __Inspector__, under __Content Packing & Loading__ > __Build and Load Paths__, select the desired path pair. If you choose the `` option, you can specify the build and load paths separately. - +# Set a build and load path + +Once you set up the necessary [variables](ProfileVariables.md) in your profile, you can select the build and load paths for an asset group based on those specified variables. + +To set build and load paths: + +1. Select an Addressable Assets group from the __Project__ window. +2. In the group’s __Inspector__, under __Content Packing & Loading__ > __Build and Load Paths__, select the desired path pair. If you choose the `` option, you can specify the build and load paths separately. + You need to select a variable representing the path defined in the __Profiles__ window rather than entering a path directly. The __Path Preview__ displays the current path, based on the active Profile. To edit a path directly, in the [group settings Inspector](GroupSchemas.md), set __Build & Load Paths__ to `` and set the individual __Build__ or __Load Path__ to ``. The edited path applies to that group only. \ No newline at end of file diff --git a/Documentation~/profiles-create.md b/Documentation~/profiles-create.md index 85e731f4..9c889aff 100644 --- a/Documentation~/profiles-create.md +++ b/Documentation~/profiles-create.md @@ -1,21 +1,21 @@ -# Create a profile - -To create a new profile, open the [Addressables Profile window](addressables-profiles-window.md), select __Create__ > __Profile__. A new profile row appears in the table. - -Every profile must define a value for every variable. When you create a new profile, Addressables copies all values from the selected profile. - -## Set the active profile - -The active profile determines the set of variables used when you run a build script. - -To set the active profile, either: - -1. Open the Groups window (menu: __Window > Asset Management > Addressables > Groups__). -2. Click the __Profile__ menu in the toolbar. -3. Choose the profile to make active. - -Or: - -1. Open the Profiles window (menu: __Window > Asset Management > Addressables > Profiles__). -2. Right-click on a profile to open the context menu. -3. Choose __Set Active__. +# Create a profile + +To create a new profile, open the [Addressables Profile window](addressables-profiles-window.md), select __Create__ > __Profile__. A new profile row appears in the table. + +Every profile must define a value for every variable. When you create a new profile, Addressables copies all values from the selected profile. + +## Set the active profile + +The active profile determines the set of variables used when you run a build script. + +To set the active profile, either: + +1. Open the Groups window (menu: __Window > Asset Management > Addressables > Groups__). +2. Click the __Profile__ menu in the toolbar. +3. Choose the profile to make active. + +Or: + +1. Open the Profiles window (menu: __Window > Asset Management > Addressables > Profiles__). +2. Right-click on a profile to open the context menu. +3. Choose __Set Active__. diff --git a/Documentation~/profiles-introduction.md b/Documentation~/profiles-introduction.md index c66dba56..bd3fa048 100644 --- a/Documentation~/profiles-introduction.md +++ b/Documentation~/profiles-introduction.md @@ -1,34 +1,34 @@ -# Profiles introduction - -A profile contains a set of variables that the Addressables build scripts uses. These variables define information such as where to save build artifacts and where to load data at runtime. You can add custom profile variables to use in your own build scripts. - -To manage the profiles in your project, use the [Addressables Profiles window](addressables-profiles-window.md) (menu: __Window > Asset Management > Addressables > Profiles__). - -You can set up different profiles for the different phases or tasks in your development process. For example, you might create a profile to use while developing your project, another to use for testing, and one to use for final publishing or release. Setting up the profiles in advance and swapping between them is best practice, rather than editing the values individually when you move to a different phase or perform a different task. - -> [!TIP] -> Using multiple profiles is most helpful when you distribute content for your application remotely. If you distribute all content as part of your application install, then the single, default profile might be the only profile you need. - -## Profile examples - -Consider the following example, which demonstrates the local development phase of your content: - -![](images/profiles-example-local.png)
*Content with local and remote bundles stored locally for development.* - -While in development, you would have both your local and remote bundles using local paths: - -![](images/profiles-example-local-paths.png)
*Paths set for local development.* - -In this instance, the local and remote paths are in fact local, which makes it unnecessary to set up a remote server just for local development. - -Once the content is ready for production, you can move the remote bundles to a server: - -![](images/profiles-example-remote.png)
*Content with the remote bundles moved to a server for production.* - -In this case, if you use profiles, you can change the remote load path for `Production` to that server. Without having to change your asset groups, you can change all of your remote bundles to remote. - -![](images/profiles-example-remote-paths.png)
*Paths set for hosting remote content* - -The Addressables system only copies data from [Addressables.BuildPath](xref:UnityEngine.AddressableAssets.Addressables.BuildPath) to the StreamingAssets folder during a Player build. It doesn't handle arbitrary paths specified through the LocalBuildPath or LocalLoadPath variables. If you build data to a different location or load data from a different location than the default, you must copy the data manually. - -Similarly, you must manually upload remote AssetBundles and associated catalog and hash files to your server so that they can be accessed at the URL defined by __RemoteLoadPath__. +# Profiles introduction + +A profile contains a set of variables that the Addressables build scripts uses. These variables define information such as where to save build artifacts and where to load data at runtime. You can add custom profile variables to use in your own build scripts. + +To manage the profiles in your project, use the [Addressables Profiles window](addressables-profiles-window.md) (menu: __Window > Asset Management > Addressables > Profiles__). + +You can set up different profiles for the different phases or tasks in your development process. For example, you might create a profile to use while developing your project, another to use for testing, and one to use for final publishing or release. Setting up the profiles in advance and swapping between them is best practice, rather than editing the values individually when you move to a different phase or perform a different task. + +> [!TIP] +> Using multiple profiles is most helpful when you distribute content for your application remotely. If you distribute all content as part of your application install, then the single, default profile might be the only profile you need. + +## Profile examples + +Consider the following example, which demonstrates the local development phase of your content: + +![](images/profiles-example-local.png)
*Content with local and remote bundles stored locally for development.* + +While in development, you would have both your local and remote bundles using local paths: + +![](images/profiles-example-local-paths.png)
*Paths set for local development.* + +In this instance, the local and remote paths are in fact local, which makes it unnecessary to set up a remote server just for local development. + +Once the content is ready for production, you can move the remote bundles to a server: + +![](images/profiles-example-remote.png)
*Content with the remote bundles moved to a server for production.* + +In this case, if you use profiles, you can change the remote load path for `Production` to that server. Without having to change your asset groups, you can change all of your remote bundles to remote. + +![](images/profiles-example-remote-paths.png)
*Paths set for hosting remote content* + +The Addressables system only copies data from [Addressables.BuildPath](xref:UnityEngine.AddressableAssets.Addressables.BuildPath) to the StreamingAssets folder during a Player build. It doesn't handle arbitrary paths specified through the LocalBuildPath or LocalLoadPath variables. If you build data to a different location or load data from a different location than the default, you must copy the data manually. + +Similarly, you must manually upload remote AssetBundles and associated catalog and hash files to your server so that they can be accessed at the URL defined by __RemoteLoadPath__. diff --git a/Documentation~/projectMetadata.json b/Documentation~/projectMetadata.json index 0fd5db91..5795f4d6 100644 --- a/Documentation~/projectMetadata.json +++ b/Documentation~/projectMetadata.json @@ -1,4 +1,4 @@ -{ - "hideGlobalNamespace": false, - "useMemberPages": true +{ + "hideGlobalNamespace": false, + "useMemberPages": true } \ No newline at end of file diff --git a/Documentation~/remote-content-assetbundle-cache.md b/Documentation~/remote-content-assetbundle-cache.md index 6591a319..48cc1e72 100644 --- a/Documentation~/remote-content-assetbundle-cache.md +++ b/Documentation~/remote-content-assetbundle-cache.md @@ -1,19 +1,19 @@ -# Remote content AssetBundle caching - -By default, AssetBundles produced for an Addressables build are cached on the client device after they are downloaded. Cached bundles are only downloaded again if they are updated or if they are deleted from the cache. - -An updated catalog can exclude bundle entries present in an older version of the catalog. When these entries are cached, their data is no longer needed on the device. - -When you have unneeded cache data on the device, you can choose one of the following options: - -* To delete the entire bundle cache, use [`Caching.ClearCache`](xref:UnityEngine.Caching.ClearCache). -* To remove cache entries that are no longer referenced at any time, use [`Addressables.CleanBundleCache`](xref:UnityEngine.AddressableAssets.Addressables.CleanBundleCache*). You usually call this function after initializing Addressables (see [Customizing Addressables initialization](xref:addressables-api-initialize-async)) or after loading additional catalogs (see [Managing catalogs at runtime](xref:addressables-api-load-content-catalog-async)). -* To automatically call [`Addressables.CleanBundleCache`](xref:UnityEngine.AddressableAssets.Addressables.CleanBundleCache*) after updating catalogs, use the parameter `autoCleanBundleCache` in [`Addressables.UpdateCatalogs`](xref:UnityEngine.AddressableAssets.Addressables.UpdateCatalogs(System.Boolean,System.Collections.Generic.IEnumerable{System.String},System.Boolean)). Refer to [Checking for content updates at runtime](xref:addressables-content-update-builds) for an example script. - -If you disable caching for a group, the remote bundles produced for the group are stored in memory when they are downloaded until you unload them or the application exits. The next time the application loads the bundle, Addressables downloads it again. - -You can control whether the bundles produced by a group are cached or not with the __Use Asset Bundle Cache__ setting under [Advanced Options](xref:addressables-content-packing-and-loading-schema) in the Group Inspector. - -See [AssetBundle compression](xref:AssetBundles-Cache) for additional information about AssetBundle caching. The Addressables system sets the cache-related parameters of the [`UnityWebRequests`](xref:UnityEngine.Networking.UnityWebRequest) it uses to download Addressable bundles based on the group settings. - +# Remote content AssetBundle caching + +By default, AssetBundles produced for an Addressables build are cached on the client device after they are downloaded. Cached bundles are only downloaded again if they are updated or if they are deleted from the cache. + +An updated catalog can exclude bundle entries present in an older version of the catalog. When these entries are cached, their data is no longer needed on the device. + +When you have unneeded cache data on the device, you can choose one of the following options: + +* To delete the entire bundle cache, use [`Caching.ClearCache`](xref:UnityEngine.Caching.ClearCache). +* To remove cache entries that are no longer referenced at any time, use [`Addressables.CleanBundleCache`](xref:UnityEngine.AddressableAssets.Addressables.CleanBundleCache*). You usually call this function after initializing Addressables (see [Customizing Addressables initialization](xref:addressables-api-initialize-async)) or after loading additional catalogs (see [Managing catalogs at runtime](xref:addressables-api-load-content-catalog-async)). +* To automatically call [`Addressables.CleanBundleCache`](xref:UnityEngine.AddressableAssets.Addressables.CleanBundleCache*) after updating catalogs, use the parameter `autoCleanBundleCache` in [`Addressables.UpdateCatalogs`](xref:UnityEngine.AddressableAssets.Addressables.UpdateCatalogs(System.Boolean,System.Collections.Generic.IEnumerable{System.String},System.Boolean)). Refer to [Checking for content updates at runtime](xref:addressables-content-update-builds) for an example script. + +If you disable caching for a group, the remote bundles produced for the group are stored in memory when they are downloaded until you unload them or the application exits. The next time the application loads the bundle, Addressables downloads it again. + +You can control whether the bundles produced by a group are cached or not with the __Use Asset Bundle Cache__ setting under [Advanced Options](xref:addressables-content-packing-and-loading-schema) in the Group Inspector. + +See [AssetBundle compression](xref:AssetBundles-Cache) for additional information about AssetBundle caching. The Addressables system sets the cache-related parameters of the [`UnityWebRequests`](xref:UnityEngine.Networking.UnityWebRequest) it uses to download Addressable bundles based on the group settings. + Note that there are some limitations for WebGL AssetBundles. For more information, see [Building and running a WebGL project](xref:webgl-building). \ No newline at end of file diff --git a/Documentation~/remote-content-enable.md b/Documentation~/remote-content-enable.md index 5f818c71..1763e186 100644 --- a/Documentation~/remote-content-enable.md +++ b/Documentation~/remote-content-enable.md @@ -1,26 +1,26 @@ -# Enable remote distribution - -To enable remote distribution of your content, you must enable the remote catalog and set up the [groups](Groups.md) containing the assets you want to host remotely. - -## Enabling the remote catalog - -Enable the remote catalog in the __Addressable Asset Settings__ Inspector (menu: __Window > Asset Management > Addressables > Settings__). - -* __Build Remote Catalog__: Enabled -* __Build & Load Paths__: Set to remote - -The catalog and its accompanying hash file are built to the folder specified by the __Build Path__ setting. You must upload these files so that they can be accessed at the URL specified by your __Load Path__ setting. Unless you have a specific reason not to, use the __Remote__ location so that the catalog is built to and loaded from the same paths as your remote bundles. - -## Set up a remote group - -To set up a group so that the assets in it can be hosted remotely, set the [Build & Load Paths](AddressableAssetSettings.md) to the __Remote__ location. - -If you plan to publish content updates between publishing full rebuilds of your application, set the __Update Restriction__ value according to how often you expect to update content in a group. - -Choose __Cannot Change Post Release__ for groups that produce larger bundles, especially if you do not anticipate changing most of the assets in the group. If you do change assets in a group with this setting, the Addressables tools move the changed assets to a new group for the update. Only the new bundles are downloaded by installed applications. - -Choose __Can Change Post Release__ for groups containing assets that you expect to change frequently. If you change assets in a group with this setting, the bundles containing those assets are rebuilt as a whole and will be redownloaded by installed applications. To reduce the amount of data that needs to be downloaded after an update, try to keep the bundles produced by groups with this setting as small as possible. - -Refer to [Content update builds](content-update-builds-overview.md) for more information about updating remote content. - +# Enable remote distribution + +To enable remote distribution of your content, you must enable the remote catalog and set up the [groups](Groups.md) containing the assets you want to host remotely. + +## Enabling the remote catalog + +Enable the remote catalog in the __Addressable Asset Settings__ Inspector (menu: __Window > Asset Management > Addressables > Settings__). + +* __Build Remote Catalog__: Enabled +* __Build & Load Paths__: Set to remote + +The catalog and its accompanying hash file are built to the folder specified by the __Build Path__ setting. You must upload these files so that they can be accessed at the URL specified by your __Load Path__ setting. Unless you have a specific reason not to, use the __Remote__ location so that the catalog is built to and loaded from the same paths as your remote bundles. + +## Set up a remote group + +To set up a group so that the assets in it can be hosted remotely, set the [Build & Load Paths](AddressableAssetSettings.md) to the __Remote__ location. + +If you plan to publish content updates between publishing full rebuilds of your application, set the __Update Restriction__ value according to how often you expect to update content in a group. + +Choose __Cannot Change Post Release__ for groups that produce larger bundles, especially if you do not anticipate changing most of the assets in the group. If you do change assets in a group with this setting, the Addressables tools move the changed assets to a new group for the update. Only the new bundles are downloaded by installed applications. + +Choose __Can Change Post Release__ for groups containing assets that you expect to change frequently. If you change assets in a group with this setting, the bundles containing those assets are rebuilt as a whole and will be redownloaded by installed applications. To reduce the amount of data that needs to be downloaded after an update, try to keep the bundles produced by groups with this setting as small as possible. + +Refer to [Content update builds](content-update-builds-overview.md) for more information about updating remote content. + The __Advanced Options__ section contains some options that affect remote hosting and downloads but aren't necessary to enable remote hosting. Refer to [Advanced Options](GroupSchemas.md) for more information. \ No newline at end of file diff --git a/Documentation~/remote-content-intro.md b/Documentation~/remote-content-intro.md index 45dc7296..20b6fc5d 100644 --- a/Documentation~/remote-content-intro.md +++ b/Documentation~/remote-content-intro.md @@ -1,35 +1,35 @@ -# Distribute remote content overview - -You can use Addressables to support remote distribution of content through a Content Delivery Network (CDN) or other hosting service. Unity provides the Unity Cloud Content Delivery (CCD) service for this purpose, but you can use any CDN or host you prefer. - -Distributing content remotely can reduce initial app download size and install time. You can also update remotely distributed assets without republishing your application. - -When you assign a remote URL as the Load Path of a group, the Addressables system loads assets in the group from that URL. When you enable the **Build Remote Catalog** property, the Addressables system looks up the addresses of any remote assets in the remote catalog. This enables you to make changes to Addressable assets without forcing users to reinstall the updated version of your application. - -To build content for remote distribution, you must: - -* Go to __Windows > Asset Management > Addressables > Settings__ and enable the __Build Remote Catalog__ property. -* In the [Profile](xref:addressables-profiles) you use to publish content, configure the __RemoteLoadPath__ to reflect the remote URL at which you plan to access the content. -* For each Addressables group containing assets you want to deliver remotely, set the __Build Path__ property to __RemoteBuildPath__ and the __Load Path__ property to __RemoteLoadPath__. -* Set the desired __Platform Target__ property in the __Build Settings__ window. - -After you make a content build through the Addressables __Groups__ window and a player build through the __Build Settings__ window, you must upload the files created in the folder designated by your profile's __RemoteBuildPath__ to your hosting service. The files to upload include: - -* Any AssetBundles (name.bundle) -* The catalog file (catalog_timestamp.json) -* The catalog hash (catalog_timestamp.hash) - -After [enabling remote distribution](remote-content-enable.md), you can build your content in two ways: - -* A full [content build](builds-full-build.md) using the **New Build > Default Build Script** builds all content bundles and catalogs. Always perform a full build before rebuilding your player when preparing to publish or update your full application. -* A [content update build](builds-update-build.md) using the **Update a Previous Build** script builds all content bundles and catalogs, but sets up the remote catalog so that installed applications only need to download the changed bundles. Run the [Check for Content Update Restrictions](content-update-build-create.md#check-for-content-update-restrictions-tool) tool to identify changes and prepare your groups before building an update. - -After building a full build or an update, you must upload your remote catalog, catalog hash file, and remote bundles to your hosting service. - -Refer to [Remote content profiles](remote-content-profiles.md) for tips on setting up Addressables Profiles to help you develop, test, and publish remote content. - -## Custom URL evaluation - -There are several scenarios where you might need to customize the path or URL of an Asset (often an AssetBundle) at runtime. The most common example is creating signed URLs. Another is dynamic host determination. - -Refer to [ID transform function](xref:addressables-api-transform-internal-id) for more information. +# Distribute remote content overview + +You can use Addressables to support remote distribution of content through a Content Delivery Network (CDN) or other hosting service. Unity provides the Unity Cloud Content Delivery (CCD) service for this purpose, but you can use any CDN or host you prefer. + +Distributing content remotely can reduce initial app download size and install time. You can also update remotely distributed assets without republishing your application. + +When you assign a remote URL as the Load Path of a group, the Addressables system loads assets in the group from that URL. When you enable the **Build Remote Catalog** property, the Addressables system looks up the addresses of any remote assets in the remote catalog. This enables you to make changes to Addressable assets without forcing users to reinstall the updated version of your application. + +To build content for remote distribution, you must: + +* Go to __Windows > Asset Management > Addressables > Settings__ and enable the __Build Remote Catalog__ property. +* In the [Profile](xref:addressables-profiles) you use to publish content, configure the __RemoteLoadPath__ to reflect the remote URL at which you plan to access the content. +* For each Addressables group containing assets you want to deliver remotely, set the __Build Path__ property to __RemoteBuildPath__ and the __Load Path__ property to __RemoteLoadPath__. +* Set the desired __Platform Target__ property in the __Build Settings__ window. + +After you make a content build through the Addressables __Groups__ window and a player build through the __Build Settings__ window, you must upload the files created in the folder designated by your profile's __RemoteBuildPath__ to your hosting service. The files to upload include: + +* Any AssetBundles (name.bundle) +* The catalog file (catalog_timestamp.json) +* The catalog hash (catalog_timestamp.hash) + +After [enabling remote distribution](remote-content-enable.md), you can build your content in two ways: + +* A full [content build](builds-full-build.md) using the **New Build > Default Build Script** builds all content bundles and catalogs. Always perform a full build before rebuilding your player when preparing to publish or update your full application. +* A [content update build](builds-update-build.md) using the **Update a Previous Build** script builds all content bundles and catalogs, but sets up the remote catalog so that installed applications only need to download the changed bundles. Run the [Check for Content Update Restrictions](content-update-build-create.md#check-for-content-update-restrictions-tool) tool to identify changes and prepare your groups before building an update. + +After building a full build or an update, you must upload your remote catalog, catalog hash file, and remote bundles to your hosting service. + +Refer to [Remote content profiles](remote-content-profiles.md) for tips on setting up Addressables Profiles to help you develop, test, and publish remote content. + +## Custom URL evaluation + +There are several scenarios where you might need to customize the path or URL of an Asset (often an AssetBundle) at runtime. The most common example is creating signed URLs. Another is dynamic host determination. + +Refer to [ID transform function](xref:addressables-api-transform-internal-id) for more information. diff --git a/Documentation~/remote-content-predownload.md b/Documentation~/remote-content-predownload.md index 3bdc5f18..c1b90371 100644 --- a/Documentation~/remote-content-predownload.md +++ b/Documentation~/remote-content-predownload.md @@ -1,22 +1,22 @@ -# Pre-download remote content - -In situations where you want to pre-download content so that it is cached on disk and faster to access when the application needs it, you can use the [`Addressables.DownloadDependenciesAsync`](xref:UnityEngine.AddressableAssets.Addressables.DownloadDependenciesAsync*) method. This method downloads an Addressable entity and any dependencies as a background task. - -Calling the `Addressables.DownloadDependenciesAsync` method loads the dependencies for the address or label that you pass in. Typically, this is the AssetBundle. - -The [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) struct returned by this call includes a PercentComplete attribute that you can use to monitor and display download progress. You can also have the app wait until the content has loaded. - -## PercentComplete - -PercentComplete takes into account several aspects of the underlying operations being handled by a single `AsyncOperationHandle`. There may be instances where the progression isn't linear, or some semblance of linear. This can be due to quick operations being weighted the same as operations that will take longer. - -For example, given an asset you wish to load from a remote location that takes a non-trivial amount of time to download and is reliant on a local bundle as a dependency you'll see your PercentComplete jump to 50% before continuing. This is because the local bundle is able to be loaded much quicker than the remote bundle. However, all the system is aware of is the need for two operations to be complete. - -If you wish to ask the user for consent prior to download, use [`Addressables.GetDownloadSize`](xref:UnityEngine.AddressableAssets.Addressables.GetDownloadSize*) to return how much space is needed to download the content from a given address or label. Note that this takes into account any previously downloaded bundles that are still in Unity's AssetBundle cache. - -While it can be advantageous to download assets for your app in advance, there are instances where you might choose not to do so. For example: - -* If your application has a large amount of online content, and you generally expect users to only ever interact with a portion of it. -* You have an app that must be connected online to function. If all your app's content is in small bundles, you might choose to download content as needed. - -Rather than using the percent complete value to wait until the content is loaded, you can use the preload functionality to show that the download has started, then continue on. This implementation would require a loading or waiting screen to handle instances where the asset has not finished loading by the time it's needed. +# Pre-download remote content + +In situations where you want to pre-download content so that it is cached on disk and faster to access when the application needs it, you can use the [`Addressables.DownloadDependenciesAsync`](xref:UnityEngine.AddressableAssets.Addressables.DownloadDependenciesAsync*) method. This method downloads an Addressable entity and any dependencies as a background task. + +Calling the `Addressables.DownloadDependenciesAsync` method loads the dependencies for the address or label that you pass in. Typically, this is the AssetBundle. + +The [`AsyncOperationHandle`](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle) struct returned by this call includes a PercentComplete attribute that you can use to monitor and display download progress. You can also have the app wait until the content has loaded. + +## PercentComplete + +PercentComplete takes into account several aspects of the underlying operations being handled by a single `AsyncOperationHandle`. There may be instances where the progression isn't linear, or some semblance of linear. This can be due to quick operations being weighted the same as operations that will take longer. + +For example, given an asset you wish to load from a remote location that takes a non-trivial amount of time to download and is reliant on a local bundle as a dependency you'll see your PercentComplete jump to 50% before continuing. This is because the local bundle is able to be loaded much quicker than the remote bundle. However, all the system is aware of is the need for two operations to be complete. + +If you wish to ask the user for consent prior to download, use [`Addressables.GetDownloadSize`](xref:UnityEngine.AddressableAssets.Addressables.GetDownloadSize*) to return how much space is needed to download the content from a given address or label. Note that this takes into account any previously downloaded bundles that are still in Unity's AssetBundle cache. + +While it can be advantageous to download assets for your app in advance, there are instances where you might choose not to do so. For example: + +* If your application has a large amount of online content, and you generally expect users to only ever interact with a portion of it. +* You have an app that must be connected online to function. If all your app's content is in small bundles, you might choose to download content as needed. + +Rather than using the percent complete value to wait until the content is loaded, you can use the preload functionality to show that the download has started, then continue on. This implementation would require a loading or waiting screen to handle instances where the asset has not finished loading by the time it's needed. diff --git a/Documentation~/remote-content-profiles.md b/Documentation~/remote-content-profiles.md index 3a7de2d5..d19974bf 100644 --- a/Documentation~/remote-content-profiles.md +++ b/Documentation~/remote-content-profiles.md @@ -1,32 +1,32 @@ -# Remote content profiles - -A [Profile](profiles-introduction.md) defines variables that you can use to set the build and load paths for both your local and remote content. - -When you distribute content remotely, you typically need to set different URLs (load paths) for your remote content depending on why you are making a build. Some examples of such situations include: - -## Builds for testing general game play and function - -Early in development or when you need to test without access to a host, you might find it convenient to treat all your content as local content. For this situation set the __Local__ and __Remote__ profile variables using the __Built-In__ location. - -## Builds for local hosting - -Later, when you set up a host on your local network (or localhost), you will need to change the Load Path for your remote groups to reflect the URL of the host. For example if using [Editor Hosting], set the __Remote__ profile variable using the __Editor Hosting__ location. - -## Builds for CDN - -As you get closer to production, you might use a staging server and then, your production Content Delivery Network (CDN). For example if using [Cloud Content Delivery], set the __Remote__ profile variable using the __Cloud Content Delivery__ location. - -## Other profiles - -Even after release, you might want to use different host URLs for beta testing or other purposes. - -Rather than hand configuring the build and load paths every time you build, you can create a different Profile and set the variables appropriately. Then, you can easily switch between Profiles before making a content build without worrying about misconfiguring the paths. - -If you use a script to launch your content builds, then you can use the Addressables API to choose a specific Profile for a build. Refer to [Starting an Addressables build from a script](build-scripting-start-build.md). - -If you have complex URLs, you can reference static fields or properties in your Profile variables that are evaluated at build- or runtime. For example, rather than entering your CCD ProjectID as a string, you could create an Editor class that provides the information as a static property and reference it as `CCDInfo.ProjectID`. Refer to [Profile variable syntax](xref:addressables-profile-variables) for more information. - -[`InternalIdTransformFunc`](xref:addressables-api-transform-internal-id) methods provide an additional method of handling complex URL requirements. - -> [!NOTE] +# Remote content profiles + +A [Profile](profiles-introduction.md) defines variables that you can use to set the build and load paths for both your local and remote content. + +When you distribute content remotely, you typically need to set different URLs (load paths) for your remote content depending on why you are making a build. Some examples of such situations include: + +## Builds for testing general game play and function + +Early in development or when you need to test without access to a host, you might find it convenient to treat all your content as local content. For this situation set the __Local__ and __Remote__ profile variables using the __Built-In__ location. + +## Builds for local hosting + +Later, when you set up a host on your local network (or localhost), you will need to change the Load Path for your remote groups to reflect the URL of the host. For example if using [Editor Hosting], set the __Remote__ profile variable using the __Editor Hosting__ location. + +## Builds for CDN + +As you get closer to production, you might use a staging server and then, your production Content Delivery Network (CDN). For example if using [Cloud Content Delivery], set the __Remote__ profile variable using the __Cloud Content Delivery__ location. + +## Other profiles + +Even after release, you might want to use different host URLs for beta testing or other purposes. + +Rather than hand configuring the build and load paths every time you build, you can create a different Profile and set the variables appropriately. Then, you can easily switch between Profiles before making a content build without worrying about misconfiguring the paths. + +If you use a script to launch your content builds, then you can use the Addressables API to choose a specific Profile for a build. Refer to [Starting an Addressables build from a script](build-scripting-start-build.md). + +If you have complex URLs, you can reference static fields or properties in your Profile variables that are evaluated at build- or runtime. For example, rather than entering your CCD ProjectID as a string, you could create an Editor class that provides the information as a static property and reference it as `CCDInfo.ProjectID`. Refer to [Profile variable syntax](xref:addressables-profile-variables) for more information. + +[`InternalIdTransformFunc`](xref:addressables-api-transform-internal-id) methods provide an additional method of handling complex URL requirements. + +> [!NOTE] > If your remote URL requires cannot be expressed as a static string see [Custom URL evaluation](xref:addressables-api-transform-internal-id) for information about how you can rewrite the URL for assets, including AssetBundles, at runtime. \ No newline at end of file diff --git a/Documentation~/safely-edit-loaded-asset.md b/Documentation~/safely-edit-loaded-asset.md index 23262d37..df9ea62f 100644 --- a/Documentation~/safely-edit-loaded-asset.md +++ b/Documentation~/safely-edit-loaded-asset.md @@ -1,26 +1,26 @@ -# Safely edit a loaded asset - -You can safely edit a loaded Asset in the following situations: - -* The Asset is loaded from an AssetBundle. -* The application is running in a Player, not in the Editor. -* When you enable the **Use Existing Build (requires built groups)** option in [Play mode scripts](xref:addressables-groups-window). - -In these cases, the assets exist as a copy in active memory. Changes made to these copied assets don't affect the saved AssetBundle on disk and any changes don't persist between sessions. - -For other situations, including when you enable the **Use Asset Database (fastest)** property in the Play mode settings, Unity loads the Assets directly from the Project files. This means that Unity saves any modifications to the Asset during runtime to the Project Asset file and that those changes will persist between different sessions. - -If you want to make runtime changes to an asset, create a new instance of the GameObject you want to change and use the copy for any runtime changes. This eliminates the risk that you might accidentally change the original asset file. The following code example demonstrates creating a new copy of a loaded asset: - -```c# -var op = Addressables.LoadAssetAsync("myKey"); -yield return op; -if (op.Result != null) -{ - GameObject inst = UnityEngine.Object.Instantiate(op.Result); - // can now use and safely make edits to inst, without the source Project Asset being changed. -} -``` - -If you use this example method to use a copy of an asset, be aware of the following: -* You must use either the original asset or the `AsyncOperationHandle` when you release the asset, not the current instance of the asset. +# Safely edit a loaded asset + +You can safely edit a loaded Asset in the following situations: + +* The Asset is loaded from an AssetBundle. +* The application is running in a Player, not in the Editor. +* When you enable the **Use Existing Build (requires built groups)** option in [Play mode scripts](xref:addressables-groups-window). + +In these cases, the assets exist as a copy in active memory. Changes made to these copied assets don't affect the saved AssetBundle on disk and any changes don't persist between sessions. + +For other situations, including when you enable the **Use Asset Database (fastest)** property in the Play mode settings, Unity loads the Assets directly from the Project files. This means that Unity saves any modifications to the Asset during runtime to the Project Asset file and that those changes will persist between different sessions. + +If you want to make runtime changes to an asset, create a new instance of the GameObject you want to change and use the copy for any runtime changes. This eliminates the risk that you might accidentally change the original asset file. The following code example demonstrates creating a new copy of a loaded asset: + +```c# +var op = Addressables.LoadAssetAsync("myKey"); +yield return op; +if (op.Result != null) +{ + GameObject inst = UnityEngine.Object.Instantiate(op.Result); + // can now use and safely make edits to inst, without the source Project Asset being changed. +} +``` + +If you use this example method to use a copy of an asset, be aware of the following: +* You must use either the original asset or the `AsyncOperationHandle` when you release the asset, not the current instance of the asset. diff --git a/Documentation~/use-addresssables-introduction.md b/Documentation~/use-addresssables-introduction.md index 1b9e21f3..26fc0375 100644 --- a/Documentation~/use-addresssables-introduction.md +++ b/Documentation~/use-addresssables-introduction.md @@ -1,45 +1,45 @@ -# Use an Addressable asset - -To load and use an Addressable asset, you can: - -* [Use an AssetReference that references the asset](#use-assetreferences) -* [Use its address string](#load-by-address) -* [Use a label assigned to the asset](#load-by-address) - -Refer to [Loading assets](xref:addressables-api-load-asset-async) for more detailed information about loading Addressable assets. - -Loading Addressable assets uses asynchronous operations. Refer to [Operations](xref:addressables-async-operation-handling) for information about the different ways to approach asynchronous programming in Unity scripts. - -> [!TIP] -> You can find more involved examples of how to use Addressable assets in the [Addressables Sample repository](https://github.com/Unity-Technologies/Addressables-Sample). - -## Use AssetReferences - -To use an `AssetReference`, add an `AssetReference` field to a `MonoBehaviour` or `ScriptableObject`. After you create an object of that type, you can assign an asset to the field in your object's Inspector window. - -> [!NOTE] -> If you assign a non-Addressable asset to an AssetReference field, Unity automatically makes that asset Addressable and adds it to your default Addressables group. AssetReferences also let you use Addressable assets in a Scene that isn't itself Addressable. - -Unity doesn't load or release the referenced asset automatically; you must load and release the asset using the `Addressables` API: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithReference.cs#doc_LoadWithReference)] - -Refer to [Loading an AssetReference](xref:addressables-loading-asset-reference) for additional information about loading AssetReferences. - -## Load by address - -You can use the address string to load an asset: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithAddress.cs#doc_LoadWithAddress)] - -Remember that every time you load an asset, you must also release it. - -Refer to [Loading a single asset](load-assets.md#load-a-single-asset) for more information. - -## Load by label - -You can load sets of assets that have the same label in one operation: - -[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithLabels.cs#doc_LoadWithLabels)] - -Refer to [Loading multiple assets](load-assets.md#load-multiple-assets) for more information. +# Use an Addressable asset + +To load and use an Addressable asset, you can: + +* [Use an AssetReference that references the asset](#use-assetreferences) +* [Use its address string](#load-by-address) +* [Use a label assigned to the asset](#load-by-address) + +Refer to [Loading assets](xref:addressables-api-load-asset-async) for more detailed information about loading Addressable assets. + +Loading Addressable assets uses asynchronous operations. Refer to [Operations](xref:addressables-async-operation-handling) for information about the different ways to approach asynchronous programming in Unity scripts. + +> [!TIP] +> You can find more involved examples of how to use Addressable assets in the [Addressables Sample repository](https://github.com/Unity-Technologies/Addressables-Sample). + +## Use AssetReferences + +To use an `AssetReference`, add an `AssetReference` field to a `MonoBehaviour` or `ScriptableObject`. After you create an object of that type, you can assign an asset to the field in your object's Inspector window. + +> [!NOTE] +> If you assign a non-Addressable asset to an AssetReference field, Unity automatically makes that asset Addressable and adds it to your default Addressables group. AssetReferences also let you use Addressable assets in a Scene that isn't itself Addressable. + +Unity doesn't load or release the referenced asset automatically; you must load and release the asset using the `Addressables` API: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithReference.cs#doc_LoadWithReference)] + +Refer to [Loading an AssetReference](xref:addressables-loading-asset-reference) for additional information about loading AssetReferences. + +## Load by address + +You can use the address string to load an asset: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithAddress.cs#doc_LoadWithAddress)] + +Remember that every time you load an asset, you must also release it. + +Refer to [Loading a single asset](load-assets.md#load-a-single-asset) for more information. + +## Load by label + +You can load sets of assets that have the same label in one operation: + +[!code-cs[sample](../Tests/Editor/DocExampleCode/LoadWithLabels.cs#doc_LoadWithLabels)] + +Refer to [Loading multiple assets](load-assets.md#load-multiple-assets) for more information. diff --git a/Editor.meta b/Editor.meta index 60f5d642..465782bb 100644 --- a/Editor.meta +++ b/Editor.meta @@ -1,10 +1,10 @@ -fileFormatVersion: 2 -guid: b38733bdad235b34b993286370a11791 -folderAsset: yes -timeCreated: 1498750562 -licenseType: Pro -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: b38733bdad235b34b993286370a11791 +folderAsset: yes +timeCreated: 1498750562 +licenseType: Pro +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/AddressableAssetSettingsDefaultObject.cs b/Editor/AddressableAssetSettingsDefaultObject.cs index 19350ad5..d642c0e6 100644 --- a/Editor/AddressableAssetSettingsDefaultObject.cs +++ b/Editor/AddressableAssetSettingsDefaultObject.cs @@ -1,181 +1,181 @@ -using System; -using UnityEditor.AddressableAssets.Settings; -using UnityEngine; -using UnityEngine.Serialization; - -namespace UnityEditor.AddressableAssets -{ - /// - /// Class used to get and set the default Addressable Asset settings object. - /// - public class AddressableAssetSettingsDefaultObject : ScriptableObject - { - /// - /// Default name for the addressable assets settings - /// - public const string kDefaultConfigAssetName = "AddressableAssetSettings"; - - /// - /// The default folder for the serialized version of this class. - /// - public const string kDefaultConfigFolder = "Assets/AddressableAssetsData"; - - /// - /// The name of the default config object - /// - public const string kDefaultConfigObjectName = "com.unity.addressableassets"; - - /// - /// Default path for addressable asset settings assets. - /// - public static string DefaultAssetPath - { - get { return kDefaultConfigFolder + "/" + kDefaultConfigAssetName + ".asset"; } - } - - [FormerlySerializedAs("m_addressableAssetSettingsGuid")] - [SerializeField] - internal string m_AddressableAssetSettingsGuid; - - bool m_LoadingSettingsObject = false; - - internal AddressableAssetSettings LoadSettingsObject() - { - //prevent re-entrant stack overflow - if (m_LoadingSettingsObject) - { - Debug.LogWarning("Detected stack overflow when accessing AddressableAssetSettingsDefaultObject.Settings object."); - return null; - } - - if (string.IsNullOrEmpty(m_AddressableAssetSettingsGuid)) - { - Debug.LogError("Invalid guid for default AddressableAssetSettings object."); - return null; - } - - var path = AssetDatabase.GUIDToAssetPath(m_AddressableAssetSettingsGuid); - if (string.IsNullOrEmpty(path)) - { - Debug.LogErrorFormat("Unable to determine path for default AddressableAssetSettings object with guid {0}.", m_AddressableAssetSettingsGuid); - return null; - } - - m_LoadingSettingsObject = true; - var settings = AssetDatabase.LoadAssetAtPath(path); - if (settings != null) - AddressablesAssetPostProcessor.OnPostProcess.Register(settings.OnPostprocessAllAssets, 0); - m_LoadingSettingsObject = false; - return settings; - } - - void SetSettingsObject(AddressableAssetSettings settings) - { - if (settings == null) - { - m_AddressableAssetSettingsGuid = null; - return; - } - - var path = AssetDatabase.GetAssetPath(settings); - if (string.IsNullOrEmpty(path)) - { - Debug.LogErrorFormat("Unable to determine path for default AddressableAssetSettings object with guid {0}.", m_AddressableAssetSettingsGuid); - return; - } - - AddressablesAssetPostProcessor.OnPostProcess.Register(settings.OnPostprocessAllAssets, 0); - m_AddressableAssetSettingsGuid = AssetDatabase.AssetPathToGUID(path); - } - - static AddressableAssetSettings s_DefaultSettingsObject; - - /// - /// Used to determine if a default settings asset exists. - /// - public static bool SettingsExists - { - get - { - AddressableAssetSettingsDefaultObject so; - if (EditorBuildSettings.TryGetConfigObject(kDefaultConfigObjectName, out so)) - return !string.IsNullOrEmpty(AssetDatabase.GUIDToAssetPath(so.m_AddressableAssetSettingsGuid)); - return false; - } - } - - /// - /// Gets the default addressable asset settings object. This will return null during editor startup if EditorApplication.isUpdating or EditorApplication.isCompiling are true. - /// - public static AddressableAssetSettings Settings - { - get - { - if (s_DefaultSettingsObject == null) - { - AddressableAssetSettingsDefaultObject so; - if (EditorBuildSettings.TryGetConfigObject(kDefaultConfigObjectName, out so)) - { - s_DefaultSettingsObject = so.LoadSettingsObject(); - } - else - { - //legacy support, try to get the old config object and then remove it - if (EditorBuildSettings.TryGetConfigObject(kDefaultConfigAssetName, out s_DefaultSettingsObject)) - { - EditorBuildSettings.RemoveConfigObject(kDefaultConfigAssetName); - so = CreateInstance(); - so.SetSettingsObject(s_DefaultSettingsObject); - AssetDatabase.CreateAsset(so, kDefaultConfigFolder + "/DefaultObject.asset"); - EditorUtility.SetDirty(so); - AddressableAssetUtility.OpenAssetIfUsingVCIntegration(kDefaultConfigFolder + "/DefaultObject.asset"); - AssetDatabase.SaveAssets(); - EditorBuildSettings.AddConfigObject(kDefaultConfigObjectName, so, true); - } - } - } - - return s_DefaultSettingsObject; - } - set - { - if (value != null) - { - var path = AssetDatabase.GetAssetPath(value); - if (string.IsNullOrEmpty(path)) - { - Debug.LogErrorFormat("AddressableAssetSettings object must be saved to an asset before it can be set as the default."); - return; - } - } - - s_DefaultSettingsObject = value; - AddressableAssetSettingsDefaultObject so; - if (!EditorBuildSettings.TryGetConfigObject(kDefaultConfigObjectName, out so)) - { - so = CreateInstance(); - AssetDatabase.CreateAsset(so, kDefaultConfigFolder + "/DefaultObject.asset"); - AssetDatabase.SaveAssets(); - EditorBuildSettings.AddConfigObject(kDefaultConfigObjectName, so, true); - } - - so.SetSettingsObject(s_DefaultSettingsObject); - EditorUtility.SetDirty(so); - AddressableAssetUtility.OpenAssetIfUsingVCIntegration(kDefaultConfigFolder + "/DefaultObject.asset"); - AssetDatabase.SaveAssets(); - } - } - - /// - /// Gets the settings object with the option to create a new one if it does not exist. - /// - /// If true and no settings object exists, a new one will be created using the default config folder and asset name. - /// The default settings object. - public static AddressableAssetSettings GetSettings(bool create) - { - if (Settings == null && create) - Settings = AddressableAssetSettings.Create(kDefaultConfigFolder, kDefaultConfigAssetName, true, true); - return Settings; - } - } -} +using System; +using UnityEditor.AddressableAssets.Settings; +using UnityEngine; +using UnityEngine.Serialization; + +namespace UnityEditor.AddressableAssets +{ + /// + /// Class used to get and set the default Addressable Asset settings object. + /// + public class AddressableAssetSettingsDefaultObject : ScriptableObject + { + /// + /// Default name for the addressable assets settings + /// + public const string kDefaultConfigAssetName = "AddressableAssetSettings"; + + /// + /// The default folder for the serialized version of this class. + /// + public const string kDefaultConfigFolder = "Assets/AddressableAssetsData"; + + /// + /// The name of the default config object + /// + public const string kDefaultConfigObjectName = "com.unity.addressableassets"; + + /// + /// Default path for addressable asset settings assets. + /// + public static string DefaultAssetPath + { + get { return kDefaultConfigFolder + "/" + kDefaultConfigAssetName + ".asset"; } + } + + [FormerlySerializedAs("m_addressableAssetSettingsGuid")] + [SerializeField] + internal string m_AddressableAssetSettingsGuid; + + bool m_LoadingSettingsObject = false; + + internal AddressableAssetSettings LoadSettingsObject() + { + //prevent re-entrant stack overflow + if (m_LoadingSettingsObject) + { + Debug.LogWarning("Detected stack overflow when accessing AddressableAssetSettingsDefaultObject.Settings object."); + return null; + } + + if (string.IsNullOrEmpty(m_AddressableAssetSettingsGuid)) + { + Debug.LogError("Invalid guid for default AddressableAssetSettings object."); + return null; + } + + var path = AssetDatabase.GUIDToAssetPath(m_AddressableAssetSettingsGuid); + if (string.IsNullOrEmpty(path)) + { + Debug.LogErrorFormat("Unable to determine path for default AddressableAssetSettings object with guid {0}.", m_AddressableAssetSettingsGuid); + return null; + } + + m_LoadingSettingsObject = true; + var settings = AssetDatabase.LoadAssetAtPath(path); + if (settings != null) + AddressablesAssetPostProcessor.OnPostProcess.Register(settings.OnPostprocessAllAssets, 0); + m_LoadingSettingsObject = false; + return settings; + } + + void SetSettingsObject(AddressableAssetSettings settings) + { + if (settings == null) + { + m_AddressableAssetSettingsGuid = null; + return; + } + + var path = AssetDatabase.GetAssetPath(settings); + if (string.IsNullOrEmpty(path)) + { + Debug.LogErrorFormat("Unable to determine path for default AddressableAssetSettings object with guid {0}.", m_AddressableAssetSettingsGuid); + return; + } + + AddressablesAssetPostProcessor.OnPostProcess.Register(settings.OnPostprocessAllAssets, 0); + m_AddressableAssetSettingsGuid = AssetDatabase.AssetPathToGUID(path); + } + + static AddressableAssetSettings s_DefaultSettingsObject; + + /// + /// Used to determine if a default settings asset exists. + /// + public static bool SettingsExists + { + get + { + AddressableAssetSettingsDefaultObject so; + if (EditorBuildSettings.TryGetConfigObject(kDefaultConfigObjectName, out so)) + return !string.IsNullOrEmpty(AssetDatabase.GUIDToAssetPath(so.m_AddressableAssetSettingsGuid)); + return false; + } + } + + /// + /// Gets the default addressable asset settings object. This will return null during editor startup if EditorApplication.isUpdating or EditorApplication.isCompiling are true. + /// + public static AddressableAssetSettings Settings + { + get + { + if (s_DefaultSettingsObject == null) + { + AddressableAssetSettingsDefaultObject so; + if (EditorBuildSettings.TryGetConfigObject(kDefaultConfigObjectName, out so)) + { + s_DefaultSettingsObject = so.LoadSettingsObject(); + } + else + { + //legacy support, try to get the old config object and then remove it + if (EditorBuildSettings.TryGetConfigObject(kDefaultConfigAssetName, out s_DefaultSettingsObject)) + { + EditorBuildSettings.RemoveConfigObject(kDefaultConfigAssetName); + so = CreateInstance(); + so.SetSettingsObject(s_DefaultSettingsObject); + AssetDatabase.CreateAsset(so, kDefaultConfigFolder + "/DefaultObject.asset"); + EditorUtility.SetDirty(so); + AddressableAssetUtility.OpenAssetIfUsingVCIntegration(kDefaultConfigFolder + "/DefaultObject.asset"); + AssetDatabase.SaveAssets(); + EditorBuildSettings.AddConfigObject(kDefaultConfigObjectName, so, true); + } + } + } + + return s_DefaultSettingsObject; + } + set + { + if (value != null) + { + var path = AssetDatabase.GetAssetPath(value); + if (string.IsNullOrEmpty(path)) + { + Debug.LogErrorFormat("AddressableAssetSettings object must be saved to an asset before it can be set as the default."); + return; + } + } + + s_DefaultSettingsObject = value; + AddressableAssetSettingsDefaultObject so; + if (!EditorBuildSettings.TryGetConfigObject(kDefaultConfigObjectName, out so)) + { + so = CreateInstance(); + AssetDatabase.CreateAsset(so, kDefaultConfigFolder + "/DefaultObject.asset"); + AssetDatabase.SaveAssets(); + EditorBuildSettings.AddConfigObject(kDefaultConfigObjectName, so, true); + } + + so.SetSettingsObject(s_DefaultSettingsObject); + EditorUtility.SetDirty(so); + AddressableAssetUtility.OpenAssetIfUsingVCIntegration(kDefaultConfigFolder + "/DefaultObject.asset"); + AssetDatabase.SaveAssets(); + } + } + + /// + /// Gets the settings object with the option to create a new one if it does not exist. + /// + /// If true and no settings object exists, a new one will be created using the default config folder and asset name. + /// The default settings object. + public static AddressableAssetSettings GetSettings(bool create) + { + if (Settings == null && create) + Settings = AddressableAssetSettings.Create(kDefaultConfigFolder, kDefaultConfigAssetName, true, true); + return Settings; + } + } +} diff --git a/Editor/AddressableAssetSettingsDefaultObject.cs.meta b/Editor/AddressableAssetSettingsDefaultObject.cs.meta index 8d2ca11b..5151bf0f 100644 --- a/Editor/AddressableAssetSettingsDefaultObject.cs.meta +++ b/Editor/AddressableAssetSettingsDefaultObject.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 3a189bb168d8d90478a09ea08c2f3d72 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 3a189bb168d8d90478a09ea08c2f3d72 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/AddressableEditorInitialization.cs b/Editor/AddressableEditorInitialization.cs index 2b6fe44f..87839e25 100644 --- a/Editor/AddressableEditorInitialization.cs +++ b/Editor/AddressableEditorInitialization.cs @@ -1,68 +1,68 @@ -using System.Collections.Generic; -using System.IO; -using System.Text; -using UnityEditor.AddressableAssets.Settings; -using UnityEngine.AddressableAssets; - -namespace UnityEditor.AddressableAssets -{ - [InitializeOnLoad] - internal class AddressableEditorInitialization - { - private const string m_EditorInitializedBoolName = nameof(m_EditorInitializedBoolName); - - static AddressableEditorInitialization() - { - bool editorInitialized = SessionState.GetBool(m_EditorInitializedBoolName, false); - if (editorInitialized) return; - - if (Directory.Exists(Addressables.LibraryPath)) - PurgeInvalidAssetEntries(AddressableAssetSettingsDefaultObject.Settings); - - SessionState.SetBool(m_EditorInitializedBoolName, true); - } - - internal static void PurgeInvalidAssetEntries(AddressableAssetSettings settings) - { - if (settings == null) return; - List entriesToRemove = new List(); - - foreach (var group in settings.groups) - { - if (group == null) - continue; - - foreach (var assetEntry in group.entries) - { - if (assetEntry == null || - assetEntry.address == AddressableAssetEntry.EditorSceneListName || - assetEntry.address == AddressableAssetEntry.ResourcesName) - continue; - - if (!string.IsNullOrEmpty(assetEntry.AssetPath)) - { - string path = Path.GetFullPath(assetEntry.AssetPath); - if (!File.Exists(path) && !Directory.Exists(path)) - entriesToRemove.Add(assetEntry); - } - else - entriesToRemove.Add(assetEntry); - } - } - - StringBuilder builder = new StringBuilder( - "Addressables was unable to detect the following assets in the project " + - "but they were still part of an Addressable group. They have been removed " + - "from Addressables."); - - foreach (var entry in entriesToRemove) - { - builder.AppendLine($"\n{entry.address} at {entry.AssetPath}"); - settings.RemoveAssetEntry(entry, false); - } - - if (entriesToRemove.Count > 0) - Addressables.Log(builder.ToString()); - } - } -} +using System.Collections.Generic; +using System.IO; +using System.Text; +using UnityEditor.AddressableAssets.Settings; +using UnityEngine.AddressableAssets; + +namespace UnityEditor.AddressableAssets +{ + [InitializeOnLoad] + internal class AddressableEditorInitialization + { + private const string m_EditorInitializedBoolName = nameof(m_EditorInitializedBoolName); + + static AddressableEditorInitialization() + { + bool editorInitialized = SessionState.GetBool(m_EditorInitializedBoolName, false); + if (editorInitialized) return; + + if (Directory.Exists(Addressables.LibraryPath)) + PurgeInvalidAssetEntries(AddressableAssetSettingsDefaultObject.Settings); + + SessionState.SetBool(m_EditorInitializedBoolName, true); + } + + internal static void PurgeInvalidAssetEntries(AddressableAssetSettings settings) + { + if (settings == null) return; + List entriesToRemove = new List(); + + foreach (var group in settings.groups) + { + if (group == null) + continue; + + foreach (var assetEntry in group.entries) + { + if (assetEntry == null || + assetEntry.address == AddressableAssetEntry.EditorSceneListName || + assetEntry.address == AddressableAssetEntry.ResourcesName) + continue; + + if (!string.IsNullOrEmpty(assetEntry.AssetPath)) + { + string path = Path.GetFullPath(assetEntry.AssetPath); + if (!File.Exists(path) && !Directory.Exists(path)) + entriesToRemove.Add(assetEntry); + } + else + entriesToRemove.Add(assetEntry); + } + } + + StringBuilder builder = new StringBuilder( + "Addressables was unable to detect the following assets in the project " + + "but they were still part of an Addressable group. They have been removed " + + "from Addressables."); + + foreach (var entry in entriesToRemove) + { + builder.AppendLine($"\n{entry.address} at {entry.AssetPath}"); + settings.RemoveAssetEntry(entry, false); + } + + if (entriesToRemove.Count > 0) + Addressables.Log(builder.ToString()); + } + } +} diff --git a/Editor/AddressableEditorInitialization.cs.meta b/Editor/AddressableEditorInitialization.cs.meta index dc0a64b6..2edb7c52 100644 --- a/Editor/AddressableEditorInitialization.cs.meta +++ b/Editor/AddressableEditorInitialization.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: bf8251aa3d694f2459ee1fbb73cf9123 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: bf8251aa3d694f2459ee1fbb73cf9123 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/AssemblyInfo.cs b/Editor/AssemblyInfo.cs index d8f4afcd..3a88bd63 100644 --- a/Editor/AssemblyInfo.cs +++ b/Editor/AssemblyInfo.cs @@ -1,10 +1,10 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -[assembly: AssemblyCompany("Unity Technologies")] -[assembly: InternalsVisibleTo("Unity.Addressables.Editor.BuildReportVisualizer")] -[assembly: InternalsVisibleTo("Unity.Addressables.Editor.Tests")] -[assembly: InternalsVisibleTo("Unity.Addressables.Tests")] -[assembly: InternalsVisibleTo("PerformanceTests.Editor")] -[assembly: InternalsVisibleTo("Unity.Localization.Editor")] -[assembly: InternalsVisibleTo("Unity.Addressables.Android.Editor")] +using System.Reflection; +using System.Runtime.CompilerServices; + +[assembly: AssemblyCompany("Unity Technologies")] +[assembly: InternalsVisibleTo("Unity.Addressables.Editor.BuildReportVisualizer")] +[assembly: InternalsVisibleTo("Unity.Addressables.Editor.Tests")] +[assembly: InternalsVisibleTo("Unity.Addressables.Tests")] +[assembly: InternalsVisibleTo("PerformanceTests.Editor")] +[assembly: InternalsVisibleTo("Unity.Localization.Editor")] +[assembly: InternalsVisibleTo("Unity.Addressables.Android.Editor")] diff --git a/Editor/AssemblyInfo.cs.meta b/Editor/AssemblyInfo.cs.meta index 6e935635..13c7bb1a 100644 --- a/Editor/AssemblyInfo.cs.meta +++ b/Editor/AssemblyInfo.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 053ca114086a74fd6842a2f9944a47cc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 053ca114086a74fd6842a2f9944a47cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build.meta b/Editor/Build.meta index beeedc5c..34a0be74 100644 --- a/Editor/Build.meta +++ b/Editor/Build.meta @@ -1,10 +1,10 @@ -fileFormatVersion: 2 -guid: e449fe7932420f940adb4c9b75596bd2 -folderAsset: yes -timeCreated: 1504023214 -licenseType: Pro -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: e449fe7932420f940adb4c9b75596bd2 +folderAsset: yes +timeCreated: 1504023214 +licenseType: Pro +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AddressableAnalytics.cs b/Editor/Build/AddressableAnalytics.cs index f1ad7d28..b93c7515 100644 --- a/Editor/Build/AddressableAnalytics.cs +++ b/Editor/Build/AddressableAnalytics.cs @@ -1,504 +1,504 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using UnityEditor.AddressableAssets.Build; -using UnityEditor.AddressableAssets.Build.DataBuilders; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.AddressableAssets.Settings.GroupSchemas; -using UnityEditor.Build.Pipeline.Utilities; -using UnityEngine; -using UnityEngine.Analytics; -using UnityEngine.ResourceManagement.Util; - -namespace UnityEditor.AddressableAssets -{ - internal static class AddressableAnalytics - { - private const string VendorKey = "unity.addressables"; - private static HashSet _registeredEvents = new HashSet(); - - private const string UsageEvent = "addressablesUsageEvent"; - private const string BuildEvent = "addressablesBuildEvent"; - - [Serializable] - internal struct BuildData - { - public bool IsUsingCCD; - public bool IsContentUpdateBuild; - public bool DebugBuildLayoutEnabled; - public bool AutoOpenBuildReportEnabled; - public bool BuildAndRelease; - public bool IsPlayModeBuild; - public int BuildScript; - public int NumberOfAddressableAssets; - public int NumberOfLabels; - public int NumberOfAssetBundles; - public int NumberOfGroups; - public int NumberOfGroupsUsingLZ4; - public int NumberOfGroupsUsingLZMA; - public int NumberOfGroupsUncompressed; - public int NumberOfGroupsPackedTogether; - public int NumberOfGroupsPackedTogetherByLabel; - public int NumberOfGroupsPackedSeparately; - public int MaxNumberOfAddressableAssetsInAGroup; - public int MinNumberOfAddressableAssetsInAGroup; - public int BuildTarget; - - public int NumberOfGroupsUsingEditorHosted; - public int NumberOfGroupsUsingBuiltIn; - public int NumberOfGroupsUsingCCD; - public int NumberOfGroupsUsingRemoteCustomPaths; - public int NumberOfGroupsUsingLocalCustomPaths; - - public int NumberOfAssetsInEditorHostedPaths; - public int NumberOfAssetsInBuiltInPaths; - public int NumberOfAssetsInCCDPaths; - public int NumberOfAssetsInRemoteCustomPaths; - public int NumberOfAssetsInLocalCustomPaths; - - public int IsIncrementalBuild; - public int ErrorCode; - public double TotalBuildTime; - } - - private static string GetSessionStateKeyByUsageEventType(UsageEventType uet) - { - switch (uet) - { - case UsageEventType.OpenAnalyzeWindow: - return "Addressables/Analyze"; - case UsageEventType.OpenGroupsWindow: - return "Addressables/Groups"; - case UsageEventType.OpenHostingWindow: - return "Addressables/Hosting"; - case UsageEventType.OpenProfilesWindow: - return "Addressables/Profiles"; - case UsageEventType.OpenEventViewerWindow: - return "Addressables/EventViewer"; - default: - return null; - } - } - - internal struct UsageData - { - public int UsageEventType; - public bool IsUsingCCD; - public int AutoRunRestrictionsOption; - } - - internal enum UsageEventType - { - OpenGroupsWindow = 0, - OpenProfilesWindow = 1, - OpenEventViewerWindow = 2, - OpenAnalyzeWindow = 3, - OpenHostingWindow = 4, - RunBundleLayoutPreviewRule = 5, - RunCheckBundleDupeDependenciesRule = 6, - RunCheckResourcesDupeDependenciesRule = 7, - RunCheckSceneDupeDependenciesRule = 8, - InstallCCDManagementPackage = 9, - ContentUpdateCancelled = 10, - ContentUpdateHasChangesInUpdateRestrictionWindow = 11, - ContentUpdateContinuesWithoutChanges = 12, - RunContentUpdateBuild = 13, - CannotLocateBinFile = 14, - BuildFailedDueToModifiedStaticEntries = 15, - BuildInterruptedDueToStaticModifiedEntriesInUpdate = 16, - OpenBuildReportManually = 17, - BuildReportSelectedExploreTab = 18, - BuildReportSelectedPotentialIssuesTab = 19, - BuildReportSelectedSummaryTab = 20, - BuildReportViewByAssetBundle = 21, - BuildReportViewByAssets = 22, - BuildReportViewByLabels = 23, - BuildReportViewByGroup = 24, - BuildReportViewByDuplicatedAssets = 25, - BuildReportImportedManually = 26, - BuildReportOpenRefsTo = 27, - BuildReportOpenRefsBy = 28, - BuildReportDrillDownRefsTo = 29, - BuildReportDrillDownRefsBy = 30, - BuildReportDetailsSelectInGroup = 31, - BuildReportDetailsSelectInEditor = 32, - BuildReportDetailsSelectInBundle = 33, - BuildReportDetailsClose = 34, - BuildReportDetailsOpen = 35, - ProfileModuleViewCreated = 36 - } - - internal enum BuildScriptType - { - PackedMode = 0, - PackedPlayMode = 1, - FastMode = 2, - VirtualMode = 3, - CustomBuildScript = 4 - } - - internal enum PathType - { - BuiltIn = 0, - EditorHosted = 1, - CCD = 2, - Custom = 3, - Automatic = 4 - } - - internal enum BuildType - { - Inconclusive = -1, - CleanBuild = 0, - IncrementalBuild = 1 - } - - internal enum ErrorType - { - NoError = 0, - GenericError = 1 - } - - internal enum AnalyticsContentUpdateRestriction - { - NotApplicable = -1, - ListUpdatedAssetsWithRestrictions = 0, - FailBuild = 1, - Disabled = 2 - } - - private static bool EventIsRegistered(string eventName) - { - return _registeredEvents.Contains(eventName); - } - - //Check if the build cache exists so we know if a build is incremental or clean. May return inconclusive if reflection fails - internal static BuildType DetermineBuildType() - { - try - { - FieldInfo cachePathField = typeof(BuildCache).GetField("k_CachePath", BindingFlags.Static | BindingFlags.NonPublic); - if (cachePathField == null) - return BuildType.Inconclusive; - string cachePath = (string)cachePathField.GetValue(null); - if (cachePath != null && Directory.Exists(cachePath)) - return BuildType.IncrementalBuild; - if (cachePath != null) - return BuildType.CleanBuild; - return BuildType.Inconclusive; - } - catch - { - return BuildType.Inconclusive; - } - } - - internal static BuildScriptType DetermineBuildScriptType(IDataBuilder buildScript) - { - if (buildScript == null) - return BuildScriptType.CustomBuildScript; - - var type = buildScript.GetType(); - if (type == typeof(BuildScriptPackedMode)) - return BuildScriptType.PackedMode; - if (type == typeof(BuildScriptFastMode)) - return BuildScriptType.FastMode; - if (type == typeof(BuildScriptPackedPlayMode)) - return BuildScriptType.PackedPlayMode; - if (type == typeof(BuildScriptVirtualMode)) - return BuildScriptType.VirtualMode; - return BuildScriptType.CustomBuildScript; - } - - internal static ErrorType ParseError(string error) - { - if (String.IsNullOrEmpty(error)) - return ErrorType.NoError; - return ErrorType.GenericError; - } - - internal static BuildData GenerateBuildData(AddressablesDataBuilderInput builderInput, AddressableAssetBuildResult result, BuildType buildType) - { - AddressableAssetSettings currentSettings = builderInput.AddressableSettings; - bool isContentUpdateBuild = builderInput.IsContentUpdateBuild; - bool isBuildAndRelease = builderInput.IsBuildAndRelease; - - bool usingCCD = false; - - string error = result.Error; - bool isPlayModeBuild = result is AddressablesPlayModeBuildResult; - double totalBuildDurationSeconds = result.Duration; - int numberOfAssetBundles = -1; - - if (result is AddressablesPlayerBuildResult buildRes) - { - numberOfAssetBundles = buildRes.AssetBundleBuildResults.Count; - } - -#if ENABLE_CCD - usingCCD = true; -#endif - - ErrorType errorCode = ParseError(error); - - if (isPlayModeBuild) - { - BuildScriptType playModeBuildScriptType = DetermineBuildScriptType(currentSettings.ActivePlayModeDataBuilder); - BuildData playModeBuildData = new BuildData() - { - IsPlayModeBuild = true, - BuildScript = (int)playModeBuildScriptType - }; - - return playModeBuildData; - } - - BuildScriptType buildScriptType = DetermineBuildScriptType(currentSettings.ActivePlayerDataBuilder); - int numberOfAddressableAssets = 0; - - int numberOfGroupsUncompressed = 0; - int numberOfGroupsUsingLZMA = 0; - int numberOfGroupsUsingLZ4 = 0; - - int numberOfGroupsPackedSeparately = 0; - int numberOfGroupsPackedTogether = 0; - int numberOfGroupsPackedTogetherByLabel = 0; - - int minNumberOfAssetsInAGroup = -1; - int maxNumberOfAssetsInAGroup = -1; - - int numberOfGroupsUsingEditorHosted = 0; - int numberOfGroupsUsingBuiltIn = 0; - int numberOfGroupsUsingCCD = 0; - int numberOfGroupsUsingRemoteCustomPaths = 0; - int numberOfGroupsUsingLocalCustomPaths = 0; - - int numberOfAssetsInEditorHostedPaths = 0; - int numberOfAssetsInBuiltInPaths = 0; - int numberOfAssetsInCCDPaths = 0; - int numberOfAssetsInRemoteCustomPaths = 0; - int numberOfAssetsInLocalCustomPaths = 0; - - - List groupTypes = ProfileGroupType.CreateGroupTypes(currentSettings.profileSettings.GetProfile(currentSettings.activeProfileId), currentSettings); - var dataSourceSettings = ProfileDataSourceSettings.GetSettings(); - Dictionary prefixToTypeMap = new Dictionary(); - - foreach (var groupType in groupTypes) - { - ProfileGroupType groupTypeArchetype = dataSourceSettings.FindGroupType(groupType); - if (groupTypeArchetype == null) - prefixToTypeMap.Add(groupType.GroupTypePrefix, PathType.Custom); - else if (groupTypeArchetype.GroupTypePrefix == "Built-In") - prefixToTypeMap.Add(groupType.GroupTypePrefix, PathType.BuiltIn); - else if (groupTypeArchetype.GroupTypePrefix == "Editor Hosted") - prefixToTypeMap.Add(groupType.GroupTypePrefix, PathType.EditorHosted); - else if (groupTypeArchetype.GroupTypePrefix.StartsWith("CCD", StringComparison.Ordinal)) - prefixToTypeMap.Add(groupType.GroupTypePrefix, PathType.CCD); - else if (groupTypeArchetype.GroupTypePrefix.StartsWith("Automatic", StringComparison.Ordinal)) - prefixToTypeMap.Add(groupType.GroupTypePrefix, PathType.CCD); - } - - HashSet vars = currentSettings.profileSettings.GetAllVariableIds(); - - foreach (var group in currentSettings.groups) - { - if (group == null) - continue; - - numberOfAddressableAssets += group.entries.Count; - - var schema = group.GetSchema(); - if (schema == null) - continue; - - int selected = schema.DetermineSelectedIndex(groupTypes, -1, currentSettings, vars); - - PathType pathType; - if (selected == -1) - pathType = PathType.Custom; - else - pathType = prefixToTypeMap[groupTypes[selected].GroupTypePrefix]; - - if (pathType == PathType.Custom) - { - if (ResourceManagerConfig.IsPathRemote(schema.LoadPath.GetValue(currentSettings))) - { - numberOfGroupsUsingRemoteCustomPaths += 1; - numberOfAssetsInRemoteCustomPaths += group.entries.Count; - } - else - { - numberOfGroupsUsingLocalCustomPaths += 1; - numberOfAssetsInLocalCustomPaths += group.entries.Count; - } - } - - if (pathType == PathType.BuiltIn) - { - numberOfGroupsUsingBuiltIn += 1; - numberOfAssetsInBuiltInPaths += group.entries.Count; - } - - if (pathType == PathType.EditorHosted) - { - numberOfGroupsUsingEditorHosted += 1; - numberOfAssetsInEditorHostedPaths += group.entries.Count; - } - - if (pathType == PathType.CCD) - { - numberOfGroupsUsingCCD += 1; - numberOfAssetsInCCDPaths += group.entries.Count; - } - - if (pathType == PathType.Automatic) - { - numberOfGroupsUsingCCD += 1; - numberOfAssetsInCCDPaths += group.entries.Count; - } - - var bundleMode = schema.BundleMode; - var compressionType = schema.Compression; - - switch (compressionType) - { - case BundledAssetGroupSchema.BundleCompressionMode.Uncompressed: - numberOfGroupsUncompressed += 1; - break; - case BundledAssetGroupSchema.BundleCompressionMode.LZ4: - numberOfGroupsUsingLZ4 += 1; - break; - case BundledAssetGroupSchema.BundleCompressionMode.LZMA: - numberOfGroupsUsingLZMA += 1; - break; - } - - switch (bundleMode) - { - case BundledAssetGroupSchema.BundlePackingMode.PackSeparately: - numberOfGroupsPackedSeparately += 1; - break; - case BundledAssetGroupSchema.BundlePackingMode.PackTogether: - numberOfGroupsPackedTogether += 1; - break; - case BundledAssetGroupSchema.BundlePackingMode.PackTogetherByLabel: - numberOfGroupsPackedTogetherByLabel += 1; - break; - } - - if (group.entries.Count > maxNumberOfAssetsInAGroup) - maxNumberOfAssetsInAGroup = group.entries.Count; - if (minNumberOfAssetsInAGroup == -1 || group.entries.Count < minNumberOfAssetsInAGroup) - minNumberOfAssetsInAGroup = group.entries.Count; - } - - BuildData data = new BuildData() - { - IsUsingCCD = usingCCD, - IsContentUpdateBuild = isContentUpdateBuild, - IsPlayModeBuild = false, - BuildScript = (int)buildScriptType, - BuildAndRelease = isBuildAndRelease, -#if UNITY_2022_2_OR_NEWER - DebugBuildLayoutEnabled = ProjectConfigData.GenerateBuildLayout, - AutoOpenBuildReportEnabled = ProjectConfigData.AutoOpenAddressablesReport && ProjectConfigData.GenerateBuildLayout, -#endif - NumberOfLabels = currentSettings.labelTable.labelNames.Count, - IsIncrementalBuild = (int)buildType, - NumberOfAssetBundles = numberOfAssetBundles, - NumberOfAddressableAssets = numberOfAddressableAssets, - MinNumberOfAddressableAssetsInAGroup = minNumberOfAssetsInAGroup, - MaxNumberOfAddressableAssetsInAGroup = maxNumberOfAssetsInAGroup, - NumberOfGroups = currentSettings.groups.Count, - TotalBuildTime = totalBuildDurationSeconds, - NumberOfGroupsUsingLZ4 = numberOfGroupsUsingLZ4, - NumberOfGroupsUsingLZMA = numberOfGroupsUsingLZMA, - NumberOfGroupsUncompressed = numberOfGroupsUncompressed, - NumberOfGroupsPackedTogether = numberOfGroupsPackedTogether, - NumberOfGroupsPackedTogetherByLabel = numberOfGroupsPackedTogetherByLabel, - NumberOfGroupsPackedSeparately = numberOfGroupsPackedSeparately, - NumberOfGroupsUsingBuiltIn = numberOfGroupsUsingBuiltIn, - NumberOfGroupsUsingEditorHosted = numberOfGroupsUsingEditorHosted, - NumberOfGroupsUsingRemoteCustomPaths = numberOfGroupsUsingRemoteCustomPaths, - NumberOfGroupsUsingLocalCustomPaths = numberOfGroupsUsingLocalCustomPaths, - NumberOfGroupsUsingCCD = numberOfGroupsUsingCCD, - NumberOfAssetsInRemoteCustomPaths = numberOfAssetsInRemoteCustomPaths, - NumberOfAssetsInLocalCustomPaths = numberOfAssetsInLocalCustomPaths, - NumberOfAssetsInBuiltInPaths = numberOfAssetsInBuiltInPaths, - NumberOfAssetsInEditorHostedPaths = numberOfAssetsInEditorHostedPaths, - NumberOfAssetsInCCDPaths = numberOfAssetsInCCDPaths, - BuildTarget = (int)EditorUserBuildSettings.activeBuildTarget, - ErrorCode = (int)errorCode - }; - - return data; - } - - internal static void ReportBuildEvent(AddressablesDataBuilderInput builderInput, AddressableAssetBuildResult result, BuildType buildType) - { - if (!EditorAnalytics.enabled) - return; - - if (!EventIsRegistered(BuildEvent)) - if (!RegisterEvent(BuildEvent)) - return; - - BuildData data = GenerateBuildData(builderInput, result, buildType); - EditorAnalytics.SendEventWithLimit(BuildEvent, data); - } - - internal static UsageData GenerateUsageData(UsageEventType eventType, AnalyticsContentUpdateRestriction restriction = AnalyticsContentUpdateRestriction.NotApplicable) - { - bool usingCCD = false; - -#if ENABLE_CCD - usingCCD = true; -#endif - - var data = new UsageData() - { - UsageEventType = (int)eventType, - IsUsingCCD = usingCCD, - AutoRunRestrictionsOption = (int)restriction - }; - - return data; - } - - internal static void ReportUsageEvent(UsageEventType eventType, bool limitEventOncePerSession = false, int contentUpdateRestriction = -1) - { - if (!EditorAnalytics.enabled) - return; - - var sessionStateKey = GetSessionStateKeyByUsageEventType(eventType); - - if (limitEventOncePerSession && sessionStateKey != null && SessionState.GetBool(sessionStateKey, false)) - return; - - if (!SessionState.GetBool(sessionStateKey, false)) - SessionState.SetBool(sessionStateKey, true); - - if (!EventIsRegistered(UsageEvent)) - if (!RegisterEvent(UsageEvent)) - return; - - UsageData data = GenerateUsageData(eventType, (AnalyticsContentUpdateRestriction) contentUpdateRestriction); - EditorAnalytics.SendEventWithLimit(UsageEvent, data); - } - - private static bool RegisterEvent(string eventName) - { - bool eventSuccessfullyRegistered = false; - AnalyticsResult registerEvent = EditorAnalytics.RegisterEventWithLimit(eventName, 100, 100, VendorKey); - if (registerEvent == AnalyticsResult.Ok) - { - _registeredEvents.Add(eventName); - eventSuccessfullyRegistered = true; - } - - return eventSuccessfullyRegistered; - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using UnityEditor.AddressableAssets.Build; +using UnityEditor.AddressableAssets.Build.DataBuilders; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEditor.Build.Pipeline.Utilities; +using UnityEngine; +using UnityEngine.Analytics; +using UnityEngine.ResourceManagement.Util; + +namespace UnityEditor.AddressableAssets +{ + internal static class AddressableAnalytics + { + private const string VendorKey = "unity.addressables"; + private static HashSet _registeredEvents = new HashSet(); + + private const string UsageEvent = "addressablesUsageEvent"; + private const string BuildEvent = "addressablesBuildEvent"; + + [Serializable] + internal struct BuildData + { + public bool IsUsingCCD; + public bool IsContentUpdateBuild; + public bool DebugBuildLayoutEnabled; + public bool AutoOpenBuildReportEnabled; + public bool BuildAndRelease; + public bool IsPlayModeBuild; + public int BuildScript; + public int NumberOfAddressableAssets; + public int NumberOfLabels; + public int NumberOfAssetBundles; + public int NumberOfGroups; + public int NumberOfGroupsUsingLZ4; + public int NumberOfGroupsUsingLZMA; + public int NumberOfGroupsUncompressed; + public int NumberOfGroupsPackedTogether; + public int NumberOfGroupsPackedTogetherByLabel; + public int NumberOfGroupsPackedSeparately; + public int MaxNumberOfAddressableAssetsInAGroup; + public int MinNumberOfAddressableAssetsInAGroup; + public int BuildTarget; + + public int NumberOfGroupsUsingEditorHosted; + public int NumberOfGroupsUsingBuiltIn; + public int NumberOfGroupsUsingCCD; + public int NumberOfGroupsUsingRemoteCustomPaths; + public int NumberOfGroupsUsingLocalCustomPaths; + + public int NumberOfAssetsInEditorHostedPaths; + public int NumberOfAssetsInBuiltInPaths; + public int NumberOfAssetsInCCDPaths; + public int NumberOfAssetsInRemoteCustomPaths; + public int NumberOfAssetsInLocalCustomPaths; + + public int IsIncrementalBuild; + public int ErrorCode; + public double TotalBuildTime; + } + + private static string GetSessionStateKeyByUsageEventType(UsageEventType uet) + { + switch (uet) + { + case UsageEventType.OpenAnalyzeWindow: + return "Addressables/Analyze"; + case UsageEventType.OpenGroupsWindow: + return "Addressables/Groups"; + case UsageEventType.OpenHostingWindow: + return "Addressables/Hosting"; + case UsageEventType.OpenProfilesWindow: + return "Addressables/Profiles"; + case UsageEventType.OpenEventViewerWindow: + return "Addressables/EventViewer"; + default: + return null; + } + } + + internal struct UsageData + { + public int UsageEventType; + public bool IsUsingCCD; + public int AutoRunRestrictionsOption; + } + + internal enum UsageEventType + { + OpenGroupsWindow = 0, + OpenProfilesWindow = 1, + OpenEventViewerWindow = 2, + OpenAnalyzeWindow = 3, + OpenHostingWindow = 4, + RunBundleLayoutPreviewRule = 5, + RunCheckBundleDupeDependenciesRule = 6, + RunCheckResourcesDupeDependenciesRule = 7, + RunCheckSceneDupeDependenciesRule = 8, + InstallCCDManagementPackage = 9, + ContentUpdateCancelled = 10, + ContentUpdateHasChangesInUpdateRestrictionWindow = 11, + ContentUpdateContinuesWithoutChanges = 12, + RunContentUpdateBuild = 13, + CannotLocateBinFile = 14, + BuildFailedDueToModifiedStaticEntries = 15, + BuildInterruptedDueToStaticModifiedEntriesInUpdate = 16, + OpenBuildReportManually = 17, + BuildReportSelectedExploreTab = 18, + BuildReportSelectedPotentialIssuesTab = 19, + BuildReportSelectedSummaryTab = 20, + BuildReportViewByAssetBundle = 21, + BuildReportViewByAssets = 22, + BuildReportViewByLabels = 23, + BuildReportViewByGroup = 24, + BuildReportViewByDuplicatedAssets = 25, + BuildReportImportedManually = 26, + BuildReportOpenRefsTo = 27, + BuildReportOpenRefsBy = 28, + BuildReportDrillDownRefsTo = 29, + BuildReportDrillDownRefsBy = 30, + BuildReportDetailsSelectInGroup = 31, + BuildReportDetailsSelectInEditor = 32, + BuildReportDetailsSelectInBundle = 33, + BuildReportDetailsClose = 34, + BuildReportDetailsOpen = 35, + ProfileModuleViewCreated = 36 + } + + internal enum BuildScriptType + { + PackedMode = 0, + PackedPlayMode = 1, + FastMode = 2, + VirtualMode = 3, + CustomBuildScript = 4 + } + + internal enum PathType + { + BuiltIn = 0, + EditorHosted = 1, + CCD = 2, + Custom = 3, + Automatic = 4 + } + + internal enum BuildType + { + Inconclusive = -1, + CleanBuild = 0, + IncrementalBuild = 1 + } + + internal enum ErrorType + { + NoError = 0, + GenericError = 1 + } + + internal enum AnalyticsContentUpdateRestriction + { + NotApplicable = -1, + ListUpdatedAssetsWithRestrictions = 0, + FailBuild = 1, + Disabled = 2 + } + + private static bool EventIsRegistered(string eventName) + { + return _registeredEvents.Contains(eventName); + } + + //Check if the build cache exists so we know if a build is incremental or clean. May return inconclusive if reflection fails + internal static BuildType DetermineBuildType() + { + try + { + FieldInfo cachePathField = typeof(BuildCache).GetField("k_CachePath", BindingFlags.Static | BindingFlags.NonPublic); + if (cachePathField == null) + return BuildType.Inconclusive; + string cachePath = (string)cachePathField.GetValue(null); + if (cachePath != null && Directory.Exists(cachePath)) + return BuildType.IncrementalBuild; + if (cachePath != null) + return BuildType.CleanBuild; + return BuildType.Inconclusive; + } + catch + { + return BuildType.Inconclusive; + } + } + + internal static BuildScriptType DetermineBuildScriptType(IDataBuilder buildScript) + { + if (buildScript == null) + return BuildScriptType.CustomBuildScript; + + var type = buildScript.GetType(); + if (type == typeof(BuildScriptPackedMode)) + return BuildScriptType.PackedMode; + if (type == typeof(BuildScriptFastMode)) + return BuildScriptType.FastMode; + if (type == typeof(BuildScriptPackedPlayMode)) + return BuildScriptType.PackedPlayMode; + if (type == typeof(BuildScriptVirtualMode)) + return BuildScriptType.VirtualMode; + return BuildScriptType.CustomBuildScript; + } + + internal static ErrorType ParseError(string error) + { + if (String.IsNullOrEmpty(error)) + return ErrorType.NoError; + return ErrorType.GenericError; + } + + internal static BuildData GenerateBuildData(AddressablesDataBuilderInput builderInput, AddressableAssetBuildResult result, BuildType buildType) + { + AddressableAssetSettings currentSettings = builderInput.AddressableSettings; + bool isContentUpdateBuild = builderInput.IsContentUpdateBuild; + bool isBuildAndRelease = builderInput.IsBuildAndRelease; + + bool usingCCD = false; + + string error = result.Error; + bool isPlayModeBuild = result is AddressablesPlayModeBuildResult; + double totalBuildDurationSeconds = result.Duration; + int numberOfAssetBundles = -1; + + if (result is AddressablesPlayerBuildResult buildRes) + { + numberOfAssetBundles = buildRes.AssetBundleBuildResults.Count; + } + +#if ENABLE_CCD + usingCCD = true; +#endif + + ErrorType errorCode = ParseError(error); + + if (isPlayModeBuild) + { + BuildScriptType playModeBuildScriptType = DetermineBuildScriptType(currentSettings.ActivePlayModeDataBuilder); + BuildData playModeBuildData = new BuildData() + { + IsPlayModeBuild = true, + BuildScript = (int)playModeBuildScriptType + }; + + return playModeBuildData; + } + + BuildScriptType buildScriptType = DetermineBuildScriptType(currentSettings.ActivePlayerDataBuilder); + int numberOfAddressableAssets = 0; + + int numberOfGroupsUncompressed = 0; + int numberOfGroupsUsingLZMA = 0; + int numberOfGroupsUsingLZ4 = 0; + + int numberOfGroupsPackedSeparately = 0; + int numberOfGroupsPackedTogether = 0; + int numberOfGroupsPackedTogetherByLabel = 0; + + int minNumberOfAssetsInAGroup = -1; + int maxNumberOfAssetsInAGroup = -1; + + int numberOfGroupsUsingEditorHosted = 0; + int numberOfGroupsUsingBuiltIn = 0; + int numberOfGroupsUsingCCD = 0; + int numberOfGroupsUsingRemoteCustomPaths = 0; + int numberOfGroupsUsingLocalCustomPaths = 0; + + int numberOfAssetsInEditorHostedPaths = 0; + int numberOfAssetsInBuiltInPaths = 0; + int numberOfAssetsInCCDPaths = 0; + int numberOfAssetsInRemoteCustomPaths = 0; + int numberOfAssetsInLocalCustomPaths = 0; + + + List groupTypes = ProfileGroupType.CreateGroupTypes(currentSettings.profileSettings.GetProfile(currentSettings.activeProfileId), currentSettings); + var dataSourceSettings = ProfileDataSourceSettings.GetSettings(); + Dictionary prefixToTypeMap = new Dictionary(); + + foreach (var groupType in groupTypes) + { + ProfileGroupType groupTypeArchetype = dataSourceSettings.FindGroupType(groupType); + if (groupTypeArchetype == null) + prefixToTypeMap.Add(groupType.GroupTypePrefix, PathType.Custom); + else if (groupTypeArchetype.GroupTypePrefix == "Built-In") + prefixToTypeMap.Add(groupType.GroupTypePrefix, PathType.BuiltIn); + else if (groupTypeArchetype.GroupTypePrefix == "Editor Hosted") + prefixToTypeMap.Add(groupType.GroupTypePrefix, PathType.EditorHosted); + else if (groupTypeArchetype.GroupTypePrefix.StartsWith("CCD", StringComparison.Ordinal)) + prefixToTypeMap.Add(groupType.GroupTypePrefix, PathType.CCD); + else if (groupTypeArchetype.GroupTypePrefix.StartsWith("Automatic", StringComparison.Ordinal)) + prefixToTypeMap.Add(groupType.GroupTypePrefix, PathType.CCD); + } + + HashSet vars = currentSettings.profileSettings.GetAllVariableIds(); + + foreach (var group in currentSettings.groups) + { + if (group == null) + continue; + + numberOfAddressableAssets += group.entries.Count; + + var schema = group.GetSchema(); + if (schema == null) + continue; + + int selected = schema.DetermineSelectedIndex(groupTypes, -1, currentSettings, vars); + + PathType pathType; + if (selected == -1) + pathType = PathType.Custom; + else + pathType = prefixToTypeMap[groupTypes[selected].GroupTypePrefix]; + + if (pathType == PathType.Custom) + { + if (ResourceManagerConfig.IsPathRemote(schema.LoadPath.GetValue(currentSettings))) + { + numberOfGroupsUsingRemoteCustomPaths += 1; + numberOfAssetsInRemoteCustomPaths += group.entries.Count; + } + else + { + numberOfGroupsUsingLocalCustomPaths += 1; + numberOfAssetsInLocalCustomPaths += group.entries.Count; + } + } + + if (pathType == PathType.BuiltIn) + { + numberOfGroupsUsingBuiltIn += 1; + numberOfAssetsInBuiltInPaths += group.entries.Count; + } + + if (pathType == PathType.EditorHosted) + { + numberOfGroupsUsingEditorHosted += 1; + numberOfAssetsInEditorHostedPaths += group.entries.Count; + } + + if (pathType == PathType.CCD) + { + numberOfGroupsUsingCCD += 1; + numberOfAssetsInCCDPaths += group.entries.Count; + } + + if (pathType == PathType.Automatic) + { + numberOfGroupsUsingCCD += 1; + numberOfAssetsInCCDPaths += group.entries.Count; + } + + var bundleMode = schema.BundleMode; + var compressionType = schema.Compression; + + switch (compressionType) + { + case BundledAssetGroupSchema.BundleCompressionMode.Uncompressed: + numberOfGroupsUncompressed += 1; + break; + case BundledAssetGroupSchema.BundleCompressionMode.LZ4: + numberOfGroupsUsingLZ4 += 1; + break; + case BundledAssetGroupSchema.BundleCompressionMode.LZMA: + numberOfGroupsUsingLZMA += 1; + break; + } + + switch (bundleMode) + { + case BundledAssetGroupSchema.BundlePackingMode.PackSeparately: + numberOfGroupsPackedSeparately += 1; + break; + case BundledAssetGroupSchema.BundlePackingMode.PackTogether: + numberOfGroupsPackedTogether += 1; + break; + case BundledAssetGroupSchema.BundlePackingMode.PackTogetherByLabel: + numberOfGroupsPackedTogetherByLabel += 1; + break; + } + + if (group.entries.Count > maxNumberOfAssetsInAGroup) + maxNumberOfAssetsInAGroup = group.entries.Count; + if (minNumberOfAssetsInAGroup == -1 || group.entries.Count < minNumberOfAssetsInAGroup) + minNumberOfAssetsInAGroup = group.entries.Count; + } + + BuildData data = new BuildData() + { + IsUsingCCD = usingCCD, + IsContentUpdateBuild = isContentUpdateBuild, + IsPlayModeBuild = false, + BuildScript = (int)buildScriptType, + BuildAndRelease = isBuildAndRelease, +#if UNITY_2022_2_OR_NEWER + DebugBuildLayoutEnabled = ProjectConfigData.GenerateBuildLayout, + AutoOpenBuildReportEnabled = ProjectConfigData.AutoOpenAddressablesReport && ProjectConfigData.GenerateBuildLayout, +#endif + NumberOfLabels = currentSettings.labelTable.labelNames.Count, + IsIncrementalBuild = (int)buildType, + NumberOfAssetBundles = numberOfAssetBundles, + NumberOfAddressableAssets = numberOfAddressableAssets, + MinNumberOfAddressableAssetsInAGroup = minNumberOfAssetsInAGroup, + MaxNumberOfAddressableAssetsInAGroup = maxNumberOfAssetsInAGroup, + NumberOfGroups = currentSettings.groups.Count, + TotalBuildTime = totalBuildDurationSeconds, + NumberOfGroupsUsingLZ4 = numberOfGroupsUsingLZ4, + NumberOfGroupsUsingLZMA = numberOfGroupsUsingLZMA, + NumberOfGroupsUncompressed = numberOfGroupsUncompressed, + NumberOfGroupsPackedTogether = numberOfGroupsPackedTogether, + NumberOfGroupsPackedTogetherByLabel = numberOfGroupsPackedTogetherByLabel, + NumberOfGroupsPackedSeparately = numberOfGroupsPackedSeparately, + NumberOfGroupsUsingBuiltIn = numberOfGroupsUsingBuiltIn, + NumberOfGroupsUsingEditorHosted = numberOfGroupsUsingEditorHosted, + NumberOfGroupsUsingRemoteCustomPaths = numberOfGroupsUsingRemoteCustomPaths, + NumberOfGroupsUsingLocalCustomPaths = numberOfGroupsUsingLocalCustomPaths, + NumberOfGroupsUsingCCD = numberOfGroupsUsingCCD, + NumberOfAssetsInRemoteCustomPaths = numberOfAssetsInRemoteCustomPaths, + NumberOfAssetsInLocalCustomPaths = numberOfAssetsInLocalCustomPaths, + NumberOfAssetsInBuiltInPaths = numberOfAssetsInBuiltInPaths, + NumberOfAssetsInEditorHostedPaths = numberOfAssetsInEditorHostedPaths, + NumberOfAssetsInCCDPaths = numberOfAssetsInCCDPaths, + BuildTarget = (int)EditorUserBuildSettings.activeBuildTarget, + ErrorCode = (int)errorCode + }; + + return data; + } + + internal static void ReportBuildEvent(AddressablesDataBuilderInput builderInput, AddressableAssetBuildResult result, BuildType buildType) + { + if (!EditorAnalytics.enabled) + return; + + if (!EventIsRegistered(BuildEvent)) + if (!RegisterEvent(BuildEvent)) + return; + + BuildData data = GenerateBuildData(builderInput, result, buildType); + EditorAnalytics.SendEventWithLimit(BuildEvent, data); + } + + internal static UsageData GenerateUsageData(UsageEventType eventType, AnalyticsContentUpdateRestriction restriction = AnalyticsContentUpdateRestriction.NotApplicable) + { + bool usingCCD = false; + +#if ENABLE_CCD + usingCCD = true; +#endif + + var data = new UsageData() + { + UsageEventType = (int)eventType, + IsUsingCCD = usingCCD, + AutoRunRestrictionsOption = (int)restriction + }; + + return data; + } + + internal static void ReportUsageEvent(UsageEventType eventType, bool limitEventOncePerSession = false, int contentUpdateRestriction = -1) + { + if (!EditorAnalytics.enabled) + return; + + var sessionStateKey = GetSessionStateKeyByUsageEventType(eventType); + + if (limitEventOncePerSession && sessionStateKey != null && SessionState.GetBool(sessionStateKey, false)) + return; + + if (!SessionState.GetBool(sessionStateKey, false)) + SessionState.SetBool(sessionStateKey, true); + + if (!EventIsRegistered(UsageEvent)) + if (!RegisterEvent(UsageEvent)) + return; + + UsageData data = GenerateUsageData(eventType, (AnalyticsContentUpdateRestriction) contentUpdateRestriction); + EditorAnalytics.SendEventWithLimit(UsageEvent, data); + } + + private static bool RegisterEvent(string eventName) + { + bool eventSuccessfullyRegistered = false; + AnalyticsResult registerEvent = EditorAnalytics.RegisterEventWithLimit(eventName, 100, 100, VendorKey); + if (registerEvent == AnalyticsResult.Ok) + { + _registeredEvents.Add(eventName); + eventSuccessfullyRegistered = true; + } + + return eventSuccessfullyRegistered; + } + } +} diff --git a/Editor/Build/AddressableAnalytics.cs.meta b/Editor/Build/AddressableAnalytics.cs.meta index 1486ffd0..15318af7 100644 --- a/Editor/Build/AddressableAnalytics.cs.meta +++ b/Editor/Build/AddressableAnalytics.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 3a6ea556a4c75be4a88f236f22eec817 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 3a6ea556a4c75be4a88f236f22eec817 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AddressableAssetSettingsLocator.cs b/Editor/Build/AddressableAssetSettingsLocator.cs index da928ecb..76cf40f9 100644 --- a/Editor/Build/AddressableAssetSettingsLocator.cs +++ b/Editor/Build/AddressableAssetSettingsLocator.cs @@ -1,414 +1,414 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEditor.Build.Content; -using UnityEngine; -using UnityEngine.AddressableAssets.ResourceLocators; -using UnityEngine.ResourceManagement.ResourceLocations; -using UnityEngine.ResourceManagement.ResourceProviders; -using UnityEngine.U2D; -using static UnityEditor.AddressableAssets.Settings.AddressablesFileEnumeration; - -namespace UnityEditor.AddressableAssets.Settings -{ - internal class AddressableAssetSettingsLocator : IResourceLocator - { - private static Type m_SpriteType = typeof(Sprite); - private static Type m_SpriteAtlasType = typeof(SpriteAtlas); - - public string LocatorId { get; private set; } - public Dictionary> m_keyToEntries; - public Dictionary> m_Cache; - public AddressableAssetTree m_AddressableAssetTree; - HashSet m_Keys = null; - AddressableAssetSettings m_Settings; - bool m_includeResourcesFolders = false; - bool m_dirty = true; - - public IEnumerable Keys - { - get - { - if (m_dirty) - RebuildInternalData(); - if (m_Keys == null) - { - var visitedFolders = new HashSet(); - using (new AddressablesFileEnumerationScope(m_AddressableAssetTree)) - { - m_Keys = new HashSet(); - foreach (var kvp in m_keyToEntries) - { - var hasNonFolder = false; - foreach (var e in kvp.Value) - { - if (AssetDatabase.IsValidFolder(e.AssetPath)) - { - if (!visitedFolders.Contains(e.AssetPath)) - { - foreach (var f in EnumerateAddressableFolder(e.AssetPath, m_Settings, true)) - { - m_Keys.Add(f.Replace(e.AssetPath, e.address)); - m_Keys.Add(AssetDatabase.AssetPathToGUID(f)); - } - - visitedFolders.Add(e.AssetPath); - } - - foreach (var l in e.labels) - m_Keys.Add(l); - } - else - { - hasNonFolder = true; - } - } - - if (hasNonFolder) - m_Keys.Add(kvp.Key); - } - - if (m_includeResourcesFolders) - { - var resourcesEntry = m_Settings.FindAssetEntry(AddressableAssetEntry.ResourcesName); - resourcesEntry.GatherResourcesEntries(null, true, entry => - { - m_Keys.Add(entry.address); - m_Keys.Add(entry.guid); - return false; - }); - } - } - } - - return m_Keys; - } - } - - /// - /// Returns an empty array of locations. - /// - public IEnumerable AllLocations => new IResourceLocation[0]; - - public struct CacheKey : IEquatable - { - public object m_key; - public Type m_type; - - public bool Equals(CacheKey other) - { - if (!m_key.Equals(other.m_key)) - return false; - return m_type == other.m_type; - } - - public override int GetHashCode() => m_key.GetHashCode() * 31 + (m_type == null ? 0 : m_type.GetHashCode()); - } - - public AddressableAssetSettingsLocator(AddressableAssetSettings settings) - { - m_Settings = settings; - LocatorId = m_Settings.name; - m_dirty = true; - m_Settings.OnModification += Settings_OnModification; - } - - void RebuildInternalData() - { - m_Keys = null; - m_AddressableAssetTree = BuildAddressableTree(m_Settings); - m_Cache = new Dictionary>(); - m_keyToEntries = new Dictionary>(m_Settings.labelTable.labelNames.Count); - using (new AddressablesFileEnumerationScope(m_AddressableAssetTree)) - { - foreach (AddressableAssetGroup g in m_Settings.groups) - { - if (g == null) - continue; - - foreach (AddressableAssetEntry e in g.entries) - { - if (e.guid == AddressableAssetEntry.EditorSceneListName) - { - if (e.parentGroup.GetSchema().IncludeBuildSettingsScenes) - { - e.GatherAllAssets(null, false, false, false, s => - { - AddEntriesToTables(m_keyToEntries, s); - return false; - }); - } - } - else if (e.guid == AddressableAssetEntry.ResourcesName) - { - m_includeResourcesFolders = e.parentGroup.GetSchema().IncludeResourcesFolders; - } - else - { - AddEntriesToTables(m_keyToEntries, e); - } - } - } - } - - m_dirty = false; - } - - private void Settings_OnModification(AddressableAssetSettings settings, AddressableAssetSettings.ModificationEvent evt, object arg3) - { - switch (evt) - { - case AddressableAssetSettings.ModificationEvent.EntryAdded: - case AddressableAssetSettings.ModificationEvent.EntryCreated: - case AddressableAssetSettings.ModificationEvent.EntryModified: - case AddressableAssetSettings.ModificationEvent.EntryMoved: - case AddressableAssetSettings.ModificationEvent.EntryRemoved: - case AddressableAssetSettings.ModificationEvent.GroupRemoved: - case AddressableAssetSettings.ModificationEvent.LabelAdded: - case AddressableAssetSettings.ModificationEvent.LabelRemoved: - case AddressableAssetSettings.ModificationEvent.BatchModification: - m_dirty = true; - break; - } - } - - static void AddEntry(AddressableAssetEntry e, object k, Dictionary> keyToEntries) - { - if (!keyToEntries.TryGetValue(k, out HashSet entries)) - keyToEntries.Add(k, entries = new HashSet()); - entries.Add(e); - } - - static void AddEntriesToTables(Dictionary> keyToEntries, AddressableAssetEntry e) - { - AddEntry(e, e.address, keyToEntries); - AddEntry(e, e.guid, keyToEntries); - if (e.IsScene && e.IsInSceneList) - { - int index = BuiltinSceneCache.GetSceneIndex(new GUID(e.guid)); - if (index != -1) - AddEntry(e, index, keyToEntries); - } - - if (e.labels != null) - { - foreach (string l in e.labels) - { - AddEntry(e, l, keyToEntries); - } - } - } - - static void GatherEntryLocations(AddressableAssetEntry entry, Type type, IList locations, AddressableAssetTree assetTree) - { - if (!string.IsNullOrEmpty(entry.address) && entry.address.Contains('[') && entry.address.Contains(']')) - { - Debug.LogErrorFormat("Address '{0}' cannot contain '[ ]'.", entry.address); - return; - } - - using (new AddressablesFileEnumerationScope(assetTree)) - { - entry.GatherAllAssets(null, true, true, false, e => - { - if (e.IsScene) - { - if (type == null || type == typeof(object) || type == typeof(SceneInstance) || AddressableAssetUtility.MapEditorTypeToRuntimeType(e.MainAssetType, false) == type) - locations.Add(new ResourceLocationBase(e.address, e.AssetPath, typeof(SceneProvider).FullName, typeof(SceneInstance))); - } - else if (type == null || (type.IsAssignableFrom(e.MainAssetType) && type != typeof(object))) - { - locations.Add(new ResourceLocationBase(e.address, e.AssetPath, typeof(AssetDatabaseProvider).FullName, e.MainAssetType)); - return true; - } - else - { - ObjectIdentifier[] ids = ContentBuildInterface.GetPlayerObjectIdentifiersInAsset(new GUID(e.guid), EditorUserBuildSettings.activeBuildTarget); - if (ids.Length > 0) - { - foreach (var t in AddressableAssetEntry.GatherMainAndReferencedSerializedTypes(ids)) - { - if (type.IsAssignableFrom(t)) - locations.Add( - new ResourceLocationBase(e.address, e.AssetPath, typeof(AssetDatabaseProvider).FullName, AddressableAssetUtility.MapEditorTypeToRuntimeType(t, false))); - } - - return true; - } - } - - return false; - }); - } - } - - public bool Locate(object key, Type type, out IList locations) - { - if (m_dirty) - RebuildInternalData(); - CacheKey cacheKey = new CacheKey() {m_key = key, m_type = type}; - if (m_Cache.TryGetValue(cacheKey, out locations)) - return locations != null; - - locations = new List(); - if (m_keyToEntries.TryGetValue(key, out HashSet entries)) - { - foreach (AddressableAssetEntry e in entries) - { - if (AssetDatabase.IsValidFolder(e.AssetPath) && !e.labels.Contains(key as string)) - continue; - - if (type == null) - { - if (e.MainAssetType != typeof(SceneAsset)) - { - ObjectIdentifier[] ids = - ContentBuildInterface.GetPlayerObjectIdentifiersInAsset(new GUID(e.guid), - EditorUserBuildSettings.activeBuildTarget); - List mainObjectTypes = AddressableAssetEntry.GatherMainObjectTypes(ids); - - if (mainObjectTypes.Count > 0) - { - foreach (Type t in mainObjectTypes) - GatherEntryLocations(e, t, locations, m_AddressableAssetTree); - } - else - { - GatherEntryLocations(e, null, locations, m_AddressableAssetTree); - } - } - else - { - GatherEntryLocations(e, null, locations, m_AddressableAssetTree); - } - } - else - { - GatherEntryLocations(e, type, locations, m_AddressableAssetTree); - } - } - } - - if (type == null) - type = typeof(object); - - string keyStr = key as string; - if (!string.IsNullOrEmpty(keyStr)) - { - //check if the key is a guid first - var keyPath = AssetDatabase.GUIDToAssetPath(keyStr); - if (!string.IsNullOrEmpty(keyPath)) - { - //only look for folders from GUID if no locations have been found - if (locations.Count == 0) - { - var slash = keyPath.LastIndexOf('/'); - while (slash > 0) - { - keyPath = keyPath.Substring(0, slash); - var parentFolderKey = AssetDatabase.AssetPathToGUID(keyPath); - if (string.IsNullOrEmpty(parentFolderKey)) - break; - - if (m_keyToEntries.ContainsKey(parentFolderKey)) - { - AddLocations(locations, type, keyPath, AssetDatabase.GUIDToAssetPath(keyStr)); - break; - } - - slash = keyPath.LastIndexOf('/'); - } - } - } - else - { - //if the key is not a GUID, see if it is contained in a folder entry - keyPath = keyStr; - int slash = keyPath.LastIndexOf('/'); - while (slash > 0) - { - keyPath = keyPath.Substring(0, slash); - if (m_keyToEntries.TryGetValue(keyPath, out var entry)) - { - foreach (var e in entry) - AddLocations(locations, type, keyStr, GetInternalIdFromFolderEntry(keyStr, e)); - break; - } - - slash = keyPath.LastIndexOf('/'); - } - } - - //check resources folders - if (m_includeResourcesFolders) - { - string resPath = keyStr; - var ext = System.IO.Path.GetExtension(resPath); - if (!string.IsNullOrEmpty(ext)) - resPath = resPath.Substring(0, resPath.Length - ext.Length); - UnityEngine.Object obj = Resources.Load(resPath, type); - if (obj == null && keyStr.Length == 32) - { - resPath = AssetDatabase.GUIDToAssetPath(keyStr); - if (!string.IsNullOrEmpty(resPath)) - { - int index = resPath.IndexOf("Resources/", StringComparison.OrdinalIgnoreCase); - if (index >= 0) - { - int start = index + 10; - int length = resPath.Length - (start + System.IO.Path.GetExtension(resPath).Length); - resPath = resPath.Substring(index + 10, length); - obj = Resources.Load(resPath, type); - } - } - } - - if (obj != null) - locations.Add(new ResourceLocationBase(keyStr, resPath, typeof(LegacyResourcesProvider).FullName, type)); - } - } - - if (locations.Count == 0) - { - locations = null; - m_Cache.Add(cacheKey, locations); - return false; - } - - m_Cache.Add(cacheKey, locations); - return true; - } - - internal static void AddLocations(IList locations, Type type, string keyStr, string internalId) - { - if (!string.IsNullOrEmpty(internalId) && !string.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(internalId))) - { - if (type == m_SpriteType && AssetDatabase.GetMainAssetTypeAtPath(internalId) == m_SpriteAtlasType) - locations.Add(new ResourceLocationBase(keyStr, internalId, typeof(AssetDatabaseProvider).FullName, m_SpriteAtlasType)); - else - { - foreach (var obj in AssetDatabaseProvider.LoadAssetsWithSubAssets(internalId)) - { - var rtt = AddressableAssetUtility.MapEditorTypeToRuntimeType(obj.GetType(), false); - if (type.IsAssignableFrom(rtt)) - locations.Add(new ResourceLocationBase(keyStr, internalId, typeof(AssetDatabaseProvider).FullName, rtt)); - } - } - } - } - - string GetInternalIdFromFolderEntry(string keyStr, AddressableAssetEntry entry) - { - var entryPath = entry.AssetPath; - if (keyStr.StartsWith(entry.address + "/", StringComparison.Ordinal)) - return entryPath + keyStr.Substring(entry.address.Length); - foreach (var l in entry.labels) - { - if (keyStr.StartsWith(l + "/", StringComparison.Ordinal)) - return entryPath + keyStr.Substring(l.Length); - } - - return string.Empty; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.Build.Content; +using UnityEngine; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.ResourceManagement.ResourceLocations; +using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.U2D; +using static UnityEditor.AddressableAssets.Settings.AddressablesFileEnumeration; + +namespace UnityEditor.AddressableAssets.Settings +{ + internal class AddressableAssetSettingsLocator : IResourceLocator + { + private static Type m_SpriteType = typeof(Sprite); + private static Type m_SpriteAtlasType = typeof(SpriteAtlas); + + public string LocatorId { get; private set; } + public Dictionary> m_keyToEntries; + public Dictionary> m_Cache; + public AddressableAssetTree m_AddressableAssetTree; + HashSet m_Keys = null; + AddressableAssetSettings m_Settings; + bool m_includeResourcesFolders = false; + bool m_dirty = true; + + public IEnumerable Keys + { + get + { + if (m_dirty) + RebuildInternalData(); + if (m_Keys == null) + { + var visitedFolders = new HashSet(); + using (new AddressablesFileEnumerationScope(m_AddressableAssetTree)) + { + m_Keys = new HashSet(); + foreach (var kvp in m_keyToEntries) + { + var hasNonFolder = false; + foreach (var e in kvp.Value) + { + if (AssetDatabase.IsValidFolder(e.AssetPath)) + { + if (!visitedFolders.Contains(e.AssetPath)) + { + foreach (var f in EnumerateAddressableFolder(e.AssetPath, m_Settings, true)) + { + m_Keys.Add(f.Replace(e.AssetPath, e.address)); + m_Keys.Add(AssetDatabase.AssetPathToGUID(f)); + } + + visitedFolders.Add(e.AssetPath); + } + + foreach (var l in e.labels) + m_Keys.Add(l); + } + else + { + hasNonFolder = true; + } + } + + if (hasNonFolder) + m_Keys.Add(kvp.Key); + } + + if (m_includeResourcesFolders) + { + var resourcesEntry = m_Settings.FindAssetEntry(AddressableAssetEntry.ResourcesName); + resourcesEntry.GatherResourcesEntries(null, true, entry => + { + m_Keys.Add(entry.address); + m_Keys.Add(entry.guid); + return false; + }); + } + } + } + + return m_Keys; + } + } + + /// + /// Returns an empty array of locations. + /// + public IEnumerable AllLocations => new IResourceLocation[0]; + + public struct CacheKey : IEquatable + { + public object m_key; + public Type m_type; + + public bool Equals(CacheKey other) + { + if (!m_key.Equals(other.m_key)) + return false; + return m_type == other.m_type; + } + + public override int GetHashCode() => m_key.GetHashCode() * 31 + (m_type == null ? 0 : m_type.GetHashCode()); + } + + public AddressableAssetSettingsLocator(AddressableAssetSettings settings) + { + m_Settings = settings; + LocatorId = m_Settings.name; + m_dirty = true; + m_Settings.OnModification += Settings_OnModification; + } + + void RebuildInternalData() + { + m_Keys = null; + m_AddressableAssetTree = BuildAddressableTree(m_Settings); + m_Cache = new Dictionary>(); + m_keyToEntries = new Dictionary>(m_Settings.labelTable.labelNames.Count); + using (new AddressablesFileEnumerationScope(m_AddressableAssetTree)) + { + foreach (AddressableAssetGroup g in m_Settings.groups) + { + if (g == null) + continue; + + foreach (AddressableAssetEntry e in g.entries) + { + if (e.guid == AddressableAssetEntry.EditorSceneListName) + { + if (e.parentGroup.GetSchema().IncludeBuildSettingsScenes) + { + e.GatherAllAssets(null, false, false, false, s => + { + AddEntriesToTables(m_keyToEntries, s); + return false; + }); + } + } + else if (e.guid == AddressableAssetEntry.ResourcesName) + { + m_includeResourcesFolders = e.parentGroup.GetSchema().IncludeResourcesFolders; + } + else + { + AddEntriesToTables(m_keyToEntries, e); + } + } + } + } + + m_dirty = false; + } + + private void Settings_OnModification(AddressableAssetSettings settings, AddressableAssetSettings.ModificationEvent evt, object arg3) + { + switch (evt) + { + case AddressableAssetSettings.ModificationEvent.EntryAdded: + case AddressableAssetSettings.ModificationEvent.EntryCreated: + case AddressableAssetSettings.ModificationEvent.EntryModified: + case AddressableAssetSettings.ModificationEvent.EntryMoved: + case AddressableAssetSettings.ModificationEvent.EntryRemoved: + case AddressableAssetSettings.ModificationEvent.GroupRemoved: + case AddressableAssetSettings.ModificationEvent.LabelAdded: + case AddressableAssetSettings.ModificationEvent.LabelRemoved: + case AddressableAssetSettings.ModificationEvent.BatchModification: + m_dirty = true; + break; + } + } + + static void AddEntry(AddressableAssetEntry e, object k, Dictionary> keyToEntries) + { + if (!keyToEntries.TryGetValue(k, out HashSet entries)) + keyToEntries.Add(k, entries = new HashSet()); + entries.Add(e); + } + + static void AddEntriesToTables(Dictionary> keyToEntries, AddressableAssetEntry e) + { + AddEntry(e, e.address, keyToEntries); + AddEntry(e, e.guid, keyToEntries); + if (e.IsScene && e.IsInSceneList) + { + int index = BuiltinSceneCache.GetSceneIndex(new GUID(e.guid)); + if (index != -1) + AddEntry(e, index, keyToEntries); + } + + if (e.labels != null) + { + foreach (string l in e.labels) + { + AddEntry(e, l, keyToEntries); + } + } + } + + static void GatherEntryLocations(AddressableAssetEntry entry, Type type, IList locations, AddressableAssetTree assetTree) + { + if (!string.IsNullOrEmpty(entry.address) && entry.address.Contains('[') && entry.address.Contains(']')) + { + Debug.LogErrorFormat("Address '{0}' cannot contain '[ ]'.", entry.address); + return; + } + + using (new AddressablesFileEnumerationScope(assetTree)) + { + entry.GatherAllAssets(null, true, true, false, e => + { + if (e.IsScene) + { + if (type == null || type == typeof(object) || type == typeof(SceneInstance) || AddressableAssetUtility.MapEditorTypeToRuntimeType(e.MainAssetType, false) == type) + locations.Add(new ResourceLocationBase(e.address, e.AssetPath, typeof(SceneProvider).FullName, typeof(SceneInstance))); + } + else if (type == null || (type.IsAssignableFrom(e.MainAssetType) && type != typeof(object))) + { + locations.Add(new ResourceLocationBase(e.address, e.AssetPath, typeof(AssetDatabaseProvider).FullName, e.MainAssetType)); + return true; + } + else + { + ObjectIdentifier[] ids = ContentBuildInterface.GetPlayerObjectIdentifiersInAsset(new GUID(e.guid), EditorUserBuildSettings.activeBuildTarget); + if (ids.Length > 0) + { + foreach (var t in AddressableAssetEntry.GatherMainAndReferencedSerializedTypes(ids)) + { + if (type.IsAssignableFrom(t)) + locations.Add( + new ResourceLocationBase(e.address, e.AssetPath, typeof(AssetDatabaseProvider).FullName, AddressableAssetUtility.MapEditorTypeToRuntimeType(t, false))); + } + + return true; + } + } + + return false; + }); + } + } + + public bool Locate(object key, Type type, out IList locations) + { + if (m_dirty) + RebuildInternalData(); + CacheKey cacheKey = new CacheKey() {m_key = key, m_type = type}; + if (m_Cache.TryGetValue(cacheKey, out locations)) + return locations != null; + + locations = new List(); + if (m_keyToEntries.TryGetValue(key, out HashSet entries)) + { + foreach (AddressableAssetEntry e in entries) + { + if (AssetDatabase.IsValidFolder(e.AssetPath) && !e.labels.Contains(key as string)) + continue; + + if (type == null) + { + if (e.MainAssetType != typeof(SceneAsset)) + { + ObjectIdentifier[] ids = + ContentBuildInterface.GetPlayerObjectIdentifiersInAsset(new GUID(e.guid), + EditorUserBuildSettings.activeBuildTarget); + List mainObjectTypes = AddressableAssetEntry.GatherMainObjectTypes(ids); + + if (mainObjectTypes.Count > 0) + { + foreach (Type t in mainObjectTypes) + GatherEntryLocations(e, t, locations, m_AddressableAssetTree); + } + else + { + GatherEntryLocations(e, null, locations, m_AddressableAssetTree); + } + } + else + { + GatherEntryLocations(e, null, locations, m_AddressableAssetTree); + } + } + else + { + GatherEntryLocations(e, type, locations, m_AddressableAssetTree); + } + } + } + + if (type == null) + type = typeof(object); + + string keyStr = key as string; + if (!string.IsNullOrEmpty(keyStr)) + { + //check if the key is a guid first + var keyPath = AssetDatabase.GUIDToAssetPath(keyStr); + if (!string.IsNullOrEmpty(keyPath)) + { + //only look for folders from GUID if no locations have been found + if (locations.Count == 0) + { + var slash = keyPath.LastIndexOf('/'); + while (slash > 0) + { + keyPath = keyPath.Substring(0, slash); + var parentFolderKey = AssetDatabase.AssetPathToGUID(keyPath); + if (string.IsNullOrEmpty(parentFolderKey)) + break; + + if (m_keyToEntries.ContainsKey(parentFolderKey)) + { + AddLocations(locations, type, keyPath, AssetDatabase.GUIDToAssetPath(keyStr)); + break; + } + + slash = keyPath.LastIndexOf('/'); + } + } + } + else + { + //if the key is not a GUID, see if it is contained in a folder entry + keyPath = keyStr; + int slash = keyPath.LastIndexOf('/'); + while (slash > 0) + { + keyPath = keyPath.Substring(0, slash); + if (m_keyToEntries.TryGetValue(keyPath, out var entry)) + { + foreach (var e in entry) + AddLocations(locations, type, keyStr, GetInternalIdFromFolderEntry(keyStr, e)); + break; + } + + slash = keyPath.LastIndexOf('/'); + } + } + + //check resources folders + if (m_includeResourcesFolders) + { + string resPath = keyStr; + var ext = System.IO.Path.GetExtension(resPath); + if (!string.IsNullOrEmpty(ext)) + resPath = resPath.Substring(0, resPath.Length - ext.Length); + UnityEngine.Object obj = Resources.Load(resPath, type); + if (obj == null && keyStr.Length == 32) + { + resPath = AssetDatabase.GUIDToAssetPath(keyStr); + if (!string.IsNullOrEmpty(resPath)) + { + int index = resPath.IndexOf("Resources/", StringComparison.OrdinalIgnoreCase); + if (index >= 0) + { + int start = index + 10; + int length = resPath.Length - (start + System.IO.Path.GetExtension(resPath).Length); + resPath = resPath.Substring(index + 10, length); + obj = Resources.Load(resPath, type); + } + } + } + + if (obj != null) + locations.Add(new ResourceLocationBase(keyStr, resPath, typeof(LegacyResourcesProvider).FullName, type)); + } + } + + if (locations.Count == 0) + { + locations = null; + m_Cache.Add(cacheKey, locations); + return false; + } + + m_Cache.Add(cacheKey, locations); + return true; + } + + internal static void AddLocations(IList locations, Type type, string keyStr, string internalId) + { + if (!string.IsNullOrEmpty(internalId) && !string.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(internalId))) + { + if (type == m_SpriteType && AssetDatabase.GetMainAssetTypeAtPath(internalId) == m_SpriteAtlasType) + locations.Add(new ResourceLocationBase(keyStr, internalId, typeof(AssetDatabaseProvider).FullName, m_SpriteAtlasType)); + else + { + foreach (var obj in AssetDatabaseProvider.LoadAssetsWithSubAssets(internalId)) + { + var rtt = AddressableAssetUtility.MapEditorTypeToRuntimeType(obj.GetType(), false); + if (type.IsAssignableFrom(rtt)) + locations.Add(new ResourceLocationBase(keyStr, internalId, typeof(AssetDatabaseProvider).FullName, rtt)); + } + } + } + } + + string GetInternalIdFromFolderEntry(string keyStr, AddressableAssetEntry entry) + { + var entryPath = entry.AssetPath; + if (keyStr.StartsWith(entry.address + "/", StringComparison.Ordinal)) + return entryPath + keyStr.Substring(entry.address.Length); + foreach (var l in entry.labels) + { + if (keyStr.StartsWith(l + "/", StringComparison.Ordinal)) + return entryPath + keyStr.Substring(l.Length); + } + + return string.Empty; + } + } +} diff --git a/Editor/Build/AddressableAssetSettingsLocator.cs.meta b/Editor/Build/AddressableAssetSettingsLocator.cs.meta index 97b813c5..2128fc48 100644 --- a/Editor/Build/AddressableAssetSettingsLocator.cs.meta +++ b/Editor/Build/AddressableAssetSettingsLocator.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: b9c2125236cf11d4a98cd25ea3214ad4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: b9c2125236cf11d4a98cd25ea3214ad4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AddressablesBuildScriptHooks.cs b/Editor/Build/AddressablesBuildScriptHooks.cs index 772bb8d8..50b079d1 100644 --- a/Editor/Build/AddressablesBuildScriptHooks.cs +++ b/Editor/Build/AddressablesBuildScriptHooks.cs @@ -1,74 +1,74 @@ -using System; -using UnityEngine; - -namespace UnityEditor.AddressableAssets.Build -{ - /// - /// Entry point to set callbacks for builds. - /// - public static class BuildScript - { - /// - /// Global delegate for handling the result of AddressableAssets builds. This will get called for player builds and when entering play mode. - /// - public static Action buildCompleted; - } - - static class AddressablesBuildScriptHooks - { - [InitializeOnLoadMethod] - static void Init() - { - EditorApplication.playModeStateChanged += OnEditorPlayModeChanged; - } - - static void OnEditorPlayModeChanged(PlayModeStateChange state) - { - var settings = AddressableAssetSettingsDefaultObject.Settings; - if (settings == null) - return; - if (state == PlayModeStateChange.ExitingEditMode) - { - if (settings.ActivePlayModeDataBuilder == null) - { - var err = "Active play mode build script is null."; - Debug.LogError(err); - - if (BuildScript.buildCompleted != null) - { - var result = AddressableAssetBuildResult.CreateResult(null, 0, err); - BuildScript.buildCompleted(result); - } - - return; - } - - if (!settings.ActivePlayModeDataBuilder.CanBuildData()) - { - var err = string.Format("Active build script {0} cannot build AddressablesPlayModeBuildResult.", settings.ActivePlayModeDataBuilder); - Debug.LogError(err); - if (BuildScript.buildCompleted != null) - { - var result = AddressableAssetBuildResult.CreateResult(null, 0, err); - BuildScript.buildCompleted(result); - } - - return; - } - - var res = settings.ActivePlayModeDataBuilder.BuildData(new AddressablesDataBuilderInput(settings)); - if (!string.IsNullOrEmpty(res.Error)) - { - Debug.LogError(res.Error); - EditorApplication.isPlaying = false; - } - else - { - if (BuildScript.buildCompleted != null) - BuildScript.buildCompleted(res); - settings.DataBuilderCompleted(settings.ActivePlayModeDataBuilder, res); - } - } - } - } -} +using System; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// Entry point to set callbacks for builds. + /// + public static class BuildScript + { + /// + /// Global delegate for handling the result of AddressableAssets builds. This will get called for player builds and when entering play mode. + /// + public static Action buildCompleted; + } + + static class AddressablesBuildScriptHooks + { + [InitializeOnLoadMethod] + static void Init() + { + EditorApplication.playModeStateChanged += OnEditorPlayModeChanged; + } + + static void OnEditorPlayModeChanged(PlayModeStateChange state) + { + var settings = AddressableAssetSettingsDefaultObject.Settings; + if (settings == null) + return; + if (state == PlayModeStateChange.ExitingEditMode) + { + if (settings.ActivePlayModeDataBuilder == null) + { + var err = "Active play mode build script is null."; + Debug.LogError(err); + + if (BuildScript.buildCompleted != null) + { + var result = AddressableAssetBuildResult.CreateResult(null, 0, err); + BuildScript.buildCompleted(result); + } + + return; + } + + if (!settings.ActivePlayModeDataBuilder.CanBuildData()) + { + var err = string.Format("Active build script {0} cannot build AddressablesPlayModeBuildResult.", settings.ActivePlayModeDataBuilder); + Debug.LogError(err); + if (BuildScript.buildCompleted != null) + { + var result = AddressableAssetBuildResult.CreateResult(null, 0, err); + BuildScript.buildCompleted(result); + } + + return; + } + + var res = settings.ActivePlayModeDataBuilder.BuildData(new AddressablesDataBuilderInput(settings)); + if (!string.IsNullOrEmpty(res.Error)) + { + Debug.LogError(res.Error); + EditorApplication.isPlaying = false; + } + else + { + if (BuildScript.buildCompleted != null) + BuildScript.buildCompleted(res); + settings.DataBuilderCompleted(settings.ActivePlayModeDataBuilder, res); + } + } + } + } +} diff --git a/Editor/Build/AddressablesBuildScriptHooks.cs.meta b/Editor/Build/AddressablesBuildScriptHooks.cs.meta index 50f4d30f..f877f7af 100644 --- a/Editor/Build/AddressablesBuildScriptHooks.cs.meta +++ b/Editor/Build/AddressablesBuildScriptHooks.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 0a15f049c10fa744ca827575ffac1c0d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 0a15f049c10fa744ca827575ffac1c0d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AddressablesDataBuilderInput.cs b/Editor/Build/AddressablesDataBuilderInput.cs index f3a6035d..705856a2 100644 --- a/Editor/Build/AddressablesDataBuilderInput.cs +++ b/Editor/Build/AddressablesDataBuilderInput.cs @@ -1,121 +1,121 @@ -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.Build.Pipeline.Interfaces; -using UnityEngine; - -namespace UnityEditor.AddressableAssets.Build -{ - /// - /// Data builder context object for Addressables. - /// - public class AddressablesDataBuilderInput - { - /// - /// The main addressables settings object. - /// - public AddressableAssetSettings AddressableSettings { get; private set; } - - /// - /// Build target group. - /// - public BuildTargetGroup TargetGroup { get; private set; } - - /// - /// Build target. - /// - public BuildTarget Target { get; private set; } - - /// - /// Player build version. - /// - public string PlayerVersion { get; set; } - - /// - /// Bool to signify if profiler events should be broadcast. - /// - public bool ProfilerEventsEnabled { get; private set; } - - /// - /// Registry of files created during the build - /// - public FileRegistry Registry { get; private set; } - - //used only by tests to inject custom info into build... - internal string PathSuffix = string.Empty; - - /// - /// The name of the default Runtime Settings file. - /// - public string RuntimeSettingsFilename = "settings.json"; - - /// - /// The name of the default Runtime Catalog file. - /// - public string RuntimeCatalogFilename = -#if ENABLE_BINARY_CATALOG - "catalog.bin"; -#else - "catalog.json"; -#endif - /// - /// The asset content state of a previous build. This allows detection of deltas with the current build content state. This will be - /// null in standard builds. This is only set during content update builds. - /// - public AddressablesContentState PreviousContentState { get; set; } - - - /// - /// Creates a default context object with values taken from the AddressableAssetSettings parameter. - /// - /// The settings object to pull values from. - public AddressablesDataBuilderInput(AddressableAssetSettings settings) - { - string version = string.Empty; - if (settings == null) - { - Debug.LogError("Attempting to set up AddressablesDataBuilderInput with null settings."); - } - else - version = settings.PlayerBuildVersion; - - SetAllValues(settings, - BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget), - EditorUserBuildSettings.activeBuildTarget, - version); - } - - /// - /// Creates a default context object with values taken from the AddressableAssetSettings parameter. - /// - /// The settings object to pull values from. - /// The player build version. - public AddressablesDataBuilderInput(AddressableAssetSettings settings, string playerBuildVersion) - { - if (settings == null) - { - Debug.LogError("Attempting to set up AddressablesDataBuilderInput with null settings."); - } - - SetAllValues(settings, - BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget), - EditorUserBuildSettings.activeBuildTarget, - playerBuildVersion); - } - - internal void SetAllValues(AddressableAssetSettings settings, BuildTargetGroup buildTargetGroup, BuildTarget buildTarget, string playerBuildVersion) - { - AddressableSettings = settings; - - TargetGroup = buildTargetGroup; - Target = buildTarget; - PlayerVersion = playerBuildVersion; - ProfilerEventsEnabled = ProjectConfigData.PostProfilerEvents; - Registry = new FileRegistry(); - PreviousContentState = null; - } - - internal bool IsBuildAndRelease = false; - internal bool IsContentUpdateBuild = false; - - internal IBuildLogger Logger { get; set; } - } -} +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// Data builder context object for Addressables. + /// + public class AddressablesDataBuilderInput + { + /// + /// The main addressables settings object. + /// + public AddressableAssetSettings AddressableSettings { get; private set; } + + /// + /// Build target group. + /// + public BuildTargetGroup TargetGroup { get; private set; } + + /// + /// Build target. + /// + public BuildTarget Target { get; private set; } + + /// + /// Player build version. + /// + public string PlayerVersion { get; set; } + + /// + /// Bool to signify if profiler events should be broadcast. + /// + public bool ProfilerEventsEnabled { get; private set; } + + /// + /// Registry of files created during the build + /// + public FileRegistry Registry { get; private set; } + + //used only by tests to inject custom info into build... + internal string PathSuffix = string.Empty; + + /// + /// The name of the default Runtime Settings file. + /// + public string RuntimeSettingsFilename = "settings.json"; + + /// + /// The name of the default Runtime Catalog file. + /// + public string RuntimeCatalogFilename = +#if ENABLE_BINARY_CATALOG + "catalog.bin"; +#else + "catalog.json"; +#endif + /// + /// The asset content state of a previous build. This allows detection of deltas with the current build content state. This will be + /// null in standard builds. This is only set during content update builds. + /// + public AddressablesContentState PreviousContentState { get; set; } + + + /// + /// Creates a default context object with values taken from the AddressableAssetSettings parameter. + /// + /// The settings object to pull values from. + public AddressablesDataBuilderInput(AddressableAssetSettings settings) + { + string version = string.Empty; + if (settings == null) + { + Debug.LogError("Attempting to set up AddressablesDataBuilderInput with null settings."); + } + else + version = settings.PlayerBuildVersion; + + SetAllValues(settings, + BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget), + EditorUserBuildSettings.activeBuildTarget, + version); + } + + /// + /// Creates a default context object with values taken from the AddressableAssetSettings parameter. + /// + /// The settings object to pull values from. + /// The player build version. + public AddressablesDataBuilderInput(AddressableAssetSettings settings, string playerBuildVersion) + { + if (settings == null) + { + Debug.LogError("Attempting to set up AddressablesDataBuilderInput with null settings."); + } + + SetAllValues(settings, + BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget), + EditorUserBuildSettings.activeBuildTarget, + playerBuildVersion); + } + + internal void SetAllValues(AddressableAssetSettings settings, BuildTargetGroup buildTargetGroup, BuildTarget buildTarget, string playerBuildVersion) + { + AddressableSettings = settings; + + TargetGroup = buildTargetGroup; + Target = buildTarget; + PlayerVersion = playerBuildVersion; + ProfilerEventsEnabled = ProjectConfigData.PostProfilerEvents; + Registry = new FileRegistry(); + PreviousContentState = null; + } + + internal bool IsBuildAndRelease = false; + internal bool IsContentUpdateBuild = false; + + internal IBuildLogger Logger { get; set; } + } +} diff --git a/Editor/Build/AddressablesDataBuilderInput.cs.meta b/Editor/Build/AddressablesDataBuilderInput.cs.meta index d85a2822..20e7fe0f 100644 --- a/Editor/Build/AddressablesDataBuilderInput.cs.meta +++ b/Editor/Build/AddressablesDataBuilderInput.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 69d3f19413a88324199b41186cf34b9f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 69d3f19413a88324199b41186cf34b9f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AddressablesDataBuilders.cs b/Editor/Build/AddressablesDataBuilders.cs index a48db159..3005b1a8 100644 --- a/Editor/Build/AddressablesDataBuilders.cs +++ b/Editor/Build/AddressablesDataBuilders.cs @@ -1,143 +1,143 @@ -using System; -using System.Collections.Generic; -using UnityEditor.AddressableAssets.Build.BuildPipelineTasks; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.Build.Pipeline; -using UnityEditor.Build.Pipeline.Interfaces; -using UnityEngine; - -namespace UnityEditor.AddressableAssets.Build -{ - /// - /// Contains information about the status of the build. - /// - public class AddressableAssetBuildResult : IDataBuilderResult - { - /// - /// Duration of build, in seconds. - /// - public double Duration { get; set; } - - /// - /// The number of addressable assets contained in the build. - /// - public int LocationCount { get; set; } - - /// - /// Error that caused the build to fail. - /// - public string Error { get; set; } - - /// - /// Path of runtime settings file - /// - public string OutputPath { get; set; } - - /// - /// Registry of files created during the build - /// - public FileRegistry FileRegistry { get; set; } - - /// - /// Helper method to create the desired result of a data builder. This should always be used to create the build result - /// with additional details added as needed. The Result.Duration should always be set at the end of the build - /// script in the non-error scenario. - /// - /// Path to the settings.json file (name may not always match that exactly) generated by this build - /// Number of locations created by this build - /// Error string if there were problems with the build. Defaults to empty - /// The actual build result created - /// - public static TResult CreateResult(string settingsPath, int locCount, string err = "") where TResult : IDataBuilderResult - { - var opResult = Activator.CreateInstance(); - opResult.OutputPath = settingsPath; - opResult.Duration = 0; - opResult.Error = err; - opResult.LocationCount = locCount; - return opResult; - } - - /// - /// Helper method to create the desired result of a data builder. This should always be used to create the build result - /// with additional details added as needed. The Result.Duration should always be set at the end of the build - /// script in the non-error scenario. Other results should be set as available. - /// - /// - /// - public static TResult CreateResult() where TResult : IDataBuilderResult - { - var opResult = Activator.CreateInstance(); - return opResult; - } - } - - /// - /// Build result for entering play mode in the editor. - /// - [Serializable] - public class AddressablesPlayModeBuildResult : AddressableAssetBuildResult - { - } - - /// - /// Build result for building the Addressables content. - /// - public class AddressablesPlayerBuildResult : AddressableAssetBuildResult - { - internal List m_AssetBundleBuildResults = new List(); - - /// - /// Information about a bundle build results - /// - [System.Serializable] - public class BundleBuildResult - { - /// - /// The file path of the bundle. - /// - public string FilePath; - /// - /// The internal AssetBundle name, this is not always the same as the file name. - /// - public string InternalBundleName; - /// - /// The Addressable Group that was responsible for generating a given AssetBundle - /// - public AddressableAssetGroup SourceAssetGroup; - /// - /// The calculated value used for security during cyclic redundancy checks - /// - public uint Crc; - /// - /// The asset hash of the assets included inside the AssetBundle - /// - public string Hash; - } - - /// - /// True if the build was doing an update to a previous build, else false. - /// - public bool IsUpdateContentBuild { get; internal set; } - - /// - /// Build results for AssetBundles created during the build. - /// - public List AssetBundleBuildResults => m_AssetBundleBuildResults; - - /// - /// File path to the generated remote catalog hash file. - /// - public string RemoteCatalogHashFilePath { get; internal set; } - - /// - /// File path to the generated remote catalog json file. - /// - public string RemoteCatalogJsonFilePath { get; internal set; } - - /// - /// File path to the generate content state file - /// - public string ContentStateFilePath { get; internal set; } - } -} +using System; +using System.Collections.Generic; +using UnityEditor.AddressableAssets.Build.BuildPipelineTasks; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.Build.Pipeline; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// Contains information about the status of the build. + /// + public class AddressableAssetBuildResult : IDataBuilderResult + { + /// + /// Duration of build, in seconds. + /// + public double Duration { get; set; } + + /// + /// The number of addressable assets contained in the build. + /// + public int LocationCount { get; set; } + + /// + /// Error that caused the build to fail. + /// + public string Error { get; set; } + + /// + /// Path of runtime settings file + /// + public string OutputPath { get; set; } + + /// + /// Registry of files created during the build + /// + public FileRegistry FileRegistry { get; set; } + + /// + /// Helper method to create the desired result of a data builder. This should always be used to create the build result + /// with additional details added as needed. The Result.Duration should always be set at the end of the build + /// script in the non-error scenario. + /// + /// Path to the settings.json file (name may not always match that exactly) generated by this build + /// Number of locations created by this build + /// Error string if there were problems with the build. Defaults to empty + /// The actual build result created + /// + public static TResult CreateResult(string settingsPath, int locCount, string err = "") where TResult : IDataBuilderResult + { + var opResult = Activator.CreateInstance(); + opResult.OutputPath = settingsPath; + opResult.Duration = 0; + opResult.Error = err; + opResult.LocationCount = locCount; + return opResult; + } + + /// + /// Helper method to create the desired result of a data builder. This should always be used to create the build result + /// with additional details added as needed. The Result.Duration should always be set at the end of the build + /// script in the non-error scenario. Other results should be set as available. + /// + /// + /// + public static TResult CreateResult() where TResult : IDataBuilderResult + { + var opResult = Activator.CreateInstance(); + return opResult; + } + } + + /// + /// Build result for entering play mode in the editor. + /// + [Serializable] + public class AddressablesPlayModeBuildResult : AddressableAssetBuildResult + { + } + + /// + /// Build result for building the Addressables content. + /// + public class AddressablesPlayerBuildResult : AddressableAssetBuildResult + { + internal List m_AssetBundleBuildResults = new List(); + + /// + /// Information about a bundle build results + /// + [System.Serializable] + public class BundleBuildResult + { + /// + /// The file path of the bundle. + /// + public string FilePath; + /// + /// The internal AssetBundle name, this is not always the same as the file name. + /// + public string InternalBundleName; + /// + /// The Addressable Group that was responsible for generating a given AssetBundle + /// + public AddressableAssetGroup SourceAssetGroup; + /// + /// The calculated value used for security during cyclic redundancy checks + /// + public uint Crc; + /// + /// The asset hash of the assets included inside the AssetBundle + /// + public string Hash; + } + + /// + /// True if the build was doing an update to a previous build, else false. + /// + public bool IsUpdateContentBuild { get; internal set; } + + /// + /// Build results for AssetBundles created during the build. + /// + public List AssetBundleBuildResults => m_AssetBundleBuildResults; + + /// + /// File path to the generated remote catalog hash file. + /// + public string RemoteCatalogHashFilePath { get; internal set; } + + /// + /// File path to the generated remote catalog json file. + /// + public string RemoteCatalogJsonFilePath { get; internal set; } + + /// + /// File path to the generate content state file + /// + public string ContentStateFilePath { get; internal set; } + } +} diff --git a/Editor/Build/AddressablesDataBuilders.cs.meta b/Editor/Build/AddressablesDataBuilders.cs.meta index c9ad37da..ae171e4a 100644 --- a/Editor/Build/AddressablesDataBuilders.cs.meta +++ b/Editor/Build/AddressablesDataBuilders.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 1912c97b524efd244bc0647b18230c7e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 1912c97b524efd244bc0647b18230c7e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AddressablesPlayerBuildProcessor.cs b/Editor/Build/AddressablesPlayerBuildProcessor.cs index b7a9fe9b..ed52d73b 100644 --- a/Editor/Build/AddressablesPlayerBuildProcessor.cs +++ b/Editor/Build/AddressablesPlayerBuildProcessor.cs @@ -1,221 +1,221 @@ -using System; -using System.IO; -using System.Collections.Generic; -using UnityEditor; -using UnityEditor.AddressableAssets; -using UnityEditor.AddressableAssets.Build; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.Build; -using UnityEditor.Build.Reporting; -using UnityEngine; -using UnityEngine.AddressableAssets; - -#if UNITY_2021_2_OR_NEWER -/// -/// Maintains Addresssables build data when processing a player build. -/// -public class AddressablesPlayerBuildProcessor : BuildPlayerProcessor -{ - /// - /// Functor to override Addressables build when building Player. - /// - /// - /// Functor is invoked where Addressables settings state to build Addressables content when performing a Player build. - /// - /// Available in Unity 2021.2 or later. - /// - public static Func BuildAddressablesOverride { get; set; } - - /// - /// Returns the player build processor callback order. - /// - public override int callbackOrder - { - get { return 1; } - } - - [InitializeOnLoadMethod] - private static void CleanTemporaryPlayerBuildData() - { - RemovePlayerBuildLinkXML(AddressableAssetSettingsDefaultObject.Settings); - } - - internal static void RemovePlayerBuildLinkXML(AddressableAssetSettings settings) - { - string linkProjectPath = GetLinkPath(settings, false); - string guid = AssetDatabase.AssetPathToGUID(linkProjectPath); - if (!string.IsNullOrEmpty(guid)) - AssetDatabase.DeleteAsset(linkProjectPath); - else if (File.Exists(linkProjectPath)) - File.Delete(linkProjectPath); - - DirectoryUtility.DeleteDirectory(Path.GetDirectoryName(linkProjectPath)); - } - - private static string GetLinkPath(AddressableAssetSettings settings, bool createFolder) - { - string folderPath; - if (settings == null) - folderPath = "Assets/Addressables_Temp"; - else - folderPath = settings.ConfigFolder; - - if (createFolder && !Directory.Exists(folderPath)) - { - Directory.CreateDirectory(folderPath); - AssetDatabase.ImportAsset(folderPath); - } - - return Path.Combine(folderPath, "link.xml"); - ; - } - - /// - /// Invoked before performing a Player build. Maintains building Addressables step and processing Addressables build data. - /// - /// - public override void PrepareForBuild(BuildPlayerContext buildPlayerContext) - { - var settings = AddressableAssetSettingsDefaultObject.Settings; - PrepareForPlayerbuild(settings, buildPlayerContext, ShouldBuildAddressablesForPlayerBuild(settings)); - } - - internal static void PrepareForPlayerbuild(AddressableAssetSettings settings, BuildPlayerContext buildPlayerContext, bool buildAddressables) - { - if (settings != null && buildAddressables) - { - AddressablesPlayerBuildResult result; - if (BuildAddressablesOverride != null) - { - try - { - result = BuildAddressablesOverride.Invoke(settings); - } - catch (Exception e) - { - result = new AddressablesPlayerBuildResult(); - result.Error = "Exception in BuildAddressablesOverride: " + e; - } - } - else - AddressableAssetSettings.BuildPlayerContent(out result); - - if (result != null && !string.IsNullOrEmpty(result.Error)) - Debug.LogError($"Failed to build Addressables content, content not included in Player Build. \"{result.Error}\""); - } - - if (buildPlayerContext != null) - { - var streamingAssetValues = GetStreamingAssetPaths(); - foreach (KeyValuePair streamingAssetValue in streamingAssetValues) - { - buildPlayerContext.AddAdditionalPathToStreamingAssets(streamingAssetValue.Key, - streamingAssetValue.Value); - } - } - - string buildPath = Addressables.BuildPath + "/AddressablesLink/link.xml"; - if (File.Exists(buildPath)) - { - string projectPath = GetLinkPath(settings, true); - File.Copy(buildPath, projectPath, true); - AssetDatabase.ImportAsset(projectPath, ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.DontDownloadFromCacheServer); - } - } - - internal static bool ShouldBuildAddressablesForPlayerBuild(AddressableAssetSettings settings) - { - if (settings == null) - return false; - - switch (settings.BuildAddressablesWithPlayerBuild) - { - case AddressableAssetSettings.PlayerBuildOption.DoNotBuildWithPlayer: - return false; - case AddressableAssetSettings.PlayerBuildOption.BuildWithPlayer: - break; - case AddressableAssetSettings.PlayerBuildOption.PreferencesValue: - if (!EditorPrefs.GetBool(AddressablesPreferences.kBuildAddressablesWithPlayerBuildKey, true)) - return false; - break; - } - - return true; - } - - /// - /// Allows to filter paths which should be added to StreamingAssets during build. Should return true if path should be added to Streaming Assets. - /// - internal static Func AddPathToStreamingAssets { get; set; } - - /// - /// Gets a list of StreamingAsset files managed through Addressables, and relative path in StreamingAssets. - /// - internal static List> GetStreamingAssetPaths() - { - List> pairs = new List>(1); - if (Directory.Exists(Addressables.BuildPath) && (AddPathToStreamingAssets != null ? AddPathToStreamingAssets.Invoke(Addressables.BuildPath) : true)) - pairs.Add(new KeyValuePair(Addressables.BuildPath, "aa")); - return pairs; - } -} -#else -/// -/// Maintains Addresssables build data when processing a player build. -/// -public class AddressablesPlayerBuildProcessor : IPreprocessBuildWithReport, IPostprocessBuildWithReport -{ - /// - /// Returns the player build processor callback order. - /// - public int callbackOrder - { - get { return 1; } - } - - /// - /// Restores temporary data created as part of a build. - /// - /// Stores temporary player build data. - public void OnPostprocessBuild(BuildReport report) - { - CleanTemporaryPlayerBuildData(); - } - - [InitializeOnLoadMethod] - internal static void CleanTemporaryPlayerBuildData() - { - if (Directory.Exists(Addressables.PlayerBuildDataPath)) - { - DirectoryUtility.DirectoryMove(Addressables.PlayerBuildDataPath, Addressables.BuildPath); - DirectoryUtility.DeleteDirectory(Application.streamingAssetsPath, onlyIfEmpty: true); - } - } - - /// - /// Initializes temporary build data. - /// - /// Contains build data information. - public void OnPreprocessBuild(BuildReport report) - { - CopyTemporaryPlayerBuildData(); - } - - internal static void CopyTemporaryPlayerBuildData() - { - if (Directory.Exists(Addressables.BuildPath)) - { - if (Directory.Exists(Addressables.PlayerBuildDataPath)) - { - Debug.LogWarning($"Found and deleting directory \"{Addressables.PlayerBuildDataPath}\", directory is managed through Addressables."); - DirectoryUtility.DeleteDirectory(Addressables.PlayerBuildDataPath, false); - } - - string parentDir = Path.GetDirectoryName(Addressables.PlayerBuildDataPath); - if (!string.IsNullOrEmpty(parentDir) && !Directory.Exists(parentDir)) - Directory.CreateDirectory(parentDir); - Directory.Move(Addressables.BuildPath, Addressables.PlayerBuildDataPath ); - } - } -} -#endif +using System; +using System.IO; +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.AddressableAssets; +using UnityEditor.AddressableAssets.Build; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using UnityEngine; +using UnityEngine.AddressableAssets; + +#if UNITY_2021_2_OR_NEWER +/// +/// Maintains Addresssables build data when processing a player build. +/// +public class AddressablesPlayerBuildProcessor : BuildPlayerProcessor +{ + /// + /// Functor to override Addressables build when building Player. + /// + /// + /// Functor is invoked where Addressables settings state to build Addressables content when performing a Player build. + /// + /// Available in Unity 2021.2 or later. + /// + public static Func BuildAddressablesOverride { get; set; } + + /// + /// Returns the player build processor callback order. + /// + public override int callbackOrder + { + get { return 1; } + } + + [InitializeOnLoadMethod] + private static void CleanTemporaryPlayerBuildData() + { + RemovePlayerBuildLinkXML(AddressableAssetSettingsDefaultObject.Settings); + } + + internal static void RemovePlayerBuildLinkXML(AddressableAssetSettings settings) + { + string linkProjectPath = GetLinkPath(settings, false); + string guid = AssetDatabase.AssetPathToGUID(linkProjectPath); + if (!string.IsNullOrEmpty(guid)) + AssetDatabase.DeleteAsset(linkProjectPath); + else if (File.Exists(linkProjectPath)) + File.Delete(linkProjectPath); + + DirectoryUtility.DeleteDirectory(Path.GetDirectoryName(linkProjectPath)); + } + + private static string GetLinkPath(AddressableAssetSettings settings, bool createFolder) + { + string folderPath; + if (settings == null) + folderPath = "Assets/Addressables_Temp"; + else + folderPath = settings.ConfigFolder; + + if (createFolder && !Directory.Exists(folderPath)) + { + Directory.CreateDirectory(folderPath); + AssetDatabase.ImportAsset(folderPath); + } + + return Path.Combine(folderPath, "link.xml"); + ; + } + + /// + /// Invoked before performing a Player build. Maintains building Addressables step and processing Addressables build data. + /// + /// + public override void PrepareForBuild(BuildPlayerContext buildPlayerContext) + { + var settings = AddressableAssetSettingsDefaultObject.Settings; + PrepareForPlayerbuild(settings, buildPlayerContext, ShouldBuildAddressablesForPlayerBuild(settings)); + } + + internal static void PrepareForPlayerbuild(AddressableAssetSettings settings, BuildPlayerContext buildPlayerContext, bool buildAddressables) + { + if (settings != null && buildAddressables) + { + AddressablesPlayerBuildResult result; + if (BuildAddressablesOverride != null) + { + try + { + result = BuildAddressablesOverride.Invoke(settings); + } + catch (Exception e) + { + result = new AddressablesPlayerBuildResult(); + result.Error = "Exception in BuildAddressablesOverride: " + e; + } + } + else + AddressableAssetSettings.BuildPlayerContent(out result); + + if (result != null && !string.IsNullOrEmpty(result.Error)) + Debug.LogError($"Failed to build Addressables content, content not included in Player Build. \"{result.Error}\""); + } + + if (buildPlayerContext != null) + { + var streamingAssetValues = GetStreamingAssetPaths(); + foreach (KeyValuePair streamingAssetValue in streamingAssetValues) + { + buildPlayerContext.AddAdditionalPathToStreamingAssets(streamingAssetValue.Key, + streamingAssetValue.Value); + } + } + + string buildPath = Addressables.BuildPath + "/AddressablesLink/link.xml"; + if (File.Exists(buildPath)) + { + string projectPath = GetLinkPath(settings, true); + File.Copy(buildPath, projectPath, true); + AssetDatabase.ImportAsset(projectPath, ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.DontDownloadFromCacheServer); + } + } + + internal static bool ShouldBuildAddressablesForPlayerBuild(AddressableAssetSettings settings) + { + if (settings == null) + return false; + + switch (settings.BuildAddressablesWithPlayerBuild) + { + case AddressableAssetSettings.PlayerBuildOption.DoNotBuildWithPlayer: + return false; + case AddressableAssetSettings.PlayerBuildOption.BuildWithPlayer: + break; + case AddressableAssetSettings.PlayerBuildOption.PreferencesValue: + if (!EditorPrefs.GetBool(AddressablesPreferences.kBuildAddressablesWithPlayerBuildKey, true)) + return false; + break; + } + + return true; + } + + /// + /// Allows to filter paths which should be added to StreamingAssets during build. Should return true if path should be added to Streaming Assets. + /// + internal static Func AddPathToStreamingAssets { get; set; } + + /// + /// Gets a list of StreamingAsset files managed through Addressables, and relative path in StreamingAssets. + /// + internal static List> GetStreamingAssetPaths() + { + List> pairs = new List>(1); + if (Directory.Exists(Addressables.BuildPath) && (AddPathToStreamingAssets != null ? AddPathToStreamingAssets.Invoke(Addressables.BuildPath) : true)) + pairs.Add(new KeyValuePair(Addressables.BuildPath, "aa")); + return pairs; + } +} +#else +/// +/// Maintains Addresssables build data when processing a player build. +/// +public class AddressablesPlayerBuildProcessor : IPreprocessBuildWithReport, IPostprocessBuildWithReport +{ + /// + /// Returns the player build processor callback order. + /// + public int callbackOrder + { + get { return 1; } + } + + /// + /// Restores temporary data created as part of a build. + /// + /// Stores temporary player build data. + public void OnPostprocessBuild(BuildReport report) + { + CleanTemporaryPlayerBuildData(); + } + + [InitializeOnLoadMethod] + internal static void CleanTemporaryPlayerBuildData() + { + if (Directory.Exists(Addressables.PlayerBuildDataPath)) + { + DirectoryUtility.DirectoryMove(Addressables.PlayerBuildDataPath, Addressables.BuildPath); + DirectoryUtility.DeleteDirectory(Application.streamingAssetsPath, onlyIfEmpty: true); + } + } + + /// + /// Initializes temporary build data. + /// + /// Contains build data information. + public void OnPreprocessBuild(BuildReport report) + { + CopyTemporaryPlayerBuildData(); + } + + internal static void CopyTemporaryPlayerBuildData() + { + if (Directory.Exists(Addressables.BuildPath)) + { + if (Directory.Exists(Addressables.PlayerBuildDataPath)) + { + Debug.LogWarning($"Found and deleting directory \"{Addressables.PlayerBuildDataPath}\", directory is managed through Addressables."); + DirectoryUtility.DeleteDirectory(Addressables.PlayerBuildDataPath, false); + } + + string parentDir = Path.GetDirectoryName(Addressables.PlayerBuildDataPath); + if (!string.IsNullOrEmpty(parentDir) && !Directory.Exists(parentDir)) + Directory.CreateDirectory(parentDir); + Directory.Move(Addressables.BuildPath, Addressables.PlayerBuildDataPath ); + } + } +} +#endif diff --git a/Editor/Build/AddressablesPlayerBuildProcessor.cs.meta b/Editor/Build/AddressablesPlayerBuildProcessor.cs.meta index beca3c9a..7d5c0311 100644 --- a/Editor/Build/AddressablesPlayerBuildProcessor.cs.meta +++ b/Editor/Build/AddressablesPlayerBuildProcessor.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 834e2bdb5fd1336429e26ec5bcbb77f7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 834e2bdb5fd1336429e26ec5bcbb77f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AnalyzeRules.meta b/Editor/Build/AnalyzeRules.meta index 5747689b..84bbc4a8 100644 --- a/Editor/Build/AnalyzeRules.meta +++ b/Editor/Build/AnalyzeRules.meta @@ -1,8 +1,8 @@ -fileFormatVersion: 2 -guid: 85d34cd37047d904e847f7f5e2b1bd25 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 85d34cd37047d904e847f7f5e2b1bd25 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AnalyzeRules/AnalyzeResultData.cs b/Editor/Build/AnalyzeRules/AnalyzeResultData.cs index c50b2446..0ce65067 100644 --- a/Editor/Build/AnalyzeRules/AnalyzeResultData.cs +++ b/Editor/Build/AnalyzeRules/AnalyzeResultData.cs @@ -1,89 +1,89 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace UnityEditor.AddressableAssets.Build.AnalyzeRules -{ - /// - /// Represents the data acquired after analyzing Addressable assets. - /// - [Obsolete("This has been made obsolete and is no longer functional. Analyze result data is handled internally.")] - public class AnalyzeResultData : ScriptableObject, ISerializationCallbackReceiver - { - /// - /// Retrieves serialized data after a domain reload. - /// - public void OnAfterDeserialize() - { - //Do nothing - } - - /// - /// Converts our data to a serialized structure before a domain reload. - /// - public void OnBeforeSerialize() - { - //Do nothing - } - } - - /// - /// Represents the data acquired after analyzing Addressable assets. - /// - [Serializable] - public class AddressablesAnalyzeResultData : ISerializationCallbackReceiver - { - [Serializable] - private class RuleToResults - { - [SerializeField] - public string RuleName; - - [SerializeField] - public List Results; - - public RuleToResults(string ruleName, List results) - { - RuleName = ruleName; - Results = results; - } - } - - [SerializeField] - private List m_RuleToResults = new List(); - - internal Dictionary> Data = - new Dictionary>(); - - /// - /// Retrieves serialized data after a domain reload. - /// - public void OnAfterDeserialize() - { - for (int i = 0; i < m_RuleToResults.Count; i++) - Data.Add(m_RuleToResults[i].RuleName, m_RuleToResults[i].Results); - } - - /// - /// Converts our data to a serialized structure before a domain reload. - /// - public void OnBeforeSerialize() - { - m_RuleToResults.Clear(); - - foreach (var key in Data.Keys) - m_RuleToResults.Add(new RuleToResults(key, Data[key])); - } - - internal void Clear(AnalyzeRule rule) - { - Clear(rule.ruleName); - } - - internal void Clear(string ruleName) - { - if (Data.ContainsKey(ruleName)) - Data[ruleName].Clear(); - } - } -} +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build.AnalyzeRules +{ + /// + /// Represents the data acquired after analyzing Addressable assets. + /// + [Obsolete("This has been made obsolete and is no longer functional. Analyze result data is handled internally.")] + public class AnalyzeResultData : ScriptableObject, ISerializationCallbackReceiver + { + /// + /// Retrieves serialized data after a domain reload. + /// + public void OnAfterDeserialize() + { + //Do nothing + } + + /// + /// Converts our data to a serialized structure before a domain reload. + /// + public void OnBeforeSerialize() + { + //Do nothing + } + } + + /// + /// Represents the data acquired after analyzing Addressable assets. + /// + [Serializable] + public class AddressablesAnalyzeResultData : ISerializationCallbackReceiver + { + [Serializable] + private class RuleToResults + { + [SerializeField] + public string RuleName; + + [SerializeField] + public List Results; + + public RuleToResults(string ruleName, List results) + { + RuleName = ruleName; + Results = results; + } + } + + [SerializeField] + private List m_RuleToResults = new List(); + + internal Dictionary> Data = + new Dictionary>(); + + /// + /// Retrieves serialized data after a domain reload. + /// + public void OnAfterDeserialize() + { + for (int i = 0; i < m_RuleToResults.Count; i++) + Data.Add(m_RuleToResults[i].RuleName, m_RuleToResults[i].Results); + } + + /// + /// Converts our data to a serialized structure before a domain reload. + /// + public void OnBeforeSerialize() + { + m_RuleToResults.Clear(); + + foreach (var key in Data.Keys) + m_RuleToResults.Add(new RuleToResults(key, Data[key])); + } + + internal void Clear(AnalyzeRule rule) + { + Clear(rule.ruleName); + } + + internal void Clear(string ruleName) + { + if (Data.ContainsKey(ruleName)) + Data[ruleName].Clear(); + } + } +} diff --git a/Editor/Build/AnalyzeRules/AnalyzeResultData.cs.meta b/Editor/Build/AnalyzeRules/AnalyzeResultData.cs.meta index 82f8dfaa..0b487535 100644 --- a/Editor/Build/AnalyzeRules/AnalyzeResultData.cs.meta +++ b/Editor/Build/AnalyzeRules/AnalyzeResultData.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: abc77607c2a62ef48b8f7dec55cc6d91 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: abc77607c2a62ef48b8f7dec55cc6d91 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AnalyzeRules/AnalyzeRule.cs b/Editor/Build/AnalyzeRules/AnalyzeRule.cs index c956bbca..b76e12df 100644 --- a/Editor/Build/AnalyzeRules/AnalyzeRule.cs +++ b/Editor/Build/AnalyzeRules/AnalyzeRule.cs @@ -1,126 +1,126 @@ -using System; -using System.Collections.Generic; -using UnityEditor.AddressableAssets.Settings; -using UnityEngine; - -namespace UnityEditor.AddressableAssets.Build.AnalyzeRules -{ - /// - /// Base class for creating rules to analyze Addressables data. Use AnalyzeWindow.RegisterNewRule<T>() to register. - /// a rule with the GUI window. - /// - [Serializable] - public class AnalyzeRule - { - internal struct CustomContextMenu - { - public string MenuName; - public Action MenuAction; - public bool MenuEnabled; - public bool ToggledOn; - - public CustomContextMenu(string name, Action action, bool enabled, bool toggledOn) - { - MenuName = name; - MenuAction = action; - MenuEnabled = enabled; - ToggledOn = toggledOn; - } - } - - /// - /// True if this rule can fix itself. If child class sets this to true, class must override FixIssues - /// - public virtual bool CanFix { get; set; } - - [SerializeField] - internal List m_Results = new List(); - - /// - /// Represents a state where no errors were found after analyzing Addressables data. - /// - [NonSerialized] - protected AnalyzeResult noErrors = new AnalyzeResult {resultName = "No issues found"}; - - /// - /// Delimiter character used in analyze rule string names. This is used when a rule result needs to display - /// as a tree view hierarchy. A rule result of A:B:C will end up in the tree view with: - /// - A - /// --- B - /// ----- C - /// - public const char kDelimiter = ':'; - - /// - /// Result data returned by rules. - /// - [Serializable] - public class AnalyzeResult - { - [SerializeField] - string m_ResultName; - - /// - /// Name of result data. This name uses AnalyzeRule.kDelimiter to signify breaks in the tree display. - /// - public string resultName - { - get { return m_ResultName; } - set { m_ResultName = value; } - } - - [SerializeField] - MessageType m_Severity = MessageType.None; - - /// - /// Severity of rule result - /// - public MessageType severity - { - get { return m_Severity; } - set { m_Severity = value; } - } - } - - /// - /// Display name for rule - /// - public virtual string ruleName - { - get { return GetType().ToString(); } - } - - /// - /// This method runs the actual analysis for the rule. - /// - /// The settings object to analyze - /// A list of resulting information (warnings, errors, or info) - public virtual List RefreshAnalysis(AddressableAssetSettings settings) - { - return new List(); - } - - /// - /// Fixing method to be run on results of the RefreshAnalysis. If CanFix returns true, this method must be - /// overriden. It is recommended that RefreshAnalysis caches any data that will be needed to fix. Fix should - /// not rerun RefreshAnalysis before fixing. - /// - /// The settings object to analyze - public virtual void FixIssues(AddressableAssetSettings settings) - { - } - - /// - /// Clears out the analysis results. When overriding, use to clear rule-specific data as well. - /// - public virtual void ClearAnalysis() - { - m_Results.Clear(); - } - - internal virtual IList GetCustomContextMenuItems() - { - return new List(); - } - } -} +using System; +using System.Collections.Generic; +using UnityEditor.AddressableAssets.Settings; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build.AnalyzeRules +{ + /// + /// Base class for creating rules to analyze Addressables data. Use AnalyzeWindow.RegisterNewRule<T>() to register. + /// a rule with the GUI window. + /// + [Serializable] + public class AnalyzeRule + { + internal struct CustomContextMenu + { + public string MenuName; + public Action MenuAction; + public bool MenuEnabled; + public bool ToggledOn; + + public CustomContextMenu(string name, Action action, bool enabled, bool toggledOn) + { + MenuName = name; + MenuAction = action; + MenuEnabled = enabled; + ToggledOn = toggledOn; + } + } + + /// + /// True if this rule can fix itself. If child class sets this to true, class must override FixIssues + /// + public virtual bool CanFix { get; set; } + + [SerializeField] + internal List m_Results = new List(); + + /// + /// Represents a state where no errors were found after analyzing Addressables data. + /// + [NonSerialized] + protected AnalyzeResult noErrors = new AnalyzeResult {resultName = "No issues found"}; + + /// + /// Delimiter character used in analyze rule string names. This is used when a rule result needs to display + /// as a tree view hierarchy. A rule result of A:B:C will end up in the tree view with: + /// - A + /// --- B + /// ----- C + /// + public const char kDelimiter = ':'; + + /// + /// Result data returned by rules. + /// + [Serializable] + public class AnalyzeResult + { + [SerializeField] + string m_ResultName; + + /// + /// Name of result data. This name uses AnalyzeRule.kDelimiter to signify breaks in the tree display. + /// + public string resultName + { + get { return m_ResultName; } + set { m_ResultName = value; } + } + + [SerializeField] + MessageType m_Severity = MessageType.None; + + /// + /// Severity of rule result + /// + public MessageType severity + { + get { return m_Severity; } + set { m_Severity = value; } + } + } + + /// + /// Display name for rule + /// + public virtual string ruleName + { + get { return GetType().ToString(); } + } + + /// + /// This method runs the actual analysis for the rule. + /// + /// The settings object to analyze + /// A list of resulting information (warnings, errors, or info) + public virtual List RefreshAnalysis(AddressableAssetSettings settings) + { + return new List(); + } + + /// + /// Fixing method to be run on results of the RefreshAnalysis. If CanFix returns true, this method must be + /// overriden. It is recommended that RefreshAnalysis caches any data that will be needed to fix. Fix should + /// not rerun RefreshAnalysis before fixing. + /// + /// The settings object to analyze + public virtual void FixIssues(AddressableAssetSettings settings) + { + } + + /// + /// Clears out the analysis results. When overriding, use to clear rule-specific data as well. + /// + public virtual void ClearAnalysis() + { + m_Results.Clear(); + } + + internal virtual IList GetCustomContextMenuItems() + { + return new List(); + } + } +} diff --git a/Editor/Build/AnalyzeRules/AnalyzeRule.cs.meta b/Editor/Build/AnalyzeRules/AnalyzeRule.cs.meta index 12d80ace..800351db 100644 --- a/Editor/Build/AnalyzeRules/AnalyzeRule.cs.meta +++ b/Editor/Build/AnalyzeRules/AnalyzeRule.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: cfe8ad6aa7980734a89a782fcc937045 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: cfe8ad6aa7980734a89a782fcc937045 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AnalyzeRules/AnalyzeSystem.cs b/Editor/Build/AnalyzeRules/AnalyzeSystem.cs index 910a02e1..d7f6f8d0 100644 --- a/Editor/Build/AnalyzeRules/AnalyzeSystem.cs +++ b/Editor/Build/AnalyzeRules/AnalyzeSystem.cs @@ -1,229 +1,229 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEditor.AddressableAssets.Build.AnalyzeRules; -using UnityEditor.AddressableAssets.GUI; -using UnityEditor.AddressableAssets.Settings; -using UnityEngine; -using UnityEngine.AddressableAssets; - -namespace UnityEditor.AddressableAssets.Build -{ - /// - /// Static system to manage Analyze functionality. - /// - [Serializable] - public static class AnalyzeSystem - { - /// - /// Method used to register any custom AnalyzeRules with the AnalyzeSystem. This replaces calling into the AnalyzeWindow - /// directly to remove logic from the GUI. The recommended pattern is to create - /// your rules like so: - /// - /// class MyRule : AnalyzeRule {} - /// [InitializeOnLoad] - /// class RegisterMyRule - /// { - /// static RegisterMyRule() - /// { - /// AnalyzeSystem.RegisterNewRule<MyRule>(); - /// } - /// } - /// - /// - /// The rule type. - public static void RegisterNewRule() where TRule : AnalyzeRule, new() - { - foreach (var rule in Rules) - { - if (rule.GetType().Equals(typeof(TRule))) - return; - } - - Rules.Add(new TRule()); - } - - internal static string AnalyzeRuleDataFolder - { - get { return $"{Addressables.LibraryPath}/AnalyzeData"; } - } - - internal static string AnalyzeRuleDataName => "AnalyzeRuleData.json"; - internal static string AnalyzeRuleDataPath => AnalyzeRuleDataFolder + "/" + AnalyzeRuleDataName; - - internal static string AnalyzeRuleDataAssetsFolderPath - { - get - { - var settings = AddressableAssetSettingsDefaultObject.Settings; - var path = AddressableAssetSettingsDefaultObject.kDefaultConfigFolder; - if (settings != null && settings.IsPersisted) - path = settings.ConfigFolder; - - return path + "/AnalyzeData/"; - } - } - - internal static AddressableAssetSettings Settings => AddressableAssetSettingsDefaultObject.Settings; - - internal static List Rules { get; } = new List(); - - [SerializeField] - private static AddressablesAnalyzeResultData m_AnalyzeData; - - internal static AssetSettingsAnalyzeTreeView TreeView { get; set; } - - internal static AddressablesAnalyzeResultData AnalyzeData - { - get - { - if (m_AnalyzeData == null) - { - if (!Directory.Exists(AnalyzeRuleDataFolder)) - Directory.CreateDirectory(AnalyzeRuleDataFolder); - DeserializeData(); - } - - return m_AnalyzeData; - } - } - - internal static void ReloadUI() - { - TreeView?.Reload(); - } - - internal static void SerializeData() - { - SerializeData(AnalyzeRuleDataPath); - } - - internal static void DeserializeData() - { - DeserializeData(AnalyzeRuleDataPath); - } - - /// - /// Serialize the analysis data to json and save to disk - /// - /// File path to save to - public static void SerializeData(string path) - { - File.WriteAllText(path, JsonUtility.ToJson(m_AnalyzeData)); - } - - /// - /// Load and deserialize analysis data from json file and reload - /// - /// File path to load from - public static void DeserializeData(string path) - { - if (!File.Exists(path)) - File.WriteAllText(path, JsonUtility.ToJson(new AddressablesAnalyzeResultData())); - - //Cleans up the previous result data - if (Directory.Exists(AnalyzeRuleDataAssetsFolderPath)) - Directory.Delete(AnalyzeRuleDataAssetsFolderPath, true); - - m_AnalyzeData = JsonUtility.FromJson(File.ReadAllText(path)); - if (m_AnalyzeData == null) - Addressables.LogWarning($"Unable to load Analyze Result Data at {path}."); - else - { - if (m_AnalyzeData.Data == null) - m_AnalyzeData.Data = new Dictionary>(); - - foreach (var rule in Rules) - { - if (rule == null) - { - Addressables.LogWarning("An unknown Analyze rule is being skipped because it is null."); - continue; - } - - if (!m_AnalyzeData.Data.ContainsKey(rule.ruleName)) - m_AnalyzeData.Data.Add(rule.ruleName, new List()); - } - } - - ReloadUI(); - } - - internal static void SaveDataForRule(AnalyzeRule rule, object data) - { - string jsonData = JsonUtility.ToJson(data); - string path = $"{AnalyzeRuleDataFolder}/{rule.ruleName}Data.json"; - File.WriteAllText(path, jsonData); - } - - internal static T GetDataForRule(AnalyzeRule rule) - { - string path = $"{AnalyzeRuleDataFolder}/{rule.ruleName}Data.json"; - if (!File.Exists(path)) - return default; - string fileRead = File.ReadAllText(path); - return JsonUtility.FromJson(fileRead); - } - - internal static void ReplaceAnalyzeData(AnalyzeRule rule, List results) - { - m_AnalyzeData.Data[rule.ruleName] = results; - } - - internal static List RefreshAnalysis() where TRule : AnalyzeRule - { - return RefreshAnalysis(FindRule()); - } - - internal static List RefreshAnalysis(AnalyzeRule rule) - { - if (rule == null) - return null; - - if (!AnalyzeData.Data.ContainsKey(rule.ruleName)) - AnalyzeData.Data.Add(rule.ruleName, new List()); - - AnalyzeData.Data[rule.ruleName] = rule.RefreshAnalysis(Settings); - - return AnalyzeData.Data[rule.ruleName]; - } - - internal static void ClearAnalysis() where TRule : AnalyzeRule - { - ClearAnalysis(FindRule()); - } - - internal static void ClearAnalysis(AnalyzeRule rule) - { - if (rule == null) - return; - - if (!AnalyzeData.Data.ContainsKey(rule.ruleName)) - AnalyzeData.Data.Add(rule.ruleName, new List()); - - rule.ClearAnalysis(); - ; - AnalyzeData.Data[rule.ruleName].Clear(); - } - - internal static void FixIssues() where TRule : AnalyzeRule - { - FixIssues(FindRule()); - } - - internal static void FixIssues(AnalyzeRule rule) - { - rule?.FixIssues(Settings); - } - - private static AnalyzeRule FindRule() where TRule : AnalyzeRule - { - var rule = Rules.FirstOrDefault(r => r.GetType().IsAssignableFrom(typeof(TRule))); - if (rule == null) - throw new ArgumentException($"No rule found corresponding to type {typeof(TRule)}"); - - return rule; - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor.AddressableAssets.Build.AnalyzeRules; +using UnityEditor.AddressableAssets.GUI; +using UnityEditor.AddressableAssets.Settings; +using UnityEngine; +using UnityEngine.AddressableAssets; + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// Static system to manage Analyze functionality. + /// + [Serializable] + public static class AnalyzeSystem + { + /// + /// Method used to register any custom AnalyzeRules with the AnalyzeSystem. This replaces calling into the AnalyzeWindow + /// directly to remove logic from the GUI. The recommended pattern is to create + /// your rules like so: + /// + /// class MyRule : AnalyzeRule {} + /// [InitializeOnLoad] + /// class RegisterMyRule + /// { + /// static RegisterMyRule() + /// { + /// AnalyzeSystem.RegisterNewRule<MyRule>(); + /// } + /// } + /// + /// + /// The rule type. + public static void RegisterNewRule() where TRule : AnalyzeRule, new() + { + foreach (var rule in Rules) + { + if (rule.GetType().Equals(typeof(TRule))) + return; + } + + Rules.Add(new TRule()); + } + + internal static string AnalyzeRuleDataFolder + { + get { return $"{Addressables.LibraryPath}/AnalyzeData"; } + } + + internal static string AnalyzeRuleDataName => "AnalyzeRuleData.json"; + internal static string AnalyzeRuleDataPath => AnalyzeRuleDataFolder + "/" + AnalyzeRuleDataName; + + internal static string AnalyzeRuleDataAssetsFolderPath + { + get + { + var settings = AddressableAssetSettingsDefaultObject.Settings; + var path = AddressableAssetSettingsDefaultObject.kDefaultConfigFolder; + if (settings != null && settings.IsPersisted) + path = settings.ConfigFolder; + + return path + "/AnalyzeData/"; + } + } + + internal static AddressableAssetSettings Settings => AddressableAssetSettingsDefaultObject.Settings; + + internal static List Rules { get; } = new List(); + + [SerializeField] + private static AddressablesAnalyzeResultData m_AnalyzeData; + + internal static AssetSettingsAnalyzeTreeView TreeView { get; set; } + + internal static AddressablesAnalyzeResultData AnalyzeData + { + get + { + if (m_AnalyzeData == null) + { + if (!Directory.Exists(AnalyzeRuleDataFolder)) + Directory.CreateDirectory(AnalyzeRuleDataFolder); + DeserializeData(); + } + + return m_AnalyzeData; + } + } + + internal static void ReloadUI() + { + TreeView?.Reload(); + } + + internal static void SerializeData() + { + SerializeData(AnalyzeRuleDataPath); + } + + internal static void DeserializeData() + { + DeserializeData(AnalyzeRuleDataPath); + } + + /// + /// Serialize the analysis data to json and save to disk + /// + /// File path to save to + public static void SerializeData(string path) + { + File.WriteAllText(path, JsonUtility.ToJson(m_AnalyzeData)); + } + + /// + /// Load and deserialize analysis data from json file and reload + /// + /// File path to load from + public static void DeserializeData(string path) + { + if (!File.Exists(path)) + File.WriteAllText(path, JsonUtility.ToJson(new AddressablesAnalyzeResultData())); + + //Cleans up the previous result data + if (Directory.Exists(AnalyzeRuleDataAssetsFolderPath)) + Directory.Delete(AnalyzeRuleDataAssetsFolderPath, true); + + m_AnalyzeData = JsonUtility.FromJson(File.ReadAllText(path)); + if (m_AnalyzeData == null) + Addressables.LogWarning($"Unable to load Analyze Result Data at {path}."); + else + { + if (m_AnalyzeData.Data == null) + m_AnalyzeData.Data = new Dictionary>(); + + foreach (var rule in Rules) + { + if (rule == null) + { + Addressables.LogWarning("An unknown Analyze rule is being skipped because it is null."); + continue; + } + + if (!m_AnalyzeData.Data.ContainsKey(rule.ruleName)) + m_AnalyzeData.Data.Add(rule.ruleName, new List()); + } + } + + ReloadUI(); + } + + internal static void SaveDataForRule(AnalyzeRule rule, object data) + { + string jsonData = JsonUtility.ToJson(data); + string path = $"{AnalyzeRuleDataFolder}/{rule.ruleName}Data.json"; + File.WriteAllText(path, jsonData); + } + + internal static T GetDataForRule(AnalyzeRule rule) + { + string path = $"{AnalyzeRuleDataFolder}/{rule.ruleName}Data.json"; + if (!File.Exists(path)) + return default; + string fileRead = File.ReadAllText(path); + return JsonUtility.FromJson(fileRead); + } + + internal static void ReplaceAnalyzeData(AnalyzeRule rule, List results) + { + m_AnalyzeData.Data[rule.ruleName] = results; + } + + internal static List RefreshAnalysis() where TRule : AnalyzeRule + { + return RefreshAnalysis(FindRule()); + } + + internal static List RefreshAnalysis(AnalyzeRule rule) + { + if (rule == null) + return null; + + if (!AnalyzeData.Data.ContainsKey(rule.ruleName)) + AnalyzeData.Data.Add(rule.ruleName, new List()); + + AnalyzeData.Data[rule.ruleName] = rule.RefreshAnalysis(Settings); + + return AnalyzeData.Data[rule.ruleName]; + } + + internal static void ClearAnalysis() where TRule : AnalyzeRule + { + ClearAnalysis(FindRule()); + } + + internal static void ClearAnalysis(AnalyzeRule rule) + { + if (rule == null) + return; + + if (!AnalyzeData.Data.ContainsKey(rule.ruleName)) + AnalyzeData.Data.Add(rule.ruleName, new List()); + + rule.ClearAnalysis(); + ; + AnalyzeData.Data[rule.ruleName].Clear(); + } + + internal static void FixIssues() where TRule : AnalyzeRule + { + FixIssues(FindRule()); + } + + internal static void FixIssues(AnalyzeRule rule) + { + rule?.FixIssues(Settings); + } + + private static AnalyzeRule FindRule() where TRule : AnalyzeRule + { + var rule = Rules.FirstOrDefault(r => r.GetType().IsAssignableFrom(typeof(TRule))); + if (rule == null) + throw new ArgumentException($"No rule found corresponding to type {typeof(TRule)}"); + + return rule; + } + } +} diff --git a/Editor/Build/AnalyzeRules/AnalyzeSystem.cs.meta b/Editor/Build/AnalyzeRules/AnalyzeSystem.cs.meta index 9a10e6cb..a13f40d6 100644 --- a/Editor/Build/AnalyzeRules/AnalyzeSystem.cs.meta +++ b/Editor/Build/AnalyzeRules/AnalyzeSystem.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 6d97546331657044a99aed2e45ee76a2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 6d97546331657044a99aed2e45ee76a2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AnalyzeRules/BuildBundleLayout.cs b/Editor/Build/AnalyzeRules/BuildBundleLayout.cs index eb2b0b19..090aaeb5 100644 --- a/Editor/Build/AnalyzeRules/BuildBundleLayout.cs +++ b/Editor/Build/AnalyzeRules/BuildBundleLayout.cs @@ -1,139 +1,139 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.SceneManagement; -using UnityEngine; - -namespace UnityEditor.AddressableAssets.Build.AnalyzeRules -{ - class BuildBundleLayout : BundleRuleBase - { - /// - /// Result data for assets included in the bundle layout - /// - protected internal struct BuildBundleLayoutResultData - { - public string AssetBundleName; - public string AssetPath; - public bool Explicit; - } - - /// - public override bool CanFix - { - get { return false; } - } - - /// - public override string ruleName - { - get { return "Bundle Layout Preview"; } - } - - private List m_ResultData = null; - - /// - /// Results of the build Layout. - /// - protected IEnumerable BuildBundleLayoutResults - { - get - { - if (m_ResultData == null) - { - if (ExtractData == null) - { - Debug.LogError("RefreshAnalysis needs to be called before getting results"); - return new List(0); - } - - m_ResultData = new List(512); - - foreach (var bundleBuild in AllBundleInputDefs) - { - foreach (string assetName in bundleBuild.assetNames) - { - m_ResultData.Add(new BuildBundleLayoutResultData() - { - AssetBundleName = bundleBuild.assetBundleName, - AssetPath = assetName, - Explicit = true - }); - } - } - - List assets = new List(); - foreach (KeyValuePair fileToBundle in ExtractData.WriteData.FileToBundle) - { - assets.Clear(); - string assetBundleName = fileToBundle.Value; - - var implicitGuids = GetImplicitGuidsForBundle(fileToBundle.Key); - foreach (GUID guid in implicitGuids) - { - string assetPath = AssetDatabase.GUIDToAssetPath(guid.ToString()); - if (AddressableAssetUtility.IsPathValidForEntry(assetPath)) - m_ResultData.Add(new BuildBundleLayoutResultData() - { - AssetBundleName = assetBundleName, - AssetPath = assetPath, - Explicit = false - }); - } - } - } - - return m_ResultData; - } - } - - /// - public override List RefreshAnalysis(AddressableAssetSettings settings) - { - ClearAnalysis(); - - if (!BuildUtility.CheckModifiedScenesAndAskToSave()) - { - Debug.LogError("Cannot run Analyze with unsaved scenes"); - m_Results.Add(new AnalyzeResult {resultName = ruleName + "Cannot run Analyze with unsaved scenes"}); - return m_Results; - } - - CalculateInputDefinitions(settings); - var context = GetBuildContext(settings); - RefreshBuild(context); - ConvertBundleNamesToGroupNames(context); - foreach (BuildBundleLayoutResultData result in BuildBundleLayoutResults) - { - m_Results.Add(new AnalyzeResult - { - resultName = result.AssetBundleName + kDelimiter - + (result.Explicit ? "Explicit" : "Implicit") + kDelimiter + result.AssetPath - }); - } - - if (m_Results.Count == 0) - m_Results.Add(noErrors); - - AddressableAnalytics.ReportUsageEvent(AddressableAnalytics.UsageEventType.RunBundleLayoutPreviewRule); - return m_Results; - } - - /// - public override void ClearAnalysis() - { - m_ResultData = null; - base.ClearAnalysis(); - } - - [InitializeOnLoad] - class RegisterBuildBundleLayout - { - static RegisterBuildBundleLayout() - { - AnalyzeSystem.RegisterNewRule(); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.SceneManagement; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build.AnalyzeRules +{ + class BuildBundleLayout : BundleRuleBase + { + /// + /// Result data for assets included in the bundle layout + /// + protected internal struct BuildBundleLayoutResultData + { + public string AssetBundleName; + public string AssetPath; + public bool Explicit; + } + + /// + public override bool CanFix + { + get { return false; } + } + + /// + public override string ruleName + { + get { return "Bundle Layout Preview"; } + } + + private List m_ResultData = null; + + /// + /// Results of the build Layout. + /// + protected IEnumerable BuildBundleLayoutResults + { + get + { + if (m_ResultData == null) + { + if (ExtractData == null) + { + Debug.LogError("RefreshAnalysis needs to be called before getting results"); + return new List(0); + } + + m_ResultData = new List(512); + + foreach (var bundleBuild in AllBundleInputDefs) + { + foreach (string assetName in bundleBuild.assetNames) + { + m_ResultData.Add(new BuildBundleLayoutResultData() + { + AssetBundleName = bundleBuild.assetBundleName, + AssetPath = assetName, + Explicit = true + }); + } + } + + List assets = new List(); + foreach (KeyValuePair fileToBundle in ExtractData.WriteData.FileToBundle) + { + assets.Clear(); + string assetBundleName = fileToBundle.Value; + + var implicitGuids = GetImplicitGuidsForBundle(fileToBundle.Key); + foreach (GUID guid in implicitGuids) + { + string assetPath = AssetDatabase.GUIDToAssetPath(guid.ToString()); + if (AddressableAssetUtility.IsPathValidForEntry(assetPath)) + m_ResultData.Add(new BuildBundleLayoutResultData() + { + AssetBundleName = assetBundleName, + AssetPath = assetPath, + Explicit = false + }); + } + } + } + + return m_ResultData; + } + } + + /// + public override List RefreshAnalysis(AddressableAssetSettings settings) + { + ClearAnalysis(); + + if (!BuildUtility.CheckModifiedScenesAndAskToSave()) + { + Debug.LogError("Cannot run Analyze with unsaved scenes"); + m_Results.Add(new AnalyzeResult {resultName = ruleName + "Cannot run Analyze with unsaved scenes"}); + return m_Results; + } + + CalculateInputDefinitions(settings); + var context = GetBuildContext(settings); + RefreshBuild(context); + ConvertBundleNamesToGroupNames(context); + foreach (BuildBundleLayoutResultData result in BuildBundleLayoutResults) + { + m_Results.Add(new AnalyzeResult + { + resultName = result.AssetBundleName + kDelimiter + + (result.Explicit ? "Explicit" : "Implicit") + kDelimiter + result.AssetPath + }); + } + + if (m_Results.Count == 0) + m_Results.Add(noErrors); + + AddressableAnalytics.ReportUsageEvent(AddressableAnalytics.UsageEventType.RunBundleLayoutPreviewRule); + return m_Results; + } + + /// + public override void ClearAnalysis() + { + m_ResultData = null; + base.ClearAnalysis(); + } + + [InitializeOnLoad] + class RegisterBuildBundleLayout + { + static RegisterBuildBundleLayout() + { + AnalyzeSystem.RegisterNewRule(); + } + } + } +} diff --git a/Editor/Build/AnalyzeRules/BuildBundleLayout.cs.meta b/Editor/Build/AnalyzeRules/BuildBundleLayout.cs.meta index 48264f59..fe01836d 100644 --- a/Editor/Build/AnalyzeRules/BuildBundleLayout.cs.meta +++ b/Editor/Build/AnalyzeRules/BuildBundleLayout.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: d314656232cf1b24a9d7e6470f8f72eb -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: d314656232cf1b24a9d7e6470f8f72eb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AnalyzeRules/BundleRuleBase.cs b/Editor/Build/AnalyzeRules/BundleRuleBase.cs index c03b3a62..ced0155f 100644 --- a/Editor/Build/AnalyzeRules/BundleRuleBase.cs +++ b/Editor/Build/AnalyzeRules/BundleRuleBase.cs @@ -1,677 +1,677 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEditor.AddressableAssets.Build.BuildPipelineTasks; -using UnityEditor.AddressableAssets.Build.DataBuilders; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.AddressableAssets.Settings.GroupSchemas; -using UnityEditor.Build.Content; -using UnityEditor.Build.Pipeline; -using UnityEditor.Build.Pipeline.Interfaces; -using UnityEditor.Build.Pipeline.Tasks; -using UnityEditor.Build.Pipeline.Utilities; -using UnityEditor.SceneManagement; -using UnityEngine; -using UnityEngine.AddressableAssets.Initialization; -using UnityEngine.AddressableAssets.ResourceLocators; - -namespace UnityEditor.AddressableAssets.Build.AnalyzeRules -{ - /// - /// Base class for handling analyzing bundle rules tasks and checking dependencies - /// - public class BundleRuleBase : AnalyzeRule - { - [NonSerialized] - internal Dictionary> m_ResourcesToDependencies = new Dictionary>(); - - [NonSerialized] - internal readonly List m_Locations = new List(); - - [NonSerialized] - internal readonly List m_AllBundleInputDefs = new List(); - - [NonSerialized] - internal readonly Dictionary m_BundleToAssetGroup = new Dictionary(); - - [NonSerialized] - internal List m_AssetEntries = new List(); - - [NonSerialized] - internal ExtractDataTask m_ExtractData = null; - - /// - /// The BuildTask used to extract write data from the build. - /// - protected ExtractDataTask ExtractData => m_ExtractData; - /// - /// A mapping of resources to a list of guids that correspond to their dependencies - /// - protected Dictionary> ResourcesToDependencies => m_ResourcesToDependencies; - protected internal List AllBundleInputDefs => m_AllBundleInputDefs; - - internal IList RuntimeDataBuildTasks(string builtinShaderBundleName) - { - IList buildTasks = new List(); - - // Setup - buildTasks.Add(new SwitchToBuildPlatform()); - buildTasks.Add(new RebuildSpriteAtlasCache()); - - // Player Scripts - buildTasks.Add(new BuildPlayerScripts()); - - // Dependency - buildTasks.Add(new CalculateSceneDependencyData()); - buildTasks.Add(new CalculateAssetDependencyData()); - buildTasks.Add(new StripUnusedSpriteSources()); - buildTasks.Add(new CreateBuiltInShadersBundle(builtinShaderBundleName)); - - // Packing - buildTasks.Add(new GenerateBundlePacking()); - buildTasks.Add(new UpdateBundleObjectLayout()); - - buildTasks.Add(new GenerateBundleCommands()); - buildTasks.Add(new GenerateSubAssetPathMaps()); - buildTasks.Add(new GenerateBundleMaps()); - - buildTasks.Add(new GenerateLocationListsTask()); - - return buildTasks; - } - - /// - /// Get context for current Addressables settings - /// - /// The current Addressables settings object - /// The build context information - protected internal AddressableAssetsBuildContext GetBuildContext(AddressableAssetSettings settings) - { - ResourceManagerRuntimeData runtimeData = new ResourceManagerRuntimeData(); - runtimeData.LogResourceManagerExceptions = settings.buildSettings.LogResourceManagerExceptions; - - var aaContext = new AddressableAssetsBuildContext - { - Settings = settings, - runtimeData = runtimeData, - bundleToAssetGroup = m_BundleToAssetGroup, - locations = m_Locations, - providerTypes = new HashSet(), - assetEntries = m_AssetEntries, - assetGroupToBundles = new Dictionary>() - }; - return aaContext; - } - - /// - /// Check path is valid path for Addressables entry - /// - /// The path to check - /// Whether path is valid - protected bool IsValidPath(string path) - { - return AddressableAssetUtility.IsPathValidForEntry(path) && - !AddressableAssetUtility.StringContains(path, "/Resources/", StringComparison.OrdinalIgnoreCase); - } - - /// - /// Refresh build to check bundles against current rules - /// - /// Context information for building - /// The return code of whether analyze build was successful, - protected internal ReturnCode RefreshBuild(AddressableAssetsBuildContext buildContext) - { - var settings = buildContext.Settings; - var context = new AddressablesDataBuilderInput(settings); - - var buildTarget = context.Target; - var buildTargetGroup = context.TargetGroup; - var buildParams = new AddressableAssetsBundleBuildParameters(settings, m_BundleToAssetGroup, buildTarget, - buildTargetGroup, settings.buildSettings.bundleBuildPath); - var builtinShaderBundleName = - settings.DefaultGroup.Name.ToLower().Replace(" ", "").Replace('\\', '/').Replace("//", "/") + - "_unitybuiltinshaders.bundle"; - var buildTasks = RuntimeDataBuildTasks(builtinShaderBundleName); - m_ExtractData = new ExtractDataTask(); - buildTasks.Add(m_ExtractData); - - IBundleBuildResults buildResults; - var exitCode = ContentPipeline.BuildAssetBundles(buildParams, new BundleBuildContent(m_AllBundleInputDefs), - out buildResults, buildTasks, buildContext); - - return exitCode; - } - - /// - /// Get dependencies from bundles - /// - /// The list of GUIDs of bundle dependencies - protected List GetAllBundleDependencies() - { - if (m_ExtractData == null) - { - Debug.LogError("Build not run, RefreshBuild needed before GetAllBundleDependencies"); - return new List(); - } - - var explicitGuids = m_ExtractData.WriteData.AssetToFiles.Keys; - var implicitGuids = GetImplicitGuidToFilesMap().Keys; - var allBundleGuids = explicitGuids.Union(implicitGuids); - - return allBundleGuids.ToList(); - } - - /// - /// Add Resource and Bundle dependencies in common to map of resources to dependencies - /// - /// GUID list of bundle dependencies - protected internal void IntersectResourcesDepedenciesWithBundleDependencies(List bundleDependencyGuids) - { - foreach (var key in m_ResourcesToDependencies.Keys) - { - var bundleDependencies = bundleDependencyGuids.Intersect(m_ResourcesToDependencies[key]).ToList(); - - m_ResourcesToDependencies[key].Clear(); - m_ResourcesToDependencies[key].AddRange(bundleDependencies); - } - } - - /// - /// Build map of resources to corresponding dependencies - /// - /// Array of resource paths - protected internal virtual void BuiltInResourcesToDependenciesMap(string[] resourcePaths) - { - for (int sceneIndex = 0; sceneIndex < resourcePaths.Length; ++sceneIndex) - { - string path = resourcePaths[sceneIndex]; - if (EditorUtility.DisplayCancelableProgressBar("Generating built-in resource dependency map", - "Checking " + path + " for duplicates with Addressables content.", - (float)sceneIndex / resourcePaths.Length)) - { - m_ResourcesToDependencies.Clear(); - EditorUtility.ClearProgressBar(); - return; - } - - string[] dependencies; - if (path.EndsWith(".unity", StringComparison.OrdinalIgnoreCase)) - { - using (var w = new BuildInterfacesWrapper()) - { - var usageTags = new BuildUsageTagSet(); - BuildSettings settings = new BuildSettings - { - group = EditorUserBuildSettings.selectedBuildTargetGroup, - target = EditorUserBuildSettings.activeBuildTarget, - typeDB = null, - buildFlags = ContentBuildFlags.None - }; - - SceneDependencyInfo sceneInfo = - ContentBuildInterface.CalculatePlayerDependenciesForScene(path, settings, usageTags); - dependencies = new string[sceneInfo.referencedObjects.Count]; - for (int i = 0; i < sceneInfo.referencedObjects.Count; ++i) - { - if (string.IsNullOrEmpty(sceneInfo.referencedObjects[i].filePath)) - dependencies[i] = AssetDatabase.GUIDToAssetPath(sceneInfo.referencedObjects[i].guid.ToString()); - else - dependencies[i] = sceneInfo.referencedObjects[i].filePath; - } - } - } - else - dependencies = AssetDatabase.GetDependencies(path); - - if (!m_ResourcesToDependencies.ContainsKey(path)) - m_ResourcesToDependencies.Add(path, new List(dependencies.Length)); - else - m_ResourcesToDependencies[path].Capacity += dependencies.Length; - - foreach (string dependency in dependencies) - { - if (dependency.EndsWith(".cs", StringComparison.OrdinalIgnoreCase) || dependency.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) - continue; - m_ResourcesToDependencies[path].Add(new GUID(AssetDatabase.AssetPathToGUID(dependency))); - } - } - - EditorUtility.ClearProgressBar(); - } - - /// - /// Use bundle names to create group names for AssetBundleBuild - /// - /// Context information for building - protected internal void ConvertBundleNamesToGroupNames(AddressableAssetsBuildContext buildContext) - { - if (m_ExtractData == null) - { - Debug.LogError("Build not run, RefreshBuild needed before ConvertBundleNamesToGroupNames"); - return; - } - - Dictionary bundleNamesToUpdate = new Dictionary(); - - foreach (var assetGroup in buildContext.Settings.groups) - { - if (assetGroup == null) - continue; - - List bundles; - if (buildContext.assetGroupToBundles.TryGetValue(assetGroup, out bundles)) - { - foreach (string bundle in bundles) - { - var keys = m_ExtractData.WriteData.FileToBundle.Keys.Where(key => m_ExtractData.WriteData.FileToBundle[key] == bundle); - foreach (string key in keys) - bundleNamesToUpdate.Add(key, assetGroup.Name); - } - } - } - - foreach (string key in bundleNamesToUpdate.Keys) - { - var bundleName = m_ExtractData.WriteData.FileToBundle[key]; - string convertedName = ConvertBundleName(bundleName, bundleNamesToUpdate[key]); - if (m_ExtractData.WriteData.FileToBundle.ContainsKey(key)) - m_ExtractData.WriteData.FileToBundle[key] = convertedName; - for (int i = 0; i < m_AllBundleInputDefs.Count; ++i) - { - if (m_AllBundleInputDefs[i].assetBundleName == bundleName) - { - var input = m_AllBundleInputDefs[i]; - input.assetBundleName = convertedName; - m_AllBundleInputDefs[i] = input; - break; - } - } - } - } - - /// - /// Generate input definitions and entries for AssetBundleBuild - /// - /// The current Addressables settings object - protected internal void CalculateInputDefinitions(AddressableAssetSettings settings) - { - int updateFrequency = Mathf.Max(settings.groups.Count / 10, 1); - bool progressDisplayed = false; - for (int groupIndex = 0; groupIndex < settings.groups.Count; ++groupIndex) - { - AddressableAssetGroup group = settings.groups[groupIndex]; - if (group == null) - continue; - if (!progressDisplayed || groupIndex % updateFrequency == 0) - { - progressDisplayed = true; - if (EditorUtility.DisplayCancelableProgressBar("Calculating Input Definitions", "", - (float)groupIndex / settings.groups.Count)) - { - m_AssetEntries.Clear(); - m_BundleToAssetGroup.Clear(); - m_AllBundleInputDefs.Clear(); - break; - } - } - - var schema = group.GetSchema(); - if (schema != null && schema.IncludeInBuild) - { - List bundleInputDefinitions = new List(); - m_AssetEntries.AddRange(BuildScriptPackedMode.PrepGroupBundlePacking(group, bundleInputDefinitions, schema)); - - for (int i = 0; i < bundleInputDefinitions.Count; i++) - { - if (m_BundleToAssetGroup.ContainsKey(bundleInputDefinitions[i].assetBundleName)) - bundleInputDefinitions[i] = CreateUniqueBundle(bundleInputDefinitions[i]); - - m_BundleToAssetGroup.Add(bundleInputDefinitions[i].assetBundleName, schema.Group.Guid); - } - - m_AllBundleInputDefs.AddRange(bundleInputDefinitions); - } - } - - if (progressDisplayed) - EditorUtility.ClearProgressBar(); - } - - internal AssetBundleBuild CreateUniqueBundle(AssetBundleBuild bid) - { - return CreateUniqueBundle(bid, m_BundleToAssetGroup); - } - - /// - /// Create new AssetBundleBuild - /// - /// ID for new AssetBundleBuild - /// Map of bundle names to asset group Guids - /// - protected internal static AssetBundleBuild CreateUniqueBundle(AssetBundleBuild bid, Dictionary bundleToAssetGroup) - { - int count = 1; - var newName = bid.assetBundleName; - while (bundleToAssetGroup.ContainsKey(newName) && count < 1000) - newName = bid.assetBundleName.Replace(".bundle", string.Format("{0}.bundle", count++)); - return new AssetBundleBuild - { - assetBundleName = newName, - addressableNames = bid.addressableNames, - assetBundleVariant = bid.assetBundleVariant, - assetNames = bid.assetNames - }; - } - - /// - /// Get bundle's object ids that have no dependency file - /// - /// Name of bundle file - /// List of GUIDS of objects in bundle with no dependency file - protected List GetImplicitGuidsForBundle(string fileName) - { - if (m_ExtractData == null) - { - Debug.LogError("Build not run, RefreshBuild needed before GetImplicitGuidsForBundle"); - return new List(); - } - - List guids = (from id in m_ExtractData.WriteData.FileToObjects[fileName] - where !m_ExtractData.WriteData.AssetToFiles.Keys.Contains(id.guid) - select id.guid).ToList(); - return guids; - } - - /// - /// Build map of implicit guids to their bundle files - /// - /// Dictionary of implicit guids to their corresponding file - protected internal Dictionary> GetImplicitGuidToFilesMap() - { - if (m_ExtractData == null) - { - Debug.LogError("Build not run, RefreshBuild needed before GetImplicitGuidToFilesMap"); - return new Dictionary>(); - } - - Dictionary> implicitGuids = new Dictionary>(); - IEnumerable> validImplicitGuids = - from fileToObject in m_ExtractData.WriteData.FileToObjects - from objectId in fileToObject.Value - where !m_ExtractData.WriteData.AssetToFiles.Keys.Contains(objectId.guid) - select new KeyValuePair(objectId, fileToObject.Key); - - //Build our Dictionary from our list of valid implicit guids (guids not already in explicit guids) - foreach (var objectIdToFile in validImplicitGuids) - { - if (!implicitGuids.ContainsKey(objectIdToFile.Key.guid)) - implicitGuids.Add(objectIdToFile.Key.guid, new List()); - implicitGuids[objectIdToFile.Key.guid].Add(objectIdToFile.Value); - } - - return implicitGuids; - } - - /// - /// Calculate built in resources and corresponding bundle dependencies - /// - /// The current Addressables settings object - /// Array of resource paths - /// List of rule results after calculating resource and bundle dependency combined - protected List CalculateBuiltInResourceDependenciesToBundleDependecies(AddressableAssetSettings settings, string[] builtInResourcesPaths) - { - List results = new List(); - - if (!BuildUtility.CheckModifiedScenesAndAskToSave()) - { - Debug.LogError("Cannot run Analyze with unsaved scenes"); - results.Add(new AnalyzeResult {resultName = ruleName + "Cannot run Analyze with unsaved scenes"}); - return results; - } - - EditorUtility.DisplayProgressBar("Calculating Built-in dependencies", "Calculating dependencies between Built-in resources and Addressables", 0); - try - { - // bulk of work and progress bars displayed in these methods - var buildSuccess = BuildAndGetResourceDependencies(settings, builtInResourcesPaths); - if (buildSuccess != ReturnCode.Success) - { - if (buildSuccess == ReturnCode.SuccessNotRun) - { - results.Add(new AnalyzeResult {resultName = ruleName + " - No issues found."}); - return results; - } - - results.Add(new AnalyzeResult {resultName = ruleName + "Analyze build failed. " + buildSuccess}); - return results; - } - } - finally - { - EditorUtility.ClearProgressBar(); - } - - results = (from resource in m_ResourcesToDependencies.Keys - from dependency in m_ResourcesToDependencies[resource] - let assetPath = AssetDatabase.GUIDToAssetPath(dependency.ToString()) - let files = m_ExtractData.WriteData.FileToObjects.Keys - from file in files - where m_ExtractData.WriteData.FileToObjects[file].Any(oid => oid.guid == dependency) - where m_ExtractData.WriteData.FileToBundle.ContainsKey(file) - let bundle = m_ExtractData.WriteData.FileToBundle[file] - select new AnalyzeResult - { - resultName = - resource + kDelimiter + - bundle + kDelimiter + - assetPath, - severity = MessageType.Warning - }).ToList(); - - if (results.Count == 0) - results.Add(new AnalyzeResult {resultName = ruleName + " - No issues found."}); - - return results; - } - - /// - /// Calculates and gathers dependencies for built in data. - /// - /// The AddressableAssetSettings to pull data from. - /// The paths that lead to all the built in Resource locations - /// A ReturnCode indicating various levels of success or failure. - protected ReturnCode BuildAndGetResourceDependencies(AddressableAssetSettings settings, string[] builtInResourcesPaths) - { - BuiltInResourcesToDependenciesMap(builtInResourcesPaths); - if (m_ResourcesToDependencies == null || m_ResourcesToDependencies.Count == 0) - return ReturnCode.SuccessNotRun; - - CalculateInputDefinitions(settings); - if (m_AllBundleInputDefs == null || m_AllBundleInputDefs.Count == 0) - return ReturnCode.SuccessNotRun; - - EditorUtility.DisplayProgressBar("Calculating Built-in dependencies", - "Calculating dependencies between Built-in resources and Addressables", 0.5f); - - ReturnCode exitCode = ReturnCode.Error; - var context = GetBuildContext(settings); - exitCode = RefreshBuild(context); - if (exitCode < ReturnCode.Success) - { - EditorUtility.ClearProgressBar(); - return exitCode; - } - - EditorUtility.DisplayProgressBar("Calculating Built-in dependencies", - "Calculating dependencies between Built-in resources and Addressables", 0.9f); - IntersectResourcesDepedenciesWithBundleDependencies(GetAllBundleDependencies()); - ConvertBundleNamesToGroupNames(context); - - return exitCode; - } - - /// - /// Convert bundle name to include group name - /// - /// Current bundle name - /// Group name of bundle's group - /// The new bundle name - protected string ConvertBundleName(string bundleName, string groupName) - { - string[] bundleNameSegments = bundleName.Split('_'); - bundleNameSegments[0] = groupName.Replace(" ", "").ToLower(); - return string.Join("_", bundleNameSegments); - } - - /// - /// Clear all previously gathered bundle data and analysis - /// - public override void ClearAnalysis() - { - m_Locations.Clear(); - m_AssetEntries.Clear(); - m_AllBundleInputDefs.Clear(); - m_BundleToAssetGroup.Clear(); - m_ResourcesToDependencies.Clear(); - m_ResultData = null; - m_ExtractData = null; - - base.ClearAnalysis(); - } - - /// - /// Data object for results of resource based analysis rules - /// - protected internal struct ResultData - { - public string ResourcePath; - public string AssetBundleName; - public string AssetPath; - } - - /// - public override bool CanFix - { - get { return false; } - } - - private List m_ResultData = null; - - /// - /// Duplicate Results between Addressables and Player content. - /// - protected IEnumerable Results - { - get - { - if (m_ResultData == null) - { - if (ExtractData == null) - { - Debug.LogError("RefreshAnalysis needs to be called before getting results"); - return new List(0); - } - - m_ResultData = new List(512); - - foreach (string resource in ResourcesToDependencies.Keys) - { - var dependencies = ResourcesToDependencies[resource]; - foreach (GUID dependency in dependencies) - { - string assetPath = AssetDatabase.GUIDToAssetPath(dependency.ToString()); - var files = ExtractData.WriteData.FileToObjects.Keys; - foreach (string file in files) - { - if (m_ExtractData.WriteData.FileToObjects[file].Any(oid => oid.guid == dependency) && - m_ExtractData.WriteData.FileToBundle.ContainsKey(file)) - { - string assetBundleName = ExtractData.WriteData.FileToBundle[file]; - m_ResultData.Add(new ResultData() - { - AssetBundleName = assetBundleName, - AssetPath = assetPath, - ResourcePath = resource - }); - } - } - } - } - } - - return m_ResultData; - } - } - - /// - /// Clear analysis and calculate built in content and corresponding bundle dependencies - /// - /// The current Addressables settings object - /// List of results from analysis - public override List RefreshAnalysis(AddressableAssetSettings settings) - { - ClearAnalysis(); - List results = new List(); - - if (!BuildUtility.CheckModifiedScenesAndAskToSave()) - { - Debug.LogError("Cannot run Analyze with unsaved scenes"); - results.Add(new AnalyzeResult {resultName = ruleName + "Cannot run Analyze with unsaved scenes"}); - return results; - } - - EditorUtility.DisplayProgressBar("Calculating Built-in dependencies", "Calculating dependencies between Resources and Addressables", 0); - try - { - // bulk of work and progress bars displayed in these methods - string[] resourcePaths = GetResourcePaths(); - - var buildSuccess = BuildAndGetResourceDependencies(settings, resourcePaths); - if (buildSuccess == ReturnCode.SuccessNotRun) - { - results.Add(new AnalyzeResult {resultName = ruleName + " - No issues found."}); - return results; - } - - if (buildSuccess != ReturnCode.Success) - { - results.Add(new AnalyzeResult {resultName = ruleName + "Analyze build failed. " + buildSuccess}); - return results; - } - } - finally - { - EditorUtility.ClearProgressBar(); - } - - foreach (ResultData result in Results) - { - results.Add(new AnalyzeResult() - { - resultName = - result.ResourcePath + kDelimiter + - result.AssetBundleName + kDelimiter + - result.AssetPath, - severity = MessageType.Warning - }); - } - - return results; - } - - /// - /// Gets an array of resource paths that are to be compared against the addressables build content - /// - /// Array of Resource paths to compare against - internal protected virtual string[] GetResourcePaths() - { - return new string[0]; - } - - /// - public override void FixIssues(AddressableAssetSettings settings) - { - //Do nothing. There's nothing to fix. - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.AddressableAssets.Build.BuildPipelineTasks; +using UnityEditor.AddressableAssets.Build.DataBuilders; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEditor.Build.Content; +using UnityEditor.Build.Pipeline; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEditor.Build.Pipeline.Tasks; +using UnityEditor.Build.Pipeline.Utilities; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.AddressableAssets.Initialization; +using UnityEngine.AddressableAssets.ResourceLocators; + +namespace UnityEditor.AddressableAssets.Build.AnalyzeRules +{ + /// + /// Base class for handling analyzing bundle rules tasks and checking dependencies + /// + public class BundleRuleBase : AnalyzeRule + { + [NonSerialized] + internal Dictionary> m_ResourcesToDependencies = new Dictionary>(); + + [NonSerialized] + internal readonly List m_Locations = new List(); + + [NonSerialized] + internal readonly List m_AllBundleInputDefs = new List(); + + [NonSerialized] + internal readonly Dictionary m_BundleToAssetGroup = new Dictionary(); + + [NonSerialized] + internal List m_AssetEntries = new List(); + + [NonSerialized] + internal ExtractDataTask m_ExtractData = null; + + /// + /// The BuildTask used to extract write data from the build. + /// + protected ExtractDataTask ExtractData => m_ExtractData; + /// + /// A mapping of resources to a list of guids that correspond to their dependencies + /// + protected Dictionary> ResourcesToDependencies => m_ResourcesToDependencies; + protected internal List AllBundleInputDefs => m_AllBundleInputDefs; + + internal IList RuntimeDataBuildTasks(string builtinShaderBundleName) + { + IList buildTasks = new List(); + + // Setup + buildTasks.Add(new SwitchToBuildPlatform()); + buildTasks.Add(new RebuildSpriteAtlasCache()); + + // Player Scripts + buildTasks.Add(new BuildPlayerScripts()); + + // Dependency + buildTasks.Add(new CalculateSceneDependencyData()); + buildTasks.Add(new CalculateAssetDependencyData()); + buildTasks.Add(new StripUnusedSpriteSources()); + buildTasks.Add(new CreateBuiltInShadersBundle(builtinShaderBundleName)); + + // Packing + buildTasks.Add(new GenerateBundlePacking()); + buildTasks.Add(new UpdateBundleObjectLayout()); + + buildTasks.Add(new GenerateBundleCommands()); + buildTasks.Add(new GenerateSubAssetPathMaps()); + buildTasks.Add(new GenerateBundleMaps()); + + buildTasks.Add(new GenerateLocationListsTask()); + + return buildTasks; + } + + /// + /// Get context for current Addressables settings + /// + /// The current Addressables settings object + /// The build context information + protected internal AddressableAssetsBuildContext GetBuildContext(AddressableAssetSettings settings) + { + ResourceManagerRuntimeData runtimeData = new ResourceManagerRuntimeData(); + runtimeData.LogResourceManagerExceptions = settings.buildSettings.LogResourceManagerExceptions; + + var aaContext = new AddressableAssetsBuildContext + { + Settings = settings, + runtimeData = runtimeData, + bundleToAssetGroup = m_BundleToAssetGroup, + locations = m_Locations, + providerTypes = new HashSet(), + assetEntries = m_AssetEntries, + assetGroupToBundles = new Dictionary>() + }; + return aaContext; + } + + /// + /// Check path is valid path for Addressables entry + /// + /// The path to check + /// Whether path is valid + protected bool IsValidPath(string path) + { + return AddressableAssetUtility.IsPathValidForEntry(path) && + !AddressableAssetUtility.StringContains(path, "/Resources/", StringComparison.OrdinalIgnoreCase); + } + + /// + /// Refresh build to check bundles against current rules + /// + /// Context information for building + /// The return code of whether analyze build was successful, + protected internal ReturnCode RefreshBuild(AddressableAssetsBuildContext buildContext) + { + var settings = buildContext.Settings; + var context = new AddressablesDataBuilderInput(settings); + + var buildTarget = context.Target; + var buildTargetGroup = context.TargetGroup; + var buildParams = new AddressableAssetsBundleBuildParameters(settings, m_BundleToAssetGroup, buildTarget, + buildTargetGroup, settings.buildSettings.bundleBuildPath); + var builtinShaderBundleName = + settings.DefaultGroup.Name.ToLower().Replace(" ", "").Replace('\\', '/').Replace("//", "/") + + "_unitybuiltinshaders.bundle"; + var buildTasks = RuntimeDataBuildTasks(builtinShaderBundleName); + m_ExtractData = new ExtractDataTask(); + buildTasks.Add(m_ExtractData); + + IBundleBuildResults buildResults; + var exitCode = ContentPipeline.BuildAssetBundles(buildParams, new BundleBuildContent(m_AllBundleInputDefs), + out buildResults, buildTasks, buildContext); + + return exitCode; + } + + /// + /// Get dependencies from bundles + /// + /// The list of GUIDs of bundle dependencies + protected List GetAllBundleDependencies() + { + if (m_ExtractData == null) + { + Debug.LogError("Build not run, RefreshBuild needed before GetAllBundleDependencies"); + return new List(); + } + + var explicitGuids = m_ExtractData.WriteData.AssetToFiles.Keys; + var implicitGuids = GetImplicitGuidToFilesMap().Keys; + var allBundleGuids = explicitGuids.Union(implicitGuids); + + return allBundleGuids.ToList(); + } + + /// + /// Add Resource and Bundle dependencies in common to map of resources to dependencies + /// + /// GUID list of bundle dependencies + protected internal void IntersectResourcesDepedenciesWithBundleDependencies(List bundleDependencyGuids) + { + foreach (var key in m_ResourcesToDependencies.Keys) + { + var bundleDependencies = bundleDependencyGuids.Intersect(m_ResourcesToDependencies[key]).ToList(); + + m_ResourcesToDependencies[key].Clear(); + m_ResourcesToDependencies[key].AddRange(bundleDependencies); + } + } + + /// + /// Build map of resources to corresponding dependencies + /// + /// Array of resource paths + protected internal virtual void BuiltInResourcesToDependenciesMap(string[] resourcePaths) + { + for (int sceneIndex = 0; sceneIndex < resourcePaths.Length; ++sceneIndex) + { + string path = resourcePaths[sceneIndex]; + if (EditorUtility.DisplayCancelableProgressBar("Generating built-in resource dependency map", + "Checking " + path + " for duplicates with Addressables content.", + (float)sceneIndex / resourcePaths.Length)) + { + m_ResourcesToDependencies.Clear(); + EditorUtility.ClearProgressBar(); + return; + } + + string[] dependencies; + if (path.EndsWith(".unity", StringComparison.OrdinalIgnoreCase)) + { + using (var w = new BuildInterfacesWrapper()) + { + var usageTags = new BuildUsageTagSet(); + BuildSettings settings = new BuildSettings + { + group = EditorUserBuildSettings.selectedBuildTargetGroup, + target = EditorUserBuildSettings.activeBuildTarget, + typeDB = null, + buildFlags = ContentBuildFlags.None + }; + + SceneDependencyInfo sceneInfo = + ContentBuildInterface.CalculatePlayerDependenciesForScene(path, settings, usageTags); + dependencies = new string[sceneInfo.referencedObjects.Count]; + for (int i = 0; i < sceneInfo.referencedObjects.Count; ++i) + { + if (string.IsNullOrEmpty(sceneInfo.referencedObjects[i].filePath)) + dependencies[i] = AssetDatabase.GUIDToAssetPath(sceneInfo.referencedObjects[i].guid.ToString()); + else + dependencies[i] = sceneInfo.referencedObjects[i].filePath; + } + } + } + else + dependencies = AssetDatabase.GetDependencies(path); + + if (!m_ResourcesToDependencies.ContainsKey(path)) + m_ResourcesToDependencies.Add(path, new List(dependencies.Length)); + else + m_ResourcesToDependencies[path].Capacity += dependencies.Length; + + foreach (string dependency in dependencies) + { + if (dependency.EndsWith(".cs", StringComparison.OrdinalIgnoreCase) || dependency.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) + continue; + m_ResourcesToDependencies[path].Add(new GUID(AssetDatabase.AssetPathToGUID(dependency))); + } + } + + EditorUtility.ClearProgressBar(); + } + + /// + /// Use bundle names to create group names for AssetBundleBuild + /// + /// Context information for building + protected internal void ConvertBundleNamesToGroupNames(AddressableAssetsBuildContext buildContext) + { + if (m_ExtractData == null) + { + Debug.LogError("Build not run, RefreshBuild needed before ConvertBundleNamesToGroupNames"); + return; + } + + Dictionary bundleNamesToUpdate = new Dictionary(); + + foreach (var assetGroup in buildContext.Settings.groups) + { + if (assetGroup == null) + continue; + + List bundles; + if (buildContext.assetGroupToBundles.TryGetValue(assetGroup, out bundles)) + { + foreach (string bundle in bundles) + { + var keys = m_ExtractData.WriteData.FileToBundle.Keys.Where(key => m_ExtractData.WriteData.FileToBundle[key] == bundle); + foreach (string key in keys) + bundleNamesToUpdate.Add(key, assetGroup.Name); + } + } + } + + foreach (string key in bundleNamesToUpdate.Keys) + { + var bundleName = m_ExtractData.WriteData.FileToBundle[key]; + string convertedName = ConvertBundleName(bundleName, bundleNamesToUpdate[key]); + if (m_ExtractData.WriteData.FileToBundle.ContainsKey(key)) + m_ExtractData.WriteData.FileToBundle[key] = convertedName; + for (int i = 0; i < m_AllBundleInputDefs.Count; ++i) + { + if (m_AllBundleInputDefs[i].assetBundleName == bundleName) + { + var input = m_AllBundleInputDefs[i]; + input.assetBundleName = convertedName; + m_AllBundleInputDefs[i] = input; + break; + } + } + } + } + + /// + /// Generate input definitions and entries for AssetBundleBuild + /// + /// The current Addressables settings object + protected internal void CalculateInputDefinitions(AddressableAssetSettings settings) + { + int updateFrequency = Mathf.Max(settings.groups.Count / 10, 1); + bool progressDisplayed = false; + for (int groupIndex = 0; groupIndex < settings.groups.Count; ++groupIndex) + { + AddressableAssetGroup group = settings.groups[groupIndex]; + if (group == null) + continue; + if (!progressDisplayed || groupIndex % updateFrequency == 0) + { + progressDisplayed = true; + if (EditorUtility.DisplayCancelableProgressBar("Calculating Input Definitions", "", + (float)groupIndex / settings.groups.Count)) + { + m_AssetEntries.Clear(); + m_BundleToAssetGroup.Clear(); + m_AllBundleInputDefs.Clear(); + break; + } + } + + var schema = group.GetSchema(); + if (schema != null && schema.IncludeInBuild) + { + List bundleInputDefinitions = new List(); + m_AssetEntries.AddRange(BuildScriptPackedMode.PrepGroupBundlePacking(group, bundleInputDefinitions, schema)); + + for (int i = 0; i < bundleInputDefinitions.Count; i++) + { + if (m_BundleToAssetGroup.ContainsKey(bundleInputDefinitions[i].assetBundleName)) + bundleInputDefinitions[i] = CreateUniqueBundle(bundleInputDefinitions[i]); + + m_BundleToAssetGroup.Add(bundleInputDefinitions[i].assetBundleName, schema.Group.Guid); + } + + m_AllBundleInputDefs.AddRange(bundleInputDefinitions); + } + } + + if (progressDisplayed) + EditorUtility.ClearProgressBar(); + } + + internal AssetBundleBuild CreateUniqueBundle(AssetBundleBuild bid) + { + return CreateUniqueBundle(bid, m_BundleToAssetGroup); + } + + /// + /// Create new AssetBundleBuild + /// + /// ID for new AssetBundleBuild + /// Map of bundle names to asset group Guids + /// + protected internal static AssetBundleBuild CreateUniqueBundle(AssetBundleBuild bid, Dictionary bundleToAssetGroup) + { + int count = 1; + var newName = bid.assetBundleName; + while (bundleToAssetGroup.ContainsKey(newName) && count < 1000) + newName = bid.assetBundleName.Replace(".bundle", string.Format("{0}.bundle", count++)); + return new AssetBundleBuild + { + assetBundleName = newName, + addressableNames = bid.addressableNames, + assetBundleVariant = bid.assetBundleVariant, + assetNames = bid.assetNames + }; + } + + /// + /// Get bundle's object ids that have no dependency file + /// + /// Name of bundle file + /// List of GUIDS of objects in bundle with no dependency file + protected List GetImplicitGuidsForBundle(string fileName) + { + if (m_ExtractData == null) + { + Debug.LogError("Build not run, RefreshBuild needed before GetImplicitGuidsForBundle"); + return new List(); + } + + List guids = (from id in m_ExtractData.WriteData.FileToObjects[fileName] + where !m_ExtractData.WriteData.AssetToFiles.Keys.Contains(id.guid) + select id.guid).ToList(); + return guids; + } + + /// + /// Build map of implicit guids to their bundle files + /// + /// Dictionary of implicit guids to their corresponding file + protected internal Dictionary> GetImplicitGuidToFilesMap() + { + if (m_ExtractData == null) + { + Debug.LogError("Build not run, RefreshBuild needed before GetImplicitGuidToFilesMap"); + return new Dictionary>(); + } + + Dictionary> implicitGuids = new Dictionary>(); + IEnumerable> validImplicitGuids = + from fileToObject in m_ExtractData.WriteData.FileToObjects + from objectId in fileToObject.Value + where !m_ExtractData.WriteData.AssetToFiles.Keys.Contains(objectId.guid) + select new KeyValuePair(objectId, fileToObject.Key); + + //Build our Dictionary from our list of valid implicit guids (guids not already in explicit guids) + foreach (var objectIdToFile in validImplicitGuids) + { + if (!implicitGuids.ContainsKey(objectIdToFile.Key.guid)) + implicitGuids.Add(objectIdToFile.Key.guid, new List()); + implicitGuids[objectIdToFile.Key.guid].Add(objectIdToFile.Value); + } + + return implicitGuids; + } + + /// + /// Calculate built in resources and corresponding bundle dependencies + /// + /// The current Addressables settings object + /// Array of resource paths + /// List of rule results after calculating resource and bundle dependency combined + protected List CalculateBuiltInResourceDependenciesToBundleDependecies(AddressableAssetSettings settings, string[] builtInResourcesPaths) + { + List results = new List(); + + if (!BuildUtility.CheckModifiedScenesAndAskToSave()) + { + Debug.LogError("Cannot run Analyze with unsaved scenes"); + results.Add(new AnalyzeResult {resultName = ruleName + "Cannot run Analyze with unsaved scenes"}); + return results; + } + + EditorUtility.DisplayProgressBar("Calculating Built-in dependencies", "Calculating dependencies between Built-in resources and Addressables", 0); + try + { + // bulk of work and progress bars displayed in these methods + var buildSuccess = BuildAndGetResourceDependencies(settings, builtInResourcesPaths); + if (buildSuccess != ReturnCode.Success) + { + if (buildSuccess == ReturnCode.SuccessNotRun) + { + results.Add(new AnalyzeResult {resultName = ruleName + " - No issues found."}); + return results; + } + + results.Add(new AnalyzeResult {resultName = ruleName + "Analyze build failed. " + buildSuccess}); + return results; + } + } + finally + { + EditorUtility.ClearProgressBar(); + } + + results = (from resource in m_ResourcesToDependencies.Keys + from dependency in m_ResourcesToDependencies[resource] + let assetPath = AssetDatabase.GUIDToAssetPath(dependency.ToString()) + let files = m_ExtractData.WriteData.FileToObjects.Keys + from file in files + where m_ExtractData.WriteData.FileToObjects[file].Any(oid => oid.guid == dependency) + where m_ExtractData.WriteData.FileToBundle.ContainsKey(file) + let bundle = m_ExtractData.WriteData.FileToBundle[file] + select new AnalyzeResult + { + resultName = + resource + kDelimiter + + bundle + kDelimiter + + assetPath, + severity = MessageType.Warning + }).ToList(); + + if (results.Count == 0) + results.Add(new AnalyzeResult {resultName = ruleName + " - No issues found."}); + + return results; + } + + /// + /// Calculates and gathers dependencies for built in data. + /// + /// The AddressableAssetSettings to pull data from. + /// The paths that lead to all the built in Resource locations + /// A ReturnCode indicating various levels of success or failure. + protected ReturnCode BuildAndGetResourceDependencies(AddressableAssetSettings settings, string[] builtInResourcesPaths) + { + BuiltInResourcesToDependenciesMap(builtInResourcesPaths); + if (m_ResourcesToDependencies == null || m_ResourcesToDependencies.Count == 0) + return ReturnCode.SuccessNotRun; + + CalculateInputDefinitions(settings); + if (m_AllBundleInputDefs == null || m_AllBundleInputDefs.Count == 0) + return ReturnCode.SuccessNotRun; + + EditorUtility.DisplayProgressBar("Calculating Built-in dependencies", + "Calculating dependencies between Built-in resources and Addressables", 0.5f); + + ReturnCode exitCode = ReturnCode.Error; + var context = GetBuildContext(settings); + exitCode = RefreshBuild(context); + if (exitCode < ReturnCode.Success) + { + EditorUtility.ClearProgressBar(); + return exitCode; + } + + EditorUtility.DisplayProgressBar("Calculating Built-in dependencies", + "Calculating dependencies between Built-in resources and Addressables", 0.9f); + IntersectResourcesDepedenciesWithBundleDependencies(GetAllBundleDependencies()); + ConvertBundleNamesToGroupNames(context); + + return exitCode; + } + + /// + /// Convert bundle name to include group name + /// + /// Current bundle name + /// Group name of bundle's group + /// The new bundle name + protected string ConvertBundleName(string bundleName, string groupName) + { + string[] bundleNameSegments = bundleName.Split('_'); + bundleNameSegments[0] = groupName.Replace(" ", "").ToLower(); + return string.Join("_", bundleNameSegments); + } + + /// + /// Clear all previously gathered bundle data and analysis + /// + public override void ClearAnalysis() + { + m_Locations.Clear(); + m_AssetEntries.Clear(); + m_AllBundleInputDefs.Clear(); + m_BundleToAssetGroup.Clear(); + m_ResourcesToDependencies.Clear(); + m_ResultData = null; + m_ExtractData = null; + + base.ClearAnalysis(); + } + + /// + /// Data object for results of resource based analysis rules + /// + protected internal struct ResultData + { + public string ResourcePath; + public string AssetBundleName; + public string AssetPath; + } + + /// + public override bool CanFix + { + get { return false; } + } + + private List m_ResultData = null; + + /// + /// Duplicate Results between Addressables and Player content. + /// + protected IEnumerable Results + { + get + { + if (m_ResultData == null) + { + if (ExtractData == null) + { + Debug.LogError("RefreshAnalysis needs to be called before getting results"); + return new List(0); + } + + m_ResultData = new List(512); + + foreach (string resource in ResourcesToDependencies.Keys) + { + var dependencies = ResourcesToDependencies[resource]; + foreach (GUID dependency in dependencies) + { + string assetPath = AssetDatabase.GUIDToAssetPath(dependency.ToString()); + var files = ExtractData.WriteData.FileToObjects.Keys; + foreach (string file in files) + { + if (m_ExtractData.WriteData.FileToObjects[file].Any(oid => oid.guid == dependency) && + m_ExtractData.WriteData.FileToBundle.ContainsKey(file)) + { + string assetBundleName = ExtractData.WriteData.FileToBundle[file]; + m_ResultData.Add(new ResultData() + { + AssetBundleName = assetBundleName, + AssetPath = assetPath, + ResourcePath = resource + }); + } + } + } + } + } + + return m_ResultData; + } + } + + /// + /// Clear analysis and calculate built in content and corresponding bundle dependencies + /// + /// The current Addressables settings object + /// List of results from analysis + public override List RefreshAnalysis(AddressableAssetSettings settings) + { + ClearAnalysis(); + List results = new List(); + + if (!BuildUtility.CheckModifiedScenesAndAskToSave()) + { + Debug.LogError("Cannot run Analyze with unsaved scenes"); + results.Add(new AnalyzeResult {resultName = ruleName + "Cannot run Analyze with unsaved scenes"}); + return results; + } + + EditorUtility.DisplayProgressBar("Calculating Built-in dependencies", "Calculating dependencies between Resources and Addressables", 0); + try + { + // bulk of work and progress bars displayed in these methods + string[] resourcePaths = GetResourcePaths(); + + var buildSuccess = BuildAndGetResourceDependencies(settings, resourcePaths); + if (buildSuccess == ReturnCode.SuccessNotRun) + { + results.Add(new AnalyzeResult {resultName = ruleName + " - No issues found."}); + return results; + } + + if (buildSuccess != ReturnCode.Success) + { + results.Add(new AnalyzeResult {resultName = ruleName + "Analyze build failed. " + buildSuccess}); + return results; + } + } + finally + { + EditorUtility.ClearProgressBar(); + } + + foreach (ResultData result in Results) + { + results.Add(new AnalyzeResult() + { + resultName = + result.ResourcePath + kDelimiter + + result.AssetBundleName + kDelimiter + + result.AssetPath, + severity = MessageType.Warning + }); + } + + return results; + } + + /// + /// Gets an array of resource paths that are to be compared against the addressables build content + /// + /// Array of Resource paths to compare against + internal protected virtual string[] GetResourcePaths() + { + return new string[0]; + } + + /// + public override void FixIssues(AddressableAssetSettings settings) + { + //Do nothing. There's nothing to fix. + } + } +} diff --git a/Editor/Build/AnalyzeRules/BundleRuleBase.cs.meta b/Editor/Build/AnalyzeRules/BundleRuleBase.cs.meta index 4e79c21c..ba9f3c0c 100644 --- a/Editor/Build/AnalyzeRules/BundleRuleBase.cs.meta +++ b/Editor/Build/AnalyzeRules/BundleRuleBase.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 8aae9ccc172d3fd48a20726e5c902489 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 8aae9ccc172d3fd48a20726e5c902489 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs b/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs index 08433e1f..0dfcc707 100644 --- a/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs +++ b/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs @@ -1,310 +1,310 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEditor.AddressableAssets.Build.DataBuilders; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.AddressableAssets.Settings.GroupSchemas; -using UnityEditor.Build.Pipeline; -using UnityEngine; - -namespace UnityEditor.AddressableAssets.Build.AnalyzeRules -{ - /// - /// Rule class to check for duplicate bundle dependencies - /// - public class CheckBundleDupeDependencies : BundleRuleBase - { - /// - /// Result for checking for duplicates - /// - protected internal struct CheckDupeResult - { - public AddressableAssetGroup Group; - public string DuplicatedFile; - public string AssetPath; - public GUID DuplicatedGroupGuid; - } - - /// - /// Results for duplicate results inverted check - /// - protected internal struct ExtraCheckBundleDupeData - { - public bool ResultsInverted; - } - - /// - public override bool CanFix - { - get { return true; } - } - - /// - public override string ruleName - { - get { return "Check Duplicate Bundle Dependencies"; } - } - - [NonSerialized] - internal readonly Dictionary>> m_AllIssues = new Dictionary>>(); - - [SerializeField] - internal HashSet m_ImplicitAssets; - - [NonSerialized] - internal List m_ResultsData; - - /// - /// Results calculated by the duplicate bundle dependencies check. - /// - protected IEnumerable CheckDupeResults - { - get - { - if (m_ResultsData == null) - { - Debug.LogError("RefreshAnalysis needs to be called before getting results"); - return new List(0); - } - - return m_ResultsData; - } - } - - /// - /// Clear current analysis and rerun check for duplicates - /// - /// The current Addressables settings object - /// List of the analysis results - public override List RefreshAnalysis(AddressableAssetSettings settings) - { - ClearAnalysis(); - return CheckForDuplicateDependencies(settings); - } - - void RefreshDisplay() - { - var savedData = AnalyzeSystem.GetDataForRule(this); - if (!savedData.ResultsInverted) - { - m_Results = (from issueGroup in m_AllIssues - from bundle in issueGroup.Value - from item in bundle.Value - select new AnalyzeResult - { - resultName = issueGroup.Key + kDelimiter + - ConvertBundleName(bundle.Key, issueGroup.Key) + kDelimiter + - item, - severity = MessageType.Warning - }).ToList(); - } - else - { - m_Results = (from issueGroup in m_AllIssues - from bundle in issueGroup.Value - from item in bundle.Value - select new AnalyzeResult - { - resultName = item + kDelimiter + - ConvertBundleName(bundle.Key, issueGroup.Key) + kDelimiter + - issueGroup.Key, - severity = MessageType.Warning - }).ToList(); - } - - if (m_Results.Count == 0) - m_Results.Add(noErrors); - } - - internal override IList GetCustomContextMenuItems() - { - IList customItems = new List(); - customItems.Add(new CustomContextMenu("Organize by Asset", - () => InvertDisplay(), - AnalyzeSystem.AnalyzeData.Data[ruleName].Any(), - AnalyzeSystem.GetDataForRule(this).ResultsInverted)); - return customItems; - } - - void InvertDisplay() - { - List updatedResults = new List(); - foreach (var result in AnalyzeSystem.AnalyzeData.Data[ruleName]) - { - updatedResults.Add(new AnalyzeResult() - { - //start at index 1 because the first result is going to be the rule name which we want to remain where it is. - resultName = ReverseStringFromIndex(result.resultName, 1, kDelimiter), - severity = result.severity - }); - } - - AnalyzeSystem.ReplaceAnalyzeData(this, updatedResults); - var savedData = AnalyzeSystem.GetDataForRule(this); - savedData.ResultsInverted = !savedData.ResultsInverted; - AnalyzeSystem.SaveDataForRule(this, savedData); - AnalyzeSystem.SerializeData(); - AnalyzeSystem.ReloadUI(); - } - - private string ReverseStringFromIndex(string data, int startingIndex, char delimiter) - { - string[] splitData = data.Split(delimiter); - int i = startingIndex; - int k = splitData.Length - 1; - while (i < k) - { - string temp = splitData[i]; - splitData[i] = splitData[k]; - splitData[k] = temp; - i++; - k--; - } - - return String.Join(kDelimiter.ToString(), splitData); - } - - /// - /// Check for duplicates among the dependencies and build implicit duplicates - /// - /// The current Addressables settings object - /// List of results from analysis - protected List CheckForDuplicateDependencies(AddressableAssetSettings settings) - { - if (!BuildUtility.CheckModifiedScenesAndAskToSave()) - { - Debug.LogError("Cannot run Analyze with unsaved scenes"); - m_Results.Add(new AnalyzeResult {resultName = ruleName + "Cannot run Analyze with unsaved scenes"}); - return m_Results; - } - - CalculateInputDefinitions(settings); - - if (AllBundleInputDefs.Count > 0) - { - var context = GetBuildContext(settings); - ReturnCode exitCode = RefreshBuild(context); - if (exitCode < ReturnCode.Success) - { - Debug.LogError("Analyze build failed. " + exitCode); - m_Results.Add(new AnalyzeResult {resultName = ruleName + "Analyze build failed. " + exitCode}); - return m_Results; - } - - var implicitGuids = GetImplicitGuidToFilesMap(); - var checkDupeResults = CalculateDuplicates(implicitGuids, context); - BuildImplicitDuplicatedAssetsSet(checkDupeResults); - m_ResultsData = checkDupeResults.ToList(); - } - else - { - m_ResultsData = new List(0); - m_ImplicitAssets = new HashSet(); - } - - AddressableAnalytics.ReportUsageEvent(AddressableAnalytics.UsageEventType.RunCheckBundleDupeDependenciesRule); - RefreshDisplay(); - return m_Results; - } - - /// - /// Calculate duplicate dependencies - /// - /// Map of implicit guids to their bundle files - /// The build context information - /// Enumerable of results from duplicates check - protected internal IEnumerable CalculateDuplicates(Dictionary> implicitGuids, AddressableAssetsBuildContext aaContext) - { - //Get all guids that have more than one bundle referencing them - IEnumerable>> validGuids = - from dupeGuid in implicitGuids - where dupeGuid.Value.Distinct().Count() > 1 - where IsValidPath(AssetDatabase.GUIDToAssetPath(dupeGuid.Key.ToString())) - select dupeGuid; - - return - from guidToFile in validGuids - from file in guidToFile.Value - - //Get the files that belong to those guids - let fileToBundle = ExtractData.WriteData.FileToBundle[file] - - //Get the bundles that belong to those files - let bundleToGroup = aaContext.bundleToAssetGroup[fileToBundle] - - //Get the asset groups that belong to those bundles - let selectedGroup = aaContext.Settings.FindGroup(findGroup => findGroup != null && findGroup.Guid == bundleToGroup) - select new CheckDupeResult - { - Group = selectedGroup, - DuplicatedFile = file, - AssetPath = AssetDatabase.GUIDToAssetPath(guidToFile.Key.ToString()), - DuplicatedGroupGuid = guidToFile.Key - }; - } - - internal void BuildImplicitDuplicatedAssetsSet(IEnumerable checkDupeResults) - { - m_ImplicitAssets = new HashSet(); - - foreach (var checkDupeResult in checkDupeResults) - { - Dictionary> groupData; - if (!m_AllIssues.TryGetValue(checkDupeResult.Group.Name, out groupData)) - { - groupData = new Dictionary>(); - m_AllIssues.Add(checkDupeResult.Group.Name, groupData); - } - - List assets; - if (!groupData.TryGetValue(ExtractData.WriteData.FileToBundle[checkDupeResult.DuplicatedFile], out assets)) - { - assets = new List(); - groupData.Add(ExtractData.WriteData.FileToBundle[checkDupeResult.DuplicatedFile], assets); - } - - assets.Add(checkDupeResult.AssetPath); - m_ImplicitAssets.Add(checkDupeResult.DuplicatedGroupGuid); - } - } - - /// - /// Fix duplicates by moving to a new group - /// - /// The current Addressables settings object - public override void FixIssues(AddressableAssetSettings settings) - { - if (m_ImplicitAssets == null) - CheckForDuplicateDependencies(settings); - - if (m_ImplicitAssets.Count == 0) - return; - - var group = settings.CreateGroup("Duplicate Asset Isolation", false, false, false, null, typeof(BundledAssetGroupSchema), typeof(ContentUpdateGroupSchema)); - group.GetSchema().StaticContent = true; - - foreach (var asset in m_ImplicitAssets) - settings.CreateOrMoveEntry(asset.ToString(), group, false, false); - - settings.SetDirty(AddressableAssetSettings.ModificationEvent.BatchModification, null, true, true); - } - - /// - public override void ClearAnalysis() - { - m_AllIssues.Clear(); - m_ImplicitAssets = null; - m_ResultsData = null; - base.ClearAnalysis(); - } - } - - [InitializeOnLoad] - class RegisterCheckBundleDupeDependencies - { - static RegisterCheckBundleDupeDependencies() - { - AnalyzeSystem.RegisterNewRule(); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.AddressableAssets.Build.DataBuilders; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEditor.Build.Pipeline; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build.AnalyzeRules +{ + /// + /// Rule class to check for duplicate bundle dependencies + /// + public class CheckBundleDupeDependencies : BundleRuleBase + { + /// + /// Result for checking for duplicates + /// + protected internal struct CheckDupeResult + { + public AddressableAssetGroup Group; + public string DuplicatedFile; + public string AssetPath; + public GUID DuplicatedGroupGuid; + } + + /// + /// Results for duplicate results inverted check + /// + protected internal struct ExtraCheckBundleDupeData + { + public bool ResultsInverted; + } + + /// + public override bool CanFix + { + get { return true; } + } + + /// + public override string ruleName + { + get { return "Check Duplicate Bundle Dependencies"; } + } + + [NonSerialized] + internal readonly Dictionary>> m_AllIssues = new Dictionary>>(); + + [SerializeField] + internal HashSet m_ImplicitAssets; + + [NonSerialized] + internal List m_ResultsData; + + /// + /// Results calculated by the duplicate bundle dependencies check. + /// + protected IEnumerable CheckDupeResults + { + get + { + if (m_ResultsData == null) + { + Debug.LogError("RefreshAnalysis needs to be called before getting results"); + return new List(0); + } + + return m_ResultsData; + } + } + + /// + /// Clear current analysis and rerun check for duplicates + /// + /// The current Addressables settings object + /// List of the analysis results + public override List RefreshAnalysis(AddressableAssetSettings settings) + { + ClearAnalysis(); + return CheckForDuplicateDependencies(settings); + } + + void RefreshDisplay() + { + var savedData = AnalyzeSystem.GetDataForRule(this); + if (!savedData.ResultsInverted) + { + m_Results = (from issueGroup in m_AllIssues + from bundle in issueGroup.Value + from item in bundle.Value + select new AnalyzeResult + { + resultName = issueGroup.Key + kDelimiter + + ConvertBundleName(bundle.Key, issueGroup.Key) + kDelimiter + + item, + severity = MessageType.Warning + }).ToList(); + } + else + { + m_Results = (from issueGroup in m_AllIssues + from bundle in issueGroup.Value + from item in bundle.Value + select new AnalyzeResult + { + resultName = item + kDelimiter + + ConvertBundleName(bundle.Key, issueGroup.Key) + kDelimiter + + issueGroup.Key, + severity = MessageType.Warning + }).ToList(); + } + + if (m_Results.Count == 0) + m_Results.Add(noErrors); + } + + internal override IList GetCustomContextMenuItems() + { + IList customItems = new List(); + customItems.Add(new CustomContextMenu("Organize by Asset", + () => InvertDisplay(), + AnalyzeSystem.AnalyzeData.Data[ruleName].Any(), + AnalyzeSystem.GetDataForRule(this).ResultsInverted)); + return customItems; + } + + void InvertDisplay() + { + List updatedResults = new List(); + foreach (var result in AnalyzeSystem.AnalyzeData.Data[ruleName]) + { + updatedResults.Add(new AnalyzeResult() + { + //start at index 1 because the first result is going to be the rule name which we want to remain where it is. + resultName = ReverseStringFromIndex(result.resultName, 1, kDelimiter), + severity = result.severity + }); + } + + AnalyzeSystem.ReplaceAnalyzeData(this, updatedResults); + var savedData = AnalyzeSystem.GetDataForRule(this); + savedData.ResultsInverted = !savedData.ResultsInverted; + AnalyzeSystem.SaveDataForRule(this, savedData); + AnalyzeSystem.SerializeData(); + AnalyzeSystem.ReloadUI(); + } + + private string ReverseStringFromIndex(string data, int startingIndex, char delimiter) + { + string[] splitData = data.Split(delimiter); + int i = startingIndex; + int k = splitData.Length - 1; + while (i < k) + { + string temp = splitData[i]; + splitData[i] = splitData[k]; + splitData[k] = temp; + i++; + k--; + } + + return String.Join(kDelimiter.ToString(), splitData); + } + + /// + /// Check for duplicates among the dependencies and build implicit duplicates + /// + /// The current Addressables settings object + /// List of results from analysis + protected List CheckForDuplicateDependencies(AddressableAssetSettings settings) + { + if (!BuildUtility.CheckModifiedScenesAndAskToSave()) + { + Debug.LogError("Cannot run Analyze with unsaved scenes"); + m_Results.Add(new AnalyzeResult {resultName = ruleName + "Cannot run Analyze with unsaved scenes"}); + return m_Results; + } + + CalculateInputDefinitions(settings); + + if (AllBundleInputDefs.Count > 0) + { + var context = GetBuildContext(settings); + ReturnCode exitCode = RefreshBuild(context); + if (exitCode < ReturnCode.Success) + { + Debug.LogError("Analyze build failed. " + exitCode); + m_Results.Add(new AnalyzeResult {resultName = ruleName + "Analyze build failed. " + exitCode}); + return m_Results; + } + + var implicitGuids = GetImplicitGuidToFilesMap(); + var checkDupeResults = CalculateDuplicates(implicitGuids, context); + BuildImplicitDuplicatedAssetsSet(checkDupeResults); + m_ResultsData = checkDupeResults.ToList(); + } + else + { + m_ResultsData = new List(0); + m_ImplicitAssets = new HashSet(); + } + + AddressableAnalytics.ReportUsageEvent(AddressableAnalytics.UsageEventType.RunCheckBundleDupeDependenciesRule); + RefreshDisplay(); + return m_Results; + } + + /// + /// Calculate duplicate dependencies + /// + /// Map of implicit guids to their bundle files + /// The build context information + /// Enumerable of results from duplicates check + protected internal IEnumerable CalculateDuplicates(Dictionary> implicitGuids, AddressableAssetsBuildContext aaContext) + { + //Get all guids that have more than one bundle referencing them + IEnumerable>> validGuids = + from dupeGuid in implicitGuids + where dupeGuid.Value.Distinct().Count() > 1 + where IsValidPath(AssetDatabase.GUIDToAssetPath(dupeGuid.Key.ToString())) + select dupeGuid; + + return + from guidToFile in validGuids + from file in guidToFile.Value + + //Get the files that belong to those guids + let fileToBundle = ExtractData.WriteData.FileToBundle[file] + + //Get the bundles that belong to those files + let bundleToGroup = aaContext.bundleToAssetGroup[fileToBundle] + + //Get the asset groups that belong to those bundles + let selectedGroup = aaContext.Settings.FindGroup(findGroup => findGroup != null && findGroup.Guid == bundleToGroup) + select new CheckDupeResult + { + Group = selectedGroup, + DuplicatedFile = file, + AssetPath = AssetDatabase.GUIDToAssetPath(guidToFile.Key.ToString()), + DuplicatedGroupGuid = guidToFile.Key + }; + } + + internal void BuildImplicitDuplicatedAssetsSet(IEnumerable checkDupeResults) + { + m_ImplicitAssets = new HashSet(); + + foreach (var checkDupeResult in checkDupeResults) + { + Dictionary> groupData; + if (!m_AllIssues.TryGetValue(checkDupeResult.Group.Name, out groupData)) + { + groupData = new Dictionary>(); + m_AllIssues.Add(checkDupeResult.Group.Name, groupData); + } + + List assets; + if (!groupData.TryGetValue(ExtractData.WriteData.FileToBundle[checkDupeResult.DuplicatedFile], out assets)) + { + assets = new List(); + groupData.Add(ExtractData.WriteData.FileToBundle[checkDupeResult.DuplicatedFile], assets); + } + + assets.Add(checkDupeResult.AssetPath); + m_ImplicitAssets.Add(checkDupeResult.DuplicatedGroupGuid); + } + } + + /// + /// Fix duplicates by moving to a new group + /// + /// The current Addressables settings object + public override void FixIssues(AddressableAssetSettings settings) + { + if (m_ImplicitAssets == null) + CheckForDuplicateDependencies(settings); + + if (m_ImplicitAssets.Count == 0) + return; + + var group = settings.CreateGroup("Duplicate Asset Isolation", false, false, false, null, typeof(BundledAssetGroupSchema), typeof(ContentUpdateGroupSchema)); + group.GetSchema().StaticContent = true; + + foreach (var asset in m_ImplicitAssets) + settings.CreateOrMoveEntry(asset.ToString(), group, false, false); + + settings.SetDirty(AddressableAssetSettings.ModificationEvent.BatchModification, null, true, true); + } + + /// + public override void ClearAnalysis() + { + m_AllIssues.Clear(); + m_ImplicitAssets = null; + m_ResultsData = null; + base.ClearAnalysis(); + } + } + + [InitializeOnLoad] + class RegisterCheckBundleDupeDependencies + { + static RegisterCheckBundleDupeDependencies() + { + AnalyzeSystem.RegisterNewRule(); + } + } +} diff --git a/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs.meta b/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs.meta index 0e1b9c74..7c16bdfe 100644 --- a/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs.meta +++ b/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 327933a391986b441b4355cdd9257400 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 327933a391986b441b4355cdd9257400 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs b/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs index d6503208..df01df84 100644 --- a/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs +++ b/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs @@ -1,62 +1,62 @@ -using System.Collections.Generic; -using System.IO; -using UnityEditor.AddressableAssets.Settings; - -namespace UnityEditor.AddressableAssets.Build.AnalyzeRules -{ - /// - /// Rule class to check resource dependencies for duplicates - /// - public class CheckResourcesDupeDependencies : BundleRuleBase - { - /// - public override string ruleName - { - get { return "Check Resources to Addressable Duplicate Dependencies"; } - } - - /// - public override bool CanFix - { - get { return false; } - } - - /// - /// Clear analysis and calculate built in resources and corresponding bundle dependencies - /// - /// The current Addressables settings object - /// List of results from analysis - public override List RefreshAnalysis(AddressableAssetSettings settings) - { - ClearAnalysis(); - AddressableAnalytics.ReportUsageEvent(AddressableAnalytics.UsageEventType.RunCheckResourcesDupeDependenciesRule); - return CalculateBuiltInResourceDependenciesToBundleDependecies(settings, GetResourcePaths()); - } - - /// - public override void FixIssues(AddressableAssetSettings settings) - { - //Do nothing. There's nothing to fix. - } - - /// - internal protected override string[] GetResourcePaths() - { - string[] resourceDirectory = Directory.GetDirectories("Assets", "Resources", SearchOption.AllDirectories); - List resourcePaths = new List(); - foreach (string directory in resourceDirectory) - resourcePaths.AddRange(Directory.GetFiles(directory, "*", SearchOption.AllDirectories)); - return resourcePaths.ToArray(); - } - } - - - [InitializeOnLoad] - class RegisterCheckResourcesDupeDependencies - { - static RegisterCheckResourcesDupeDependencies() - { - AnalyzeSystem.RegisterNewRule(); - } - } -} +using System.Collections.Generic; +using System.IO; +using UnityEditor.AddressableAssets.Settings; + +namespace UnityEditor.AddressableAssets.Build.AnalyzeRules +{ + /// + /// Rule class to check resource dependencies for duplicates + /// + public class CheckResourcesDupeDependencies : BundleRuleBase + { + /// + public override string ruleName + { + get { return "Check Resources to Addressable Duplicate Dependencies"; } + } + + /// + public override bool CanFix + { + get { return false; } + } + + /// + /// Clear analysis and calculate built in resources and corresponding bundle dependencies + /// + /// The current Addressables settings object + /// List of results from analysis + public override List RefreshAnalysis(AddressableAssetSettings settings) + { + ClearAnalysis(); + AddressableAnalytics.ReportUsageEvent(AddressableAnalytics.UsageEventType.RunCheckResourcesDupeDependenciesRule); + return CalculateBuiltInResourceDependenciesToBundleDependecies(settings, GetResourcePaths()); + } + + /// + public override void FixIssues(AddressableAssetSettings settings) + { + //Do nothing. There's nothing to fix. + } + + /// + internal protected override string[] GetResourcePaths() + { + string[] resourceDirectory = Directory.GetDirectories("Assets", "Resources", SearchOption.AllDirectories); + List resourcePaths = new List(); + foreach (string directory in resourceDirectory) + resourcePaths.AddRange(Directory.GetFiles(directory, "*", SearchOption.AllDirectories)); + return resourcePaths.ToArray(); + } + } + + + [InitializeOnLoad] + class RegisterCheckResourcesDupeDependencies + { + static RegisterCheckResourcesDupeDependencies() + { + AnalyzeSystem.RegisterNewRule(); + } + } +} diff --git a/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs.meta b/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs.meta index 6970e3a3..2864c532 100644 --- a/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs.meta +++ b/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 555da02c9c624644c9695f325ea6a22c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 555da02c9c624644c9695f325ea6a22c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs b/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs index 3b8abdf7..82f69cc4 100644 --- a/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs +++ b/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs @@ -1,68 +1,68 @@ -using System.Collections.Generic; -using System.Linq; -using UnityEditor.AddressableAssets.Settings; - -namespace UnityEditor.AddressableAssets.Build.AnalyzeRules -{ - /// - /// Rule class to check scene dependencies for duplicates - /// - public class CheckSceneDupeDependencies : BundleRuleBase - { - /// - public override string ruleName - { - get { return "Check Scene to Addressable Duplicate Dependencies"; } - } - - /// - public override bool CanFix - { - get { return false; } - } - - /// - public override void FixIssues(AddressableAssetSettings settings) - { - //Do nothing, there's nothing to fix. - } - - /// - /// Clear analysis and calculate built in resources and corresponding bundle dependencies for scenes - /// - /// The current Addressables settings object - /// List of results from analysis - public override List RefreshAnalysis(AddressableAssetSettings settings) - { - ClearAnalysis(); - - string[] scenePaths = (from editorScene in EditorBuildSettings.scenes - where editorScene.enabled - select editorScene.path).ToArray(); - AddressableAnalytics.ReportUsageEvent(AddressableAnalytics.UsageEventType.RunCheckSceneDupeDependenciesRule); - return CalculateBuiltInResourceDependenciesToBundleDependecies(settings, scenePaths); - } - - /// - internal protected override string[] GetResourcePaths() - { - List scenes = new List(EditorBuildSettings.scenes.Length); - foreach (EditorBuildSettingsScene settingsScene in EditorBuildSettings.scenes) - { - if (settingsScene.enabled) - scenes.Add(settingsScene.path); - } - - return scenes.ToArray(); - } - } - - [InitializeOnLoad] - class RegisterCheckSceneDupeDependencies - { - static RegisterCheckSceneDupeDependencies() - { - AnalyzeSystem.RegisterNewRule(); - } - } -} +using System.Collections.Generic; +using System.Linq; +using UnityEditor.AddressableAssets.Settings; + +namespace UnityEditor.AddressableAssets.Build.AnalyzeRules +{ + /// + /// Rule class to check scene dependencies for duplicates + /// + public class CheckSceneDupeDependencies : BundleRuleBase + { + /// + public override string ruleName + { + get { return "Check Scene to Addressable Duplicate Dependencies"; } + } + + /// + public override bool CanFix + { + get { return false; } + } + + /// + public override void FixIssues(AddressableAssetSettings settings) + { + //Do nothing, there's nothing to fix. + } + + /// + /// Clear analysis and calculate built in resources and corresponding bundle dependencies for scenes + /// + /// The current Addressables settings object + /// List of results from analysis + public override List RefreshAnalysis(AddressableAssetSettings settings) + { + ClearAnalysis(); + + string[] scenePaths = (from editorScene in EditorBuildSettings.scenes + where editorScene.enabled + select editorScene.path).ToArray(); + AddressableAnalytics.ReportUsageEvent(AddressableAnalytics.UsageEventType.RunCheckSceneDupeDependenciesRule); + return CalculateBuiltInResourceDependenciesToBundleDependecies(settings, scenePaths); + } + + /// + internal protected override string[] GetResourcePaths() + { + List scenes = new List(EditorBuildSettings.scenes.Length); + foreach (EditorBuildSettingsScene settingsScene in EditorBuildSettings.scenes) + { + if (settingsScene.enabled) + scenes.Add(settingsScene.path); + } + + return scenes.ToArray(); + } + } + + [InitializeOnLoad] + class RegisterCheckSceneDupeDependencies + { + static RegisterCheckSceneDupeDependencies() + { + AnalyzeSystem.RegisterNewRule(); + } + } +} diff --git a/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs.meta b/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs.meta index 62f8b877..4414d215 100644 --- a/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs.meta +++ b/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: bd1bea4352ab4fb49a0d15da275cd26d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: bd1bea4352ab4fb49a0d15da275cd26d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/BuildPipelineTasks.meta b/Editor/Build/BuildPipelineTasks.meta index 1b0c3a8a..c6c7c322 100644 --- a/Editor/Build/BuildPipelineTasks.meta +++ b/Editor/Build/BuildPipelineTasks.meta @@ -1,8 +1,8 @@ -fileFormatVersion: 2 -guid: 2e63e5dd2cdcb394984e15b78da0a927 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 2e63e5dd2cdcb394984e15b78da0a927 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs b/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs index 7a675a34..8f260883 100644 --- a/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs +++ b/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs @@ -1,107 +1,107 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEditor.AddressableAssets.Build.DataBuilders; -using UnityEditor.Build.Content; -using UnityEditor.Build.Pipeline; -using UnityEditor.Build.Pipeline.Injector; -using UnityEditor.Build.Pipeline.Interfaces; -using UnityEditor.Build.Pipeline.Utilities; -using UnityEngine; - -namespace UnityEditor.AddressableAssets.Build.BuildPipelineTasks -{ - /// - /// The BuildTask used to append the asset hash to the internal bundle name. - /// - public class AddHashToBundleNameTask : IBuildTask - { - /// - /// The task version. - /// - public int Version - { - get { return 1; } - } - -#pragma warning disable 649 - [InjectContext(ContextUsage.In)] - IBuildParameters m_Parameters; - - [InjectContext(ContextUsage.In)] - IBundleBuildContent m_BuildContent; - - [InjectContext] - IDependencyData m_DependencyData; - - [InjectContext(ContextUsage.InOut, true)] - IBuildSpriteData m_SpriteData; - - [InjectContext(ContextUsage.In)] - IAddressableAssetsBuildContext m_AaBuildContext; - - [InjectContext(ContextUsage.In, true)] - IBuildCache m_Cache; -#pragma warning restore 649 - - /// - /// Runs the AddHashToBundleNameTask. - /// - /// Success. - public ReturnCode Run() - { - var aa = m_AaBuildContext as AddressableAssetsBuildContext; - if (!aa.Settings.UniqueBundleIds) - return ReturnCode.Success; - - var newBundleLayout = new Dictionary>(); - foreach (var bid in m_BuildContent.BundleLayout) - { - var hash = GetAssetsHash(bid.Value, aa); - var newName = $"{bid.Key}_{hash}"; - newBundleLayout.Add(newName, bid.Value); - string assetGroup; - if (aa.bundleToAssetGroup.TryGetValue(bid.Key, out assetGroup)) - { - aa.bundleToAssetGroup.Remove(bid.Key); - aa.bundleToAssetGroup.Add(newName, assetGroup); - } - } - - m_BuildContent.BundleLayout.Clear(); - - foreach (var bid in newBundleLayout) - m_BuildContent.BundleLayout.Add(bid.Key, bid.Value); - return ReturnCode.Success; - } - - internal RawHash GetAssetsHash(List assets, AddressableAssetsBuildContext context) - { - assets.Sort(); - var hashes = new HashSet(); - foreach (var g in assets) - { - AssetLoadInfo assetInfo; - if (m_DependencyData.AssetInfo.TryGetValue(g, out assetInfo)) - { - var diskOnlyReferencedObjects = assetInfo.referencedObjects.Where(ro => context.Settings.FindAssetEntry(ro.guid.ToString()) == null).ToList(); - GetAssetHashes(hashes, g, diskOnlyReferencedObjects, m_Cache != null && m_Parameters.UseCache); - } - } - - return HashingMethods.Calculate(hashes.ToArray()); - } - - void GetAssetHashes(HashSet hashes, GUID g, List referencedObjects, bool useCache) - { - if (useCache) - { - hashes.Add(m_Cache.GetCacheEntry(g, Version).Hash); - foreach (var reference in referencedObjects) - hashes.Add(m_Cache.GetCacheEntry(reference).Hash); - } - else - hashes.Add(AssetDatabase.GetAssetDependencyHash(AssetDatabase.GUIDToAssetPath(g.ToString()))); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.AddressableAssets.Build.DataBuilders; +using UnityEditor.Build.Content; +using UnityEditor.Build.Pipeline; +using UnityEditor.Build.Pipeline.Injector; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEditor.Build.Pipeline.Utilities; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build.BuildPipelineTasks +{ + /// + /// The BuildTask used to append the asset hash to the internal bundle name. + /// + public class AddHashToBundleNameTask : IBuildTask + { + /// + /// The task version. + /// + public int Version + { + get { return 1; } + } + +#pragma warning disable 649 + [InjectContext(ContextUsage.In)] + IBuildParameters m_Parameters; + + [InjectContext(ContextUsage.In)] + IBundleBuildContent m_BuildContent; + + [InjectContext] + IDependencyData m_DependencyData; + + [InjectContext(ContextUsage.InOut, true)] + IBuildSpriteData m_SpriteData; + + [InjectContext(ContextUsage.In)] + IAddressableAssetsBuildContext m_AaBuildContext; + + [InjectContext(ContextUsage.In, true)] + IBuildCache m_Cache; +#pragma warning restore 649 + + /// + /// Runs the AddHashToBundleNameTask. + /// + /// Success. + public ReturnCode Run() + { + var aa = m_AaBuildContext as AddressableAssetsBuildContext; + if (!aa.Settings.UniqueBundleIds) + return ReturnCode.Success; + + var newBundleLayout = new Dictionary>(); + foreach (var bid in m_BuildContent.BundleLayout) + { + var hash = GetAssetsHash(bid.Value, aa); + var newName = $"{bid.Key}_{hash}"; + newBundleLayout.Add(newName, bid.Value); + string assetGroup; + if (aa.bundleToAssetGroup.TryGetValue(bid.Key, out assetGroup)) + { + aa.bundleToAssetGroup.Remove(bid.Key); + aa.bundleToAssetGroup.Add(newName, assetGroup); + } + } + + m_BuildContent.BundleLayout.Clear(); + + foreach (var bid in newBundleLayout) + m_BuildContent.BundleLayout.Add(bid.Key, bid.Value); + return ReturnCode.Success; + } + + internal RawHash GetAssetsHash(List assets, AddressableAssetsBuildContext context) + { + assets.Sort(); + var hashes = new HashSet(); + foreach (var g in assets) + { + AssetLoadInfo assetInfo; + if (m_DependencyData.AssetInfo.TryGetValue(g, out assetInfo)) + { + var diskOnlyReferencedObjects = assetInfo.referencedObjects.Where(ro => context.Settings.FindAssetEntry(ro.guid.ToString()) == null).ToList(); + GetAssetHashes(hashes, g, diskOnlyReferencedObjects, m_Cache != null && m_Parameters.UseCache); + } + } + + return HashingMethods.Calculate(hashes.ToArray()); + } + + void GetAssetHashes(HashSet hashes, GUID g, List referencedObjects, bool useCache) + { + if (useCache) + { + hashes.Add(m_Cache.GetCacheEntry(g, Version).Hash); + foreach (var reference in referencedObjects) + hashes.Add(m_Cache.GetCacheEntry(reference).Hash); + } + else + hashes.Add(AssetDatabase.GetAssetDependencyHash(AssetDatabase.GUIDToAssetPath(g.ToString()))); + } + } +} diff --git a/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs.meta b/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs.meta index a3d00732..417cd5d6 100644 --- a/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs.meta +++ b/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 5d624c3bd70705446adc7ee473ceb159 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 5d624c3bd70705446adc7ee473ceb159 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs b/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs index a952633e..d025dfd6 100644 --- a/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs +++ b/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs @@ -1,1247 +1,1247 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using UnityEditor.AddressableAssets.Build.DataBuilders; -using UnityEditor.AddressableAssets.Build.Layout; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.AddressableAssets.Settings.GroupSchemas; -using UnityEditor.Build.Content; -using UnityEditor.Build.Pipeline; -using UnityEditor.Build.Pipeline.Injector; -using UnityEditor.Build.Pipeline.Interfaces; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.AddressableAssets.ResourceLocators; -using UnityEngine.ResourceManagement.ResourceProviders; -using UnityEngine.ResourceManagement.Util; - -namespace UnityEditor.AddressableAssets.Build.BuildPipelineTasks -{ - /// - /// The BuildTask used to generate the bundle layout. - /// - public class BuildLayoutGenerationTask : IBuildTask - { - const int k_Version = 1; - const bool k_PrettyPrint = false; - - internal static Action s_LayoutCompleteCallback; - - /// - /// The GenerateLocationListsTask version. - /// - public int Version - { - get { return k_Version; } - } - - /// - /// The mapping of the old to new bundle names. - /// - public Dictionary BundleNameRemap - { - get { return m_BundleNameRemap; } - set { m_BundleNameRemap = value; } - } - -#pragma warning disable 649 - [InjectContext(ContextUsage.In)] - IAddressableAssetsBuildContext m_AaBuildContext; - - [InjectContext(ContextUsage.In)] - IBuildParameters m_Parameters; - - [InjectContext] - IBundleWriteData m_WriteData; - - [InjectContext(ContextUsage.In, true)] - IBuildLogger m_Log; - - [InjectContext] - IBuildResults m_Results; - - [InjectContext(ContextUsage.In)] - IDependencyData m_DependencyData; - - [InjectContext(ContextUsage.In)] - IObjectDependencyData m_ObjectDependencyData; - - [InjectContext(ContextUsage.In)] - IBundleBuildResults m_BuildBundleResults; -#pragma warning restore 649 - - internal Dictionary m_BundleNameRemap; - internal AddressablesDataBuilderInput m_AddressablesInput; - internal ContentCatalogData m_ContentCatalogData; - - private bool IsContentUpdateBuild => m_AddressablesInput != null && m_AddressablesInput.PreviousContentState != null; - - internal static string m_LayoutFileName = "buildlayout"; - internal static string m_LayoutFilePath = $"{Addressables.LibraryPath}{m_LayoutFileName}"; - internal static string m_ReportsFilePath = $"{Addressables.BuildReportPath}{m_LayoutFileName}"; - - internal static string GetLayoutFilePathForFormat(ProjectConfigData.ReportFileFormat fileFormat) - { - string ext = (fileFormat == ProjectConfigData.ReportFileFormat.JSON) ? "json" : "txt"; - return $"{m_LayoutFilePath}.{ext}"; - } - - internal static string TimeStampedReportPath(DateTime now) - { - string stringNow = string.Format("{0:D4}.{1:D2}.{2:D2}.{3:D2}.{4:D2}.{5:D2}", now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second); - return $"{m_ReportsFilePath}_{stringNow}.json"; - } - - static AssetBucket GetOrCreate(Dictionary buckets, string asset) - { - if (!buckets.TryGetValue(asset, out AssetBucket bucket)) - { - bucket = new AssetBucket(); - bucket.guid = asset; - buckets.Add(asset, bucket); - } - - return bucket; - } - - class AssetBucket - { - public string guid; - public bool isFilePathBucket; - public List objs = new List(); - public BuildLayout.ExplicitAsset ExplictAsset; - - public ulong CalcObjectSize() - { - ulong sum = 0; - foreach (var obj in objs) - sum += obj.header.size; - return sum; - } - - public ulong CalcStreamedSize() - { - ulong sum = 0; - foreach (var obj in objs) - sum += obj.rawData.size; - return sum; - } - } - - AssetType GetSceneObjectType(string name) - { - if (AssetType.TryParse(name, true, out var rst)) - return rst; - return AssetType.SceneObject; - } - - ulong GetFileSizeFromPath(string path, out bool success) - { - success = false; - FileInfo fileInfo = new FileInfo(path); - if (fileInfo.Exists) - { - success = true; - return (ulong)fileInfo.Length; - } - return 0; - } - - private BuildLayout CreateBuildLayout() - { - AddressableAssetsBuildContext aaContext = (AddressableAssetsBuildContext)m_AaBuildContext; - - LayoutLookupTables lookup = null; - BuildLayout result = null; - using (m_Log.ScopedStep(LogLevel.Info, "Generate Lookup tables")) - lookup = GenerateLookupTables(aaContext); - using (m_Log.ScopedStep(LogLevel.Info, "Generate Build Layout")) - result = GenerateBuildLayout(aaContext, lookup); - return result; - } - - private LayoutLookupTables GenerateLookupTables(AddressableAssetsBuildContext aaContext) - { - LayoutLookupTables lookup = new LayoutLookupTables(); - - Dictionary objectTypes = new Dictionary(1024); - foreach (KeyValuePair assetResult in m_Results.AssetResults) - { - foreach (var resultEntry in assetResult.Value.ObjectTypes) - { - if (!objectTypes.ContainsKey(resultEntry.Key)) - objectTypes.Add(resultEntry.Key, resultEntry.Value); - } - } - - foreach (string bundleName in m_WriteData.FileToBundle.Values.Distinct()) - { - BuildLayout.Bundle bundle = new BuildLayout.Bundle(); - if (m_BuildBundleResults.BundleInfos.TryGetValue(bundleName, out var info)) - { - bundle.CRC = info.Crc; - bundle.Hash = info.Hash; - } - - bundle.Name = bundleName; - UnityEngine.BuildCompression compression = m_Parameters.GetCompressionForIdentifier(bundle.Name); - bundle.Compression = compression.compression.ToString(); - lookup.Bundles.Add(bundleName, bundle); - } - - foreach (BuildLayout.Bundle b in lookup.Bundles.Values) - { - if (aaContext.bundleToImmediateBundleDependencies.TryGetValue(b.Name, out List deps)) - b.Dependencies = deps.Select(x => lookup.Bundles[x]).Where(x => b != x).ToList(); - if (aaContext.bundleToExpandedBundleDependencies.TryGetValue(b.Name, out List deps2)) - b.ExpandedDependencies = deps2.Select(x => lookup.Bundles[x]).Where(x => b != x).ToList(); - } - - // create files - foreach (KeyValuePair fileBundle in m_WriteData.FileToBundle) - { - BuildLayout.Bundle bundle = lookup.Bundles[fileBundle.Value]; - BuildLayout.File f = new BuildLayout.File(); - f.Name = fileBundle.Key; - f.Bundle = bundle; - - WriteResult result = m_Results.WriteResults[f.Name]; - foreach (ResourceFile rf in result.resourceFiles) - { - var sf = new BuildLayout.SubFile(); - sf.IsSerializedFile = rf.serializedFile; - sf.Name = rf.fileAlias; - sf.Size = GetFileSizeFromPath(rf.fileName, out bool success); - if (!success) - Debug.LogWarning($"Resource File {sf.Name} from file \"{f.Name}\" was detected as part of the build, but the file could not be found. This may be because your build cache size is too small. Filesize of this Resource File will be 0 in BuildLayout."); - - f.SubFiles.Add(sf); - } - - bundle.Files.Add(f); - lookup.Files.Add(f.Name, f); - } - - // create assets - foreach (KeyValuePair> assetFile in m_WriteData.AssetToFiles) - { - BuildLayout.File file = lookup.Files[assetFile.Value[0]]; - BuildLayout.ExplicitAsset a = new BuildLayout.ExplicitAsset(); - a.Guid = assetFile.Key.ToString(); - a.AssetPath = AssetDatabase.GUIDToAssetPath(a.Guid); - a.File = file; - a.Bundle = file.Bundle; - file.Assets.Add(a); - lookup.GuidToExplicitAsset.Add(a.Guid, a); - } - - Dictionary> guidToPulledInBuckets = - new Dictionary>(); - - foreach (BuildLayout.File file in lookup.Files.Values) - { - Dictionary buckets = new Dictionary(); - WriteResult writeResult = m_Results.WriteResults[file.Name]; - List sceneObjects = new List(); - FileObjectData fData = new FileObjectData(); - lookup.FileToFileObjectData.Add(file, fData); - - foreach (ObjectSerializedInfo info in writeResult.serializedObjects) - { - if (info.serializedObject.guid.Empty()) - { - if (info.serializedObject.filePath.Equals("temp:/assetbundle", StringComparison.OrdinalIgnoreCase)) - { - file.BundleObjectInfo = new BuildLayout.AssetBundleObjectInfo(); - file.BundleObjectInfo.Size = info.header.size; - continue; - } - else if (info.serializedObject.filePath.StartsWith("temp:/preloaddata", - StringComparison.OrdinalIgnoreCase)) - { - file.PreloadInfoSize = (int)info.header.size; - continue; - } - else if (info.serializedObject.filePath.StartsWith("temp:/", StringComparison.OrdinalIgnoreCase)) - { - sceneObjects.Add(info); - continue; - } - else if (!string.IsNullOrEmpty(info.serializedObject.filePath)) - { - AssetBucket pathBucket = GetOrCreate(buckets, info.serializedObject.filePath.ToString()); - pathBucket.isFilePathBucket = true; - pathBucket.objs.Add(info); - continue; - } - } - - AssetBucket bucket = GetOrCreate(buckets, info.serializedObject.guid.ToString()); - bucket.objs.Add(info); - } - - if (sceneObjects.Count > 0) - { - BuildLayout.ExplicitAsset sceneAsset = file.Assets.First(x => x.AssetPath.EndsWith(".unity", StringComparison.OrdinalIgnoreCase)); - AssetBucket bucket = GetOrCreate(buckets, sceneAsset.Guid); - bucket.objs.AddRange(sceneObjects); - } - - // Update buckets with a reference to their explicit asset - file.Assets.ForEach(eAsset => - { - if (!buckets.TryGetValue(eAsset.Guid, out AssetBucket b)) - b = GetOrCreate(buckets, eAsset.Guid); // some assets might not pull in any objects - b.ExplictAsset = eAsset; - }); - - // Create entries for buckets that are implicitly pulled in - Dictionary guidToOtherData = new Dictionary(); - Dictionary> guidToObjectNames = new Dictionary>(); - int assetInFileId = 0; - HashSet MonoScriptAssets = new HashSet(); - - foreach (AssetBucket bucket in buckets.Values.Where(x => x.ExplictAsset == null)) - { - string assetPath = bucket.isFilePathBucket ? bucket.guid : AssetDatabase.GUIDToAssetPath(bucket.guid); - if (assetPath.EndsWith(".cs", StringComparison.OrdinalIgnoreCase) || - assetPath.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) - { - file.MonoScriptCount++; - file.MonoScriptSize += bucket.CalcObjectSize(); - MonoScriptAssets.Add(bucket.guid); - continue; - } - - var implicitAsset = new BuildLayout.DataFromOtherAsset(); - implicitAsset.AssetPath = assetPath; - implicitAsset.AssetGuid = bucket.guid; - implicitAsset.SerializedSize = bucket.CalcObjectSize(); - implicitAsset.StreamedSize = bucket.CalcStreamedSize(); - implicitAsset.ObjectCount = bucket.objs.Count; - implicitAsset.File = file; - assetInFileId = file.OtherAssets.Count; - file.OtherAssets.Add(implicitAsset); - - if (lookup.UsedImplicits.TryGetValue(implicitAsset.AssetGuid, out var dataList)) - dataList.Add(implicitAsset); - else - lookup.UsedImplicits.Add(implicitAsset.AssetGuid, new List(){implicitAsset}); - - guidToOtherData[implicitAsset.AssetGuid] = implicitAsset; - - if (lookup.AssetPathToTypeMap.ContainsKey(implicitAsset.AssetPath)) - implicitAsset.MainAssetType = lookup.AssetPathToTypeMap[implicitAsset.AssetPath]; - else - { - implicitAsset.MainAssetType = BuildLayoutHelpers.GetAssetType(AssetDatabase.GetMainAssetTypeAtPath(implicitAsset.AssetPath)); - lookup.AssetPathToTypeMap[implicitAsset.AssetPath] = implicitAsset.MainAssetType; - } - - Dictionary localIdentifierToObjectName; - if (!guidToObjectNames.TryGetValue(bucket.guid, out localIdentifierToObjectName)) - { - localIdentifierToObjectName = GetObjectsIdForAsset(assetPath); - guidToObjectNames.Add(bucket.guid, localIdentifierToObjectName); - } - - foreach (ObjectSerializedInfo bucketObj in bucket.objs) - { - Type objType = null; - if (objectTypes.TryGetValue(bucketObj.serializedObject, out Type[] types) && types.Length > 0) - objType = types[0]; - - AssetType eType = objType == null ? AssetType.Other : BuildLayoutHelpers.GetAssetType(objType); - if (implicitAsset.IsScene) - { - if (eType == AssetType.Other) - eType = AssetType.SceneObject; - } - - string name = ""; - if (localIdentifierToObjectName.TryGetValue(bucketObj.serializedObject.localIdentifierInFile, out string value)) - name = value; - BuildLayout.ObjectData layoutObject = new BuildLayout.ObjectData() - { - ObjectName = name, - LocalIdentifierInFile = bucketObj.serializedObject.localIdentifierInFile, - AssetType = eType, - SerializedSize = bucketObj.header.size, - StreamedSize = bucketObj.rawData.size - }; - - int objectIndex = implicitAsset.Objects.Count; - implicitAsset.Objects.Add(layoutObject); - fData.Add(bucketObj.serializedObject, layoutObject, assetInFileId, objectIndex); - } - - if (!guidToPulledInBuckets.TryGetValue(implicitAsset.AssetGuid, - out List bucketList)) - bucketList = guidToPulledInBuckets[implicitAsset.AssetGuid] = new List(); - bucketList.Add(implicitAsset); - } - - assetInFileId = file.OtherAssets.Count - 1; - foreach (BuildLayout.ExplicitAsset asset in file.Assets) - { - assetInFileId++; - AssetBucket bucket = buckets[asset.Guid]; - GUID.TryParse(asset.Guid, out GUID guid); - - // size info - asset.SerializedSize = bucket.CalcObjectSize(); - asset.StreamedSize = bucket.CalcStreamedSize(); - - // asset hash - if (m_Results.AssetResults.TryGetValue(guid, out var data)) - asset.AssetHash = data.Hash; - - // asset type - if (lookup.AssetPathToTypeMap.ContainsKey(asset.AssetPath)) - asset.MainAssetType = lookup.AssetPathToTypeMap[asset.AssetPath]; - else - { - System.Type type = AssetDatabase.GetMainAssetTypeAtPath(asset.AssetPath); - asset.MainAssetType = BuildLayoutHelpers.GetAssetType(type); - lookup.AssetPathToTypeMap[asset.AssetPath] = asset.MainAssetType; - } - - if (asset.MainAssetType == AssetType.GameObject) - { -#if UNITY_2022_2_OR_NEWER - Type importerType = AssetDatabase.GetImporterType(asset.AssetPath); - if (importerType == typeof(ModelImporter)) - asset.MainAssetType = AssetType.Model; - else if (importerType != null) -#endif - asset.MainAssetType = AssetType.Prefab; - } - - if (asset.IsScene) - { - CollectObjectsForScene(bucket, asset); - } - else - { - Dictionary localIdentifierToObjectName; - if (!guidToObjectNames.TryGetValue(bucket.guid, out localIdentifierToObjectName)) - { - localIdentifierToObjectName = GetObjectsIdForAsset(asset.AssetPath); - guidToObjectNames.Add(bucket.guid, localIdentifierToObjectName); - } - - CollectObjectsForAsset(bucket, objectTypes, asset, localIdentifierToObjectName, fData, assetInFileId); - } - } - - HashSet explicitAssetsAddedAsExternal = new HashSet(); - // Add references - foreach (BuildLayout.ExplicitAsset asset in file.Assets) - { - IEnumerable refs = null; - if (m_DependencyData.AssetInfo.TryGetValue(new GUID(asset.Guid), out AssetLoadInfo info)) - refs = info.referencedObjects; - else - refs = m_DependencyData.SceneInfo[new GUID(asset.Guid)].referencedObjects; - - foreach (string refGUID in refs.Select(x => x.guid.Empty() ? x.filePath : x.guid.ToString()).Distinct()) - { - if (MonoScriptAssets.Contains(refGUID)) - continue; - if (guidToOtherData.TryGetValue(refGUID, out BuildLayout.DataFromOtherAsset dfoa)) - { - dfoa.ReferencingAssets.Add(asset); - asset.InternalReferencedOtherAssets.Add(dfoa); - } - else if (buckets.TryGetValue(refGUID, out AssetBucket refBucket) && refBucket.ExplictAsset != null) - { - refBucket.ExplictAsset.ReferencingAssets.Add(asset); - asset.InternalReferencedExplicitAssets.Add(refBucket.ExplictAsset); - } - else if (lookup.GuidToExplicitAsset.TryGetValue(refGUID, out BuildLayout.ExplicitAsset refAsset)) - { - refAsset.ReferencingAssets.Add(asset); - asset.ExternallyReferencedAssets.Add(refAsset); - if (explicitAssetsAddedAsExternal.Add(refAsset)) - file.ExternalReferences.Add(refAsset); - } - } - } - } - - foreach (BuildLayout.File file in lookup.Files.Values) - { - if (lookup.FileToFileObjectData.TryGetValue(file, out FileObjectData fData)) - { - foreach (BuildLayout.ExplicitAsset asset in file.Assets) - { - if (asset.IsScene && asset.Objects.Count > 0) - { - BuildLayout.ObjectData objectData = asset.Objects[0]; - IEnumerable dependencies = m_DependencyData.SceneInfo[new GUID(asset.Guid)].referencedObjects; - CollectObjectReferences(fData, objectData, file, lookup, dependencies); - } - else - { - foreach (BuildLayout.ObjectData objectData in asset.Objects) - CollectObjectReferences(fData, objectData, file, lookup); - } - } - - foreach (var otherAsset in file.OtherAssets) - { - foreach (BuildLayout.ObjectData objectData in otherAsset.Objects) - { - // TODO see if theres a cached result for this - CollectObjectReferences(fData, objectData, file, lookup); - } - } - } - } - - return lookup; - } - - private static Dictionary GetObjectsIdForAsset(string assetPath) - { - Dictionary localIdentifierToObjectName = new Dictionary(); - var prop = new HierarchyProperty(assetPath, false); - if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(prop.instanceID, out _, out long mainLocalID)) - { - localIdentifierToObjectName[mainLocalID] = prop.name; - if (prop.hasChildren) - { - while (prop.Next(Array.Empty())) - { - if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(prop.instanceID, out _, out long localID)) - localIdentifierToObjectName[localID] = prop.name; - } - } - } - return localIdentifierToObjectName; - } - - private void CollectObjectsForAsset(in AssetBucket bucket, in Dictionary objectTypes, BuildLayout.ExplicitAsset asset, - in Dictionary localIdentifierToObjectName, FileObjectData fileObjectData, int assetInFileId) - { - foreach (ObjectSerializedInfo bucketObj in bucket.objs) - { - Type objType = null; - if (objectTypes.TryGetValue(bucketObj.serializedObject, out Type[] types) && types.Length > 0) - objType = types[0]; - - AssetType eType = objType == null ? AssetType.Other : BuildLayoutHelpers.GetAssetType(objType); - if (IsComponentType(eType)) - eType = AssetType.Component; - string componentName = ""; - - if (asset.IsScene && (eType == AssetType.Other || eType == AssetType.Component)) - eType = GetSceneObjectType(bucketObj.serializedObject.filePath.Remove(0, 6)); - if (eType == AssetType.Component) - componentName = objType.Name; - - string name = ""; - if (localIdentifierToObjectName.TryGetValue(bucketObj.serializedObject.localIdentifierInFile, out string value)) - name = value; - - BuildLayout.ObjectData layoutObject = new BuildLayout.ObjectData() - { - ObjectName = name, - ComponentName = componentName, - LocalIdentifierInFile = bucketObj.serializedObject.localIdentifierInFile, - AssetType = eType, - SerializedSize = bucketObj.header.size, - StreamedSize = bucketObj.rawData.size - }; - - int objectIndex = asset.Objects.Count; - asset.Objects.Add(layoutObject); - fileObjectData.Add(bucketObj.serializedObject, layoutObject, assetInFileId, objectIndex); - } - } - - private static bool IsComponentType(AssetType eType) - { - if (eType == AssetType.Transform || - eType == AssetType.GameObject || - eType == AssetType.Camera || - eType == AssetType.Light || - eType == AssetType.MeshFilter || - eType == AssetType.MeshRenderer || - eType == AssetType.SphereCollider || - eType == AssetType.AudioListener || - eType == AssetType.BoxCollider || - eType == AssetType.BoxCollider2D - || - eType == AssetType.MonoBehaviour) - { - // old components that should not have been in the enum, treat all as component type - return true; - } - - return false; - } - - private void CollectObjectsForScene(in AssetBucket bucket, BuildLayout.ExplicitAsset asset) - { - Dictionary TypeToObjectData = new Dictionary(); - foreach (ObjectSerializedInfo bucketObj in bucket.objs) - { - AssetType eType = GetSceneObjectType(bucketObj.serializedObject.filePath.Remove(0, 6)); - if (!TypeToObjectData.TryGetValue(eType, out BuildLayout.ObjectData layoutObject)) - { - layoutObject = new BuildLayout.ObjectData() - { - ObjectName = eType.ToString(), - LocalIdentifierInFile = TypeToObjectData.Count + 1, - AssetType = eType, - SerializedSize = bucketObj.header.size, - StreamedSize = bucketObj.rawData.size - }; - TypeToObjectData.Add(eType, layoutObject); - } - else - { - layoutObject.SerializedSize += bucketObj.header.size; - layoutObject.StreamedSize += bucketObj.rawData.size; - } - } - - // main scene object - asset.Objects.Add(new BuildLayout.ObjectData() - { - ObjectName = "Main", - LocalIdentifierInFile = 0, - AssetType = AssetType.SceneObject, - SerializedSize = 0, - StreamedSize = 0 - }); - - foreach (BuildLayout.ObjectData layoutObject in TypeToObjectData.Values) - { - asset.Objects.Add(layoutObject); - } - } - - private void CollectObjectReferences(FileObjectData fileObjectLookup, BuildLayout.ObjectData objectData, BuildLayout.File fileData, LayoutLookupTables lookup, - IEnumerable dependencies = null) - { - // get the ObjectIdentification object for the objectData - if (dependencies == null && fileObjectLookup.TryGetObjectIdentifier(objectData, out var objId)) - { - m_ObjectDependencyData.ObjectDependencyMap.TryGetValue(objId, out List dependenciesFromMap); - dependencies = dependenciesFromMap; - } - - if (dependencies != null) - { - int assetIdOffset = fileData.Assets.Count + fileData.OtherAssets.Count; - Dictionary> assetIndices = new Dictionary>(); // TODO I don't like this is allocated so much - HashSet indices; - foreach (ObjectIdentifier dependency in dependencies) - { - if (fileObjectLookup.TryGetObjectReferenceData(dependency, out (int, int)val)) - { - // object dependency within this file was found - if (assetIndices.TryGetValue(val.Item1, out indices)) - indices.Add(val.Item2); - else - assetIndices[val.Item1] = new HashSet(){val.Item2}; - } - else // if not in fileObjectLookup, not a dependency on this file, need to find in another file - { - if (lookup.GuidToExplicitAsset.TryGetValue(dependency.guid.ToString(), out BuildLayout.ExplicitAsset referencedAsset)) - { - var otherFData = lookup.FileToFileObjectData[referencedAsset.File]; - if (otherFData.TryGetObjectReferenceData(dependency, out val)) - { - val.Item1 = -1; - for (int i = 0; i < fileData.ExternalReferences.Count; ++i) - { - if (fileData.ExternalReferences[i] == referencedAsset) - { - val.Item1 = i + assetIdOffset; - break; - } - } - - if (val.Item1 >= 0) - { - if (assetIndices.TryGetValue(val.Item1, out indices)) - indices.Add(val.Item2); - else - assetIndices[val.Item1] = new HashSet(){val.Item2}; - } - } - } // can be false for built in shared bundles - } - } - - foreach (KeyValuePair> assetRefData in assetIndices) - { - objectData.References.Add(new BuildLayout.ObjectReference() {AssetId = assetRefData.Key, ObjectIds = new List(assetRefData.Value)}); - } - } - } - - private BuildLayout GenerateBuildLayout(AddressableAssetsBuildContext aaContext, LayoutLookupTables lookup) - { - BuildLayout layout = new BuildLayout(); - layout.BuildStart = aaContext.buildStartTime; - - layout.LocalCatalogBuildPath = aaContext.Settings.DefaultGroup.GetSchema().BuildPath.GetValue(aaContext.Settings); - layout.RemoteCatalogBuildPath = aaContext.Settings.RemoteCatalogBuildPath.GetValue(aaContext.Settings); - - AddressableAssetSettings aaSettings = aaContext.Settings; - if (m_ContentCatalogData != null) - layout.BuildResultHash = m_ContentCatalogData.m_BuildResultHash; - - using (m_Log.ScopedStep(LogLevel.Info, "Generate Basic Information")) - { - SetLayoutMetaData(layout, aaSettings); - layout.AddressablesEditorSettings = GetAddressableEditorSettings(aaSettings); - layout.AddressablesRuntimeSettings = GetAddressableRuntimeSettings(aaContext, m_ContentCatalogData); - } - - if (IsContentUpdateBuild) - layout.BuildType = BuildType.UpdateBuild; - else - layout.BuildType = BuildType.NewBuild; - - // Map from GUID to AddrssableAssetEntry - lookup.GuidToEntry = aaContext.assetEntries.ToDictionary(x => x.guid, x => x); - - // create groups - foreach (AddressableAssetGroup group in aaSettings.groups) - { - if (group.Name != group.name) - { - Debug.LogWarningFormat( - "Group name in settings does not match name in group asset, reset group name: \"{0}\" to \"{1}\"", - group.name, group.Name); - group.name = group.Name; - } - - var grp = new BuildLayout.Group(); - grp.Name = group.Name; - grp.Guid = group.Guid; - if (group.IsDefaultGroup()) - layout.DefaultGroup = grp; - - foreach (AddressableAssetGroupSchema schema in group.Schemas) - { - var sd = GenerateSchemaData(schema, aaSettings); - - BundledAssetGroupSchema bSchema = schema as BundledAssetGroupSchema; - if (bSchema != null) - { - for (int i = 0; i < sd.KvpDetails.Count; ++i) - { - if (sd.KvpDetails[i].Item1 == "BundleMode") - { - string modeStr = bSchema.BundleMode.ToString(); - sd.KvpDetails[i] = new Tuple("PackingMode", modeStr); - grp.PackingMode = modeStr; - break; - } - } - - lookup.GroupNameToBuildPath[group.name] = bSchema.BuildPath.GetValue(aaSettings); - } - - grp.Schemas.Add(sd); - } - - lookup.GroupLookup.Add(group.Guid, grp); - layout.Groups.Add(grp); - } - - // Create a lookup for bundle update states - foreach (ContentCatalogDataEntry entry in aaContext.locations) - { - if (entry.Data is AssetBundleRequestOptions options) - { - lookup.BundleNameToRequestOptions.Add(options.BundleName, options); - lookup.BundleNameToCatalogEntry.Add(options.BundleName, entry); - } - } - - if (IsContentUpdateBuild) - { - foreach (CachedBundleState prevState in m_AddressablesInput.PreviousContentState.cachedBundles) - { - if (prevState.data is AssetBundleRequestOptions options) - lookup.BundleNameToPreviousRequestOptions.Add(options.BundleName, options); - } - } - - using (m_Log.ScopedStep(LogLevel.Info, "Correlate Bundles to groups")) - { - foreach (BuildLayout.Bundle b in lookup.Bundles.Values) - CorrelateBundleToAssetGroup(layout, b, lookup, aaContext); - } - - using (m_Log.ScopedStep(LogLevel.Info, "Apply Addressable info to layout data")) - ApplyAddressablesInformationToExplicitAssets(layout, lookup); - using (m_Log.ScopedStep(LogLevel.Info, "Process additional bundle data")) - PostProcessBundleData(lookup); - using (m_Log.ScopedStep(LogLevel.Info, "Generating implicit inclusion data")) - AddImplicitAssetsToLayout(lookup, layout); - - SetDuration(layout); - return layout; - } - - BuildLayout.SchemaData GenerateSchemaData(AddressableAssetGroupSchema schema, AddressableAssetSettings aaSettings) - { - var sd = new BuildLayout.SchemaData(); - sd.Guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(schema)); - Type schemaType = schema.GetType(); - sd.Type = schemaType.Name; - - var properties = schemaType.GetProperties(); - - foreach (PropertyInfo property in properties) - { - if (!property.PropertyType.IsSerializable || !property.CanRead) - continue; - string propertyName = property.Name; - if (propertyName == "name" || propertyName == "hideFlags") - continue; - - if (property.PropertyType.IsPrimitive || property.PropertyType.IsEnum) - { - object propertyObject = property.GetValue(schema); - if (propertyObject != null) - sd.KvpDetails.Add(new Tuple(propertyName, propertyObject.ToString())); - } - else if (property.PropertyType == typeof(string)) - { - if (property.GetValue(schema) is string stringValue) - sd.KvpDetails.Add(new Tuple(propertyName, stringValue)); - } - else if (property.PropertyType == typeof(SerializedType)) - { - SerializedType serializeTypeValue = (SerializedType)property.GetValue(schema); - sd.KvpDetails.Add(new Tuple(propertyName, serializeTypeValue.ClassName)); - } - else if (property.PropertyType == typeof(ProfileValueReference)) - { - if (property.GetValue(schema) is ProfileValueReference profileValue) - sd.KvpDetails.Add( - new Tuple(propertyName, profileValue.GetValue(aaSettings))); - } - } - - return sd; - } - - void CorrelateBundleToAssetGroup(BuildLayout layout, BuildLayout.Bundle b, LayoutLookupTables lookup, AddressableAssetsBuildContext aaContext) - { - int indexFrom = b.Name.IndexOf(".bundle", StringComparison.Ordinal); - string nameWithoutExtension = indexFrom > 0 ? b.Name.Remove(indexFrom) : b.Name; - b.InternalName = nameWithoutExtension; - if (aaContext.bundleToAssetGroup.TryGetValue(b.Name, out var grpName)) - { - var assetGroup = lookup.GroupLookup[grpName]; - b.Name = m_BundleNameRemap[b.Name]; - b.Group = assetGroup; - lookup.FilenameToBundle[b.Name] = b; - var filePath = Path.Combine(lookup.GroupNameToBuildPath[assetGroup.Name], b.Name); - - b.FileSize = GetFileSizeFromPath(filePath, out bool success); - if (!success) - Debug.LogWarning($"AssetBundle {b.Name} from Addressable Group \"{assetGroup.Name}\" was detected as part of the build, but the file could not be found. Filesize of this AssetBundle will be 0 in BuildLayout."); - - assetGroup.Bundles.Add(b); - } - else - { - // bundleToAssetGroup doesn't contain the builtin bundles. The builtin content is built using values from the default group - AddressableAssetGroup defaultGroup = aaContext.Settings.DefaultGroup; - b.Name = m_BundleNameRemap[b.Name]; - b.Group = lookup.GroupLookup[defaultGroup.Guid]; // should this be set? - lookup.FilenameToBundle[b.Name] = b; - - b.FileSize = GetFileSizeFromPath(Path.Combine(lookup.GroupNameToBuildPath[defaultGroup.Name], b.Name), out bool success); - if (!success) - Debug.LogWarning($"Built in assetBundle {b.Name} was detected as part of the build, but the file could not be found. Filesize of this AssetBundle will be 0 in BuildLayout."); - - layout.BuiltInBundles.Add(b); - } - } - - void PostProcessBundleData(LayoutLookupTables lookup) - { - HashSet rootBundles = new HashSet(lookup.Bundles.Values); - foreach (BuildLayout.Bundle b in lookup.Bundles.Values) - { - SetBundleDataFromCatalogEntry(b, lookup); - GenerateBundleDependencyAndEfficiencyInformation(b, rootBundles); - } - - CalculateBundleEfficiencies(rootBundles); - } - - internal static void CalculateBundleEfficiencies(IEnumerable rootBundles) - { - Dictionary bundleDependencyCache = new Dictionary(); - foreach (BuildLayout.Bundle b in rootBundles) - CalculateEfficiency(b, bundleDependencyCache); - } - - /// - /// Calculates the Efficiency of bundle and all bundles below it in the dependency tree and caches the results. - /// Example: There are 3 bundles A, B, and C, that are each 10 MB on disk. A depends on 2 MB worth of assets in B, and B depends on 4 MB worth of assets in C. - /// The Efficiency of the dependencyLink from A->B would be 2/10 -> 20% and the ExpandedEfficiency of A->B would be (2 + 4)/(10 + 10) -> 6/20 -> 30% - /// - /// the root of the dependency tree that the CalculateEfficiency call will start from. - /// Cache of all bundle dependencies that have already been calculated - internal static void CalculateEfficiency(BuildLayout.Bundle bundle, Dictionary bundleDependencyCache = null) - { - Stack stk = new Stack(); - Queue q = new Queue(); - HashSet seenBundles = new HashSet(); - - if (bundleDependencyCache == null) - bundleDependencyCache = new Dictionary(); - - q.Enqueue(bundle); - - // Populate the stack of BundleDependencies with the lowest depth BundleDependencies being at the top of the stack - while (q.Count > 0) - { - var curBundle = q.Dequeue(); - foreach (var bd in curBundle.BundleDependencies) - { - if (bundleDependencyCache.ContainsKey(bd)) - break; - - if (!seenBundles.Contains(curBundle)) - { - q.Enqueue(bd.DependencyBundle); - stk.Push(bd); - } - } - seenBundles.Add(curBundle); - } - - // Get the required information out of each BundleDependency, caching the necessary info for each as you work your way up the tree - while (stk.Count > 0) - { - var curBd = stk.Pop(); - - ulong totalReferencedAssetFilesize = 0; - ulong totalDependentAssetFilesize = 0; - foreach (var bd in curBd.DependencyBundle.BundleDependencies) - { - if (bundleDependencyCache.TryGetValue(bd, out var ei)) - { - totalReferencedAssetFilesize += ei.referencedAssetFileSize; - totalDependentAssetFilesize += ei.totalAssetFileSize; - } - } - - var newEfficiencyInfo = new BuildLayout.Bundle.EfficiencyInfo() - { - referencedAssetFileSize = curBd.referencedAssetsFileSize + totalReferencedAssetFilesize, - totalAssetFileSize = curBd.DependencyBundle.FileSize + totalDependentAssetFilesize, - }; - - curBd.Efficiency = newEfficiencyInfo.totalAssetFileSize > 0 ? (float)curBd.referencedAssetsFileSize / curBd.DependencyBundle.FileSize : 1f; - curBd.ExpandedEfficiency = newEfficiencyInfo.totalAssetFileSize > 0 ? (float)newEfficiencyInfo.referencedAssetFileSize / newEfficiencyInfo.totalAssetFileSize : 1f; - bundleDependencyCache[curBd] = newEfficiencyInfo; - } - } - - void SetBundleDataFromCatalogEntry(BuildLayout.Bundle b, LayoutLookupTables lookup) - { - if (lookup.BundleNameToCatalogEntry.TryGetValue(b.InternalName, out var entry)) - { - b.LoadPath = entry.InternalId; - b.Provider = entry.Provider; - b.ResultType = entry.ResourceType.Name; - } - - if (lookup.BundleNameToPreviousRequestOptions.TryGetValue(b.InternalName, out var prevOptions)) - { - if (m_BuildBundleResults.BundleInfos.TryGetValue(b.Name, out var currentBundleDetails)) - { - if (currentBundleDetails.Hash.ToString() != prevOptions.Hash) - { - b.BuildStatus = BundleBuildStatus.Modified; - if (entry?.Data is AssetBundleRequestOptions currentOptions) - if (currentOptions.Hash == prevOptions.Hash) - b.BuildStatus = BundleBuildStatus.ModifiedUpdatePrevented; - } - else - { - b.BuildStatus = BundleBuildStatus.Unmodified; - } - } - } - } - - void ApplyAddressablesInformationToExplicitAssets(BuildLayout layout, LayoutLookupTables lookup) - { - HashSet loadPathsForBundle = new HashSet(); - foreach (var bundle in BuildLayoutHelpers.EnumerateBundles(layout)) - { - loadPathsForBundle.Clear(); - for (int fileIndex = 0; fileIndex < bundle.Files.Count; ++fileIndex) - { - foreach (BuildLayout.ExplicitAsset rootAsset in bundle.Files[fileIndex].Assets) - { - if (lookup.GuidToEntry.TryGetValue(rootAsset.Guid, out AddressableAssetEntry rootEntry)) - { - ApplyAddressablesInformationToExplicitAsset(lookup, rootAsset, rootEntry, loadPathsForBundle); - } - } - } - } - } - - private static void ApplyAddressablesInformationToExplicitAsset(LayoutLookupTables lookup, BuildLayout.ExplicitAsset rootAsset, AddressableAssetEntry rootEntry, HashSet loadPathsForBundle) - { - rootAsset.AddressableName = rootEntry.address; - rootAsset.MainAssetType = BuildLayoutHelpers.GetAssetType(rootEntry.MainAssetType); - rootAsset.InternalId = rootEntry.GetAssetLoadPath(true, loadPathsForBundle); - rootAsset.Labels = new string[rootEntry.labels.Count]; - rootEntry.labels.CopyTo(rootAsset.Labels); - rootAsset.GroupGuid = rootEntry.parentGroup.Guid; - - if (rootAsset.Bundle == null) - { - Debug.LogError($"Failed to get bundle information for AddressableAssetEntry: {rootEntry.AssetPath}"); - return; - } - - foreach (BuildLayout.ExplicitAsset referencedAsset in rootAsset.ExternallyReferencedAssets) - { - if (referencedAsset.Bundle == null) - { - Debug.LogError($"Failed to get bundle information for AddressableAssetEntry: {rootEntry.AssetPath}"); - continue; - } - - // Create the dependency between rootAssets bundle and referenced Assets bundle, - rootAsset.Bundle.UpdateBundleDependency(rootAsset, referencedAsset); - } - } - - void GenerateBundleDependencyAndEfficiencyInformation(BuildLayout.Bundle b, HashSet rootBundles) - { - b.ExpandedDependencyFileSize = 0; - b.DependencyFileSize = 0; - foreach (var dependency in b.Dependencies) - { - dependency.DependentBundles.Add(b); - rootBundles.Remove(dependency); - b.DependencyFileSize += dependency.FileSize; - } - - foreach (var expandedDependency in b.ExpandedDependencies) - b.ExpandedDependencyFileSize += expandedDependency.FileSize; - - foreach (var file in b.Files) - b.AssetCount += file.Assets.Count; - - b.SerializeBundleToBundleDependency(); - } - - void AddImplicitAssetsToLayout(LayoutLookupTables lookup, BuildLayout layout) - { - foreach (KeyValuePair> pair in lookup.UsedImplicits) - { - if (pair.Value.Count <= 1) - continue; - - BuildLayout.AssetDuplicationData assetDuplication = new BuildLayout.AssetDuplicationData(); - assetDuplication.AssetGuid = pair.Key; - bool hasDuplicatedObjects = false; - - foreach (BuildLayout.DataFromOtherAsset implicitData in pair.Value) - { - foreach (BuildLayout.ObjectData objectData in implicitData.Objects) - { - var existing = assetDuplication.DuplicatedObjects.Find(data => data.LocalIdentifierInFile == objectData.LocalIdentifierInFile); - if (existing != null) - existing.IncludedInBundleFiles.Add(implicitData.File); - else - { - assetDuplication.DuplicatedObjects.Add( - new BuildLayout.ObjectDuplicationData() - { - IncludedInBundleFiles = new List {implicitData.File}, - LocalIdentifierInFile = objectData.LocalIdentifierInFile - }); - hasDuplicatedObjects = true; - } - } - } - - if (!hasDuplicatedObjects) - continue; - - for (int i = assetDuplication.DuplicatedObjects.Count - 1; i >= 0; --i) - { - if (assetDuplication.DuplicatedObjects[i].IncludedInBundleFiles.Count <= 1) - assetDuplication.DuplicatedObjects.RemoveAt(i); - } - - if (assetDuplication.DuplicatedObjects.Count > 0) - layout.DuplicatedAssets.Add(assetDuplication); - } - } - - private static void SetDuration(BuildLayout layout) - { - var duration = DateTime.Now - layout.BuildStart; - layout.Duration = duration.TotalSeconds; - } - - static BuildLayout.AddressablesEditorData GetAddressableEditorSettings(AddressableAssetSettings aaSettings) - { - BuildLayout.AddressablesEditorData editorSettings = new BuildLayout.AddressablesEditorData(); - editorSettings.SettingsHash = aaSettings.currentHash.ToString(); - - editorSettings.DisableSubAssetRepresentations = aaSettings.DisableVisibleSubAssetRepresentations; - editorSettings.MaxConcurrentWebRequests = aaSettings.MaxConcurrentWebRequests; - editorSettings.NonRecursiveBuilding = aaSettings.NonRecursiveBuilding; - editorSettings.ContiguousBundles = aaSettings.ContiguousBundles; - editorSettings.UniqueBundleIds = aaSettings.UniqueBundleIds; - - if (aaSettings.ShaderBundleNaming == ShaderBundleNaming.Custom) - editorSettings.ShaderBundleNaming = aaSettings.ShaderBundleCustomNaming; - else - editorSettings.ShaderBundleNaming = aaSettings.ShaderBundleNaming.ToString(); - if (aaSettings.MonoScriptBundleNaming == MonoScriptBundleNaming.Custom) - editorSettings.MonoScriptBundleNaming = aaSettings.MonoScriptBundleCustomNaming; - else - editorSettings.MonoScriptBundleNaming = aaSettings.MonoScriptBundleNaming.ToString(); - editorSettings.StripUnityVersionFromBundleBuild = aaSettings.StripUnityVersionFromBundleBuild; - - editorSettings.BuildRemoteCatalog = aaSettings.BuildRemoteCatalog; - if (aaSettings.BuildRemoteCatalog) - editorSettings.RemoteCatalogLoadPath = aaSettings.RemoteCatalogLoadPath.GetValue(aaSettings); - editorSettings.CatalogRequestsTimeout = aaSettings.CatalogRequestsTimeout; - editorSettings.BundleLocalCatalog = aaSettings.BundleLocalCatalog; - editorSettings.OptimizeCatalogSize = aaSettings.OptimizeCatalogSize; - editorSettings.DisableCatalogUpdateOnStartup = aaSettings.DisableCatalogUpdateOnStartup; - - var profile = aaSettings.profileSettings.GetProfile(aaSettings.activeProfileId); - editorSettings.ActiveProfile = new BuildLayout.Profile() - { - Id = profile.id, - Name = profile.profileName - }; - - editorSettings.ActiveProfile.Values = new BuildLayout.StringPair[profile.values.Count]; - for (int i = 0; i < profile.values.Count; ++i) - editorSettings.ActiveProfile.Values[i] = (new BuildLayout.StringPair() - {Key = profile.values[i].id, Value = profile.values[i].value}); - - return editorSettings; - } - - private static void SetLayoutMetaData(BuildLayout layoutOut, AddressableAssetSettings aaSettings) - { - layoutOut.UnityVersion = Application.unityVersion; - PackageManager.PackageInfo info = PackageManager.PackageInfo.FindForAssembly(typeof(BuildLayoutPrinter).Assembly); - if (info != null) - layoutOut.PackageVersion = $"{info.name}: {info.version}"; - layoutOut.BuildTarget = EditorUserBuildSettings.activeBuildTarget; - layoutOut.BuildScript = aaSettings.ActivePlayerDataBuilder.Name; - layoutOut.PlayerBuildVersion = aaSettings.PlayerBuildVersion; - } - - static BuildLayout.AddressablesRuntimeData GetAddressableRuntimeSettings(AddressableAssetsBuildContext aaContext, ContentCatalogData contentCatalog) - { - if (aaContext.runtimeData == null) - { - Debug.LogError("Could not get runtime data for Addressables BuildReport"); - return null; - } - - BuildLayout.AddressablesRuntimeData runtimeSettings = new BuildLayout.AddressablesRuntimeData(); - runtimeSettings.ProfilerEvents = aaContext.runtimeData.ProfileEvents; - runtimeSettings.LogResourceManagerExceptions = aaContext.runtimeData.LogResourceManagerExceptions; - - runtimeSettings.CatalogLoadPaths = new List(); - foreach (ResourceLocationData catalogLocation in aaContext.runtimeData.CatalogLocations) - runtimeSettings.CatalogLoadPaths.Add(catalogLocation.InternalId); - if (contentCatalog != null) - runtimeSettings.CatalogHash = contentCatalog.localHash; - - return runtimeSettings; - } - - /// - /// Runs the build task with the injected context. - /// - /// The success or failure ReturnCode - public ReturnCode Run() - { - BuildLayout layout = CreateBuildLayout(); - - string destinationPath = TimeStampedReportPath(layout.BuildStart); - using (m_Log.ScopedStep(LogLevel.Info, "Writing BuildReport File")) - layout.WriteToFile(destinationPath, k_PrettyPrint); - - if (ProjectConfigData.BuildLayoutReportFileFormat == ProjectConfigData.ReportFileFormat.TXT) - { - using (m_Log.ScopedStep(LogLevel.Info, "Writing Layout Text File")) - { - string txtFilePath = GetLayoutFilePathForFormat(ProjectConfigData.ReportFileFormat.TXT); - using (FileStream s = File.Open(txtFilePath, FileMode.Create)) - BuildLayoutPrinter.WriteBundleLayout(s, layout); - Debug.Log($"Text build layout written to {txtFilePath} and json build layout written to {destinationPath}"); - } - } - else - { - string legacyJsonFilePath = GetLayoutFilePathForFormat(ProjectConfigData.ReportFileFormat.JSON); - Directory.CreateDirectory(Path.GetDirectoryName(legacyJsonFilePath)); - if (File.Exists(legacyJsonFilePath)) - File.Delete(legacyJsonFilePath); - File.Copy(destinationPath, legacyJsonFilePath); - Debug.Log($"Json build layout written to {legacyJsonFilePath}"); - } - - ProjectConfigData.AddBuildReportFilePath(destinationPath); - s_LayoutCompleteCallback?.Invoke(destinationPath, layout); - return ReturnCode.Success; - } - - /// - /// Creates an Error report for the error provided - /// - /// Build error string - /// The current build context - /// Previous content state, used to determine whether a new or build update was performed. - public static void GenerateErrorReport(string error, AddressableAssetsBuildContext aaContext, AddressablesContentState previousContentState) - { - if (aaContext == null) - return; - AddressableAssetSettings aaSettings = aaContext.Settings; - if (aaSettings == null) - return; - - BuildLayout layout = new BuildLayout(); - layout.BuildStart = aaContext.buildStartTime; - layout.BuildError = error; - SetLayoutMetaData(layout, aaSettings); - layout.AddressablesEditorSettings = GetAddressableEditorSettings(aaSettings); - - if (previousContentState != null) - layout.BuildType = BuildType.UpdateBuild; - else - layout.BuildType = BuildType.NewBuild; - - string destinationPath = TimeStampedReportPath(layout.BuildStart); - layout.WriteToFile(destinationPath, k_PrettyPrint); - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using UnityEditor.AddressableAssets.Build.DataBuilders; +using UnityEditor.AddressableAssets.Build.Layout; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEditor.Build.Content; +using UnityEditor.Build.Pipeline; +using UnityEditor.Build.Pipeline.Injector; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.ResourceManagement.Util; + +namespace UnityEditor.AddressableAssets.Build.BuildPipelineTasks +{ + /// + /// The BuildTask used to generate the bundle layout. + /// + public class BuildLayoutGenerationTask : IBuildTask + { + const int k_Version = 1; + const bool k_PrettyPrint = false; + + internal static Action s_LayoutCompleteCallback; + + /// + /// The GenerateLocationListsTask version. + /// + public int Version + { + get { return k_Version; } + } + + /// + /// The mapping of the old to new bundle names. + /// + public Dictionary BundleNameRemap + { + get { return m_BundleNameRemap; } + set { m_BundleNameRemap = value; } + } + +#pragma warning disable 649 + [InjectContext(ContextUsage.In)] + IAddressableAssetsBuildContext m_AaBuildContext; + + [InjectContext(ContextUsage.In)] + IBuildParameters m_Parameters; + + [InjectContext] + IBundleWriteData m_WriteData; + + [InjectContext(ContextUsage.In, true)] + IBuildLogger m_Log; + + [InjectContext] + IBuildResults m_Results; + + [InjectContext(ContextUsage.In)] + IDependencyData m_DependencyData; + + [InjectContext(ContextUsage.In)] + IObjectDependencyData m_ObjectDependencyData; + + [InjectContext(ContextUsage.In)] + IBundleBuildResults m_BuildBundleResults; +#pragma warning restore 649 + + internal Dictionary m_BundleNameRemap; + internal AddressablesDataBuilderInput m_AddressablesInput; + internal ContentCatalogData m_ContentCatalogData; + + private bool IsContentUpdateBuild => m_AddressablesInput != null && m_AddressablesInput.PreviousContentState != null; + + internal static string m_LayoutFileName = "buildlayout"; + internal static string m_LayoutFilePath = $"{Addressables.LibraryPath}{m_LayoutFileName}"; + internal static string m_ReportsFilePath = $"{Addressables.BuildReportPath}{m_LayoutFileName}"; + + internal static string GetLayoutFilePathForFormat(ProjectConfigData.ReportFileFormat fileFormat) + { + string ext = (fileFormat == ProjectConfigData.ReportFileFormat.JSON) ? "json" : "txt"; + return $"{m_LayoutFilePath}.{ext}"; + } + + internal static string TimeStampedReportPath(DateTime now) + { + string stringNow = string.Format("{0:D4}.{1:D2}.{2:D2}.{3:D2}.{4:D2}.{5:D2}", now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second); + return $"{m_ReportsFilePath}_{stringNow}.json"; + } + + static AssetBucket GetOrCreate(Dictionary buckets, string asset) + { + if (!buckets.TryGetValue(asset, out AssetBucket bucket)) + { + bucket = new AssetBucket(); + bucket.guid = asset; + buckets.Add(asset, bucket); + } + + return bucket; + } + + class AssetBucket + { + public string guid; + public bool isFilePathBucket; + public List objs = new List(); + public BuildLayout.ExplicitAsset ExplictAsset; + + public ulong CalcObjectSize() + { + ulong sum = 0; + foreach (var obj in objs) + sum += obj.header.size; + return sum; + } + + public ulong CalcStreamedSize() + { + ulong sum = 0; + foreach (var obj in objs) + sum += obj.rawData.size; + return sum; + } + } + + AssetType GetSceneObjectType(string name) + { + if (AssetType.TryParse(name, true, out var rst)) + return rst; + return AssetType.SceneObject; + } + + ulong GetFileSizeFromPath(string path, out bool success) + { + success = false; + FileInfo fileInfo = new FileInfo(path); + if (fileInfo.Exists) + { + success = true; + return (ulong)fileInfo.Length; + } + return 0; + } + + private BuildLayout CreateBuildLayout() + { + AddressableAssetsBuildContext aaContext = (AddressableAssetsBuildContext)m_AaBuildContext; + + LayoutLookupTables lookup = null; + BuildLayout result = null; + using (m_Log.ScopedStep(LogLevel.Info, "Generate Lookup tables")) + lookup = GenerateLookupTables(aaContext); + using (m_Log.ScopedStep(LogLevel.Info, "Generate Build Layout")) + result = GenerateBuildLayout(aaContext, lookup); + return result; + } + + private LayoutLookupTables GenerateLookupTables(AddressableAssetsBuildContext aaContext) + { + LayoutLookupTables lookup = new LayoutLookupTables(); + + Dictionary objectTypes = new Dictionary(1024); + foreach (KeyValuePair assetResult in m_Results.AssetResults) + { + foreach (var resultEntry in assetResult.Value.ObjectTypes) + { + if (!objectTypes.ContainsKey(resultEntry.Key)) + objectTypes.Add(resultEntry.Key, resultEntry.Value); + } + } + + foreach (string bundleName in m_WriteData.FileToBundle.Values.Distinct()) + { + BuildLayout.Bundle bundle = new BuildLayout.Bundle(); + if (m_BuildBundleResults.BundleInfos.TryGetValue(bundleName, out var info)) + { + bundle.CRC = info.Crc; + bundle.Hash = info.Hash; + } + + bundle.Name = bundleName; + UnityEngine.BuildCompression compression = m_Parameters.GetCompressionForIdentifier(bundle.Name); + bundle.Compression = compression.compression.ToString(); + lookup.Bundles.Add(bundleName, bundle); + } + + foreach (BuildLayout.Bundle b in lookup.Bundles.Values) + { + if (aaContext.bundleToImmediateBundleDependencies.TryGetValue(b.Name, out List deps)) + b.Dependencies = deps.Select(x => lookup.Bundles[x]).Where(x => b != x).ToList(); + if (aaContext.bundleToExpandedBundleDependencies.TryGetValue(b.Name, out List deps2)) + b.ExpandedDependencies = deps2.Select(x => lookup.Bundles[x]).Where(x => b != x).ToList(); + } + + // create files + foreach (KeyValuePair fileBundle in m_WriteData.FileToBundle) + { + BuildLayout.Bundle bundle = lookup.Bundles[fileBundle.Value]; + BuildLayout.File f = new BuildLayout.File(); + f.Name = fileBundle.Key; + f.Bundle = bundle; + + WriteResult result = m_Results.WriteResults[f.Name]; + foreach (ResourceFile rf in result.resourceFiles) + { + var sf = new BuildLayout.SubFile(); + sf.IsSerializedFile = rf.serializedFile; + sf.Name = rf.fileAlias; + sf.Size = GetFileSizeFromPath(rf.fileName, out bool success); + if (!success) + Debug.LogWarning($"Resource File {sf.Name} from file \"{f.Name}\" was detected as part of the build, but the file could not be found. This may be because your build cache size is too small. Filesize of this Resource File will be 0 in BuildLayout."); + + f.SubFiles.Add(sf); + } + + bundle.Files.Add(f); + lookup.Files.Add(f.Name, f); + } + + // create assets + foreach (KeyValuePair> assetFile in m_WriteData.AssetToFiles) + { + BuildLayout.File file = lookup.Files[assetFile.Value[0]]; + BuildLayout.ExplicitAsset a = new BuildLayout.ExplicitAsset(); + a.Guid = assetFile.Key.ToString(); + a.AssetPath = AssetDatabase.GUIDToAssetPath(a.Guid); + a.File = file; + a.Bundle = file.Bundle; + file.Assets.Add(a); + lookup.GuidToExplicitAsset.Add(a.Guid, a); + } + + Dictionary> guidToPulledInBuckets = + new Dictionary>(); + + foreach (BuildLayout.File file in lookup.Files.Values) + { + Dictionary buckets = new Dictionary(); + WriteResult writeResult = m_Results.WriteResults[file.Name]; + List sceneObjects = new List(); + FileObjectData fData = new FileObjectData(); + lookup.FileToFileObjectData.Add(file, fData); + + foreach (ObjectSerializedInfo info in writeResult.serializedObjects) + { + if (info.serializedObject.guid.Empty()) + { + if (info.serializedObject.filePath.Equals("temp:/assetbundle", StringComparison.OrdinalIgnoreCase)) + { + file.BundleObjectInfo = new BuildLayout.AssetBundleObjectInfo(); + file.BundleObjectInfo.Size = info.header.size; + continue; + } + else if (info.serializedObject.filePath.StartsWith("temp:/preloaddata", + StringComparison.OrdinalIgnoreCase)) + { + file.PreloadInfoSize = (int)info.header.size; + continue; + } + else if (info.serializedObject.filePath.StartsWith("temp:/", StringComparison.OrdinalIgnoreCase)) + { + sceneObjects.Add(info); + continue; + } + else if (!string.IsNullOrEmpty(info.serializedObject.filePath)) + { + AssetBucket pathBucket = GetOrCreate(buckets, info.serializedObject.filePath.ToString()); + pathBucket.isFilePathBucket = true; + pathBucket.objs.Add(info); + continue; + } + } + + AssetBucket bucket = GetOrCreate(buckets, info.serializedObject.guid.ToString()); + bucket.objs.Add(info); + } + + if (sceneObjects.Count > 0) + { + BuildLayout.ExplicitAsset sceneAsset = file.Assets.First(x => x.AssetPath.EndsWith(".unity", StringComparison.OrdinalIgnoreCase)); + AssetBucket bucket = GetOrCreate(buckets, sceneAsset.Guid); + bucket.objs.AddRange(sceneObjects); + } + + // Update buckets with a reference to their explicit asset + file.Assets.ForEach(eAsset => + { + if (!buckets.TryGetValue(eAsset.Guid, out AssetBucket b)) + b = GetOrCreate(buckets, eAsset.Guid); // some assets might not pull in any objects + b.ExplictAsset = eAsset; + }); + + // Create entries for buckets that are implicitly pulled in + Dictionary guidToOtherData = new Dictionary(); + Dictionary> guidToObjectNames = new Dictionary>(); + int assetInFileId = 0; + HashSet MonoScriptAssets = new HashSet(); + + foreach (AssetBucket bucket in buckets.Values.Where(x => x.ExplictAsset == null)) + { + string assetPath = bucket.isFilePathBucket ? bucket.guid : AssetDatabase.GUIDToAssetPath(bucket.guid); + if (assetPath.EndsWith(".cs", StringComparison.OrdinalIgnoreCase) || + assetPath.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) + { + file.MonoScriptCount++; + file.MonoScriptSize += bucket.CalcObjectSize(); + MonoScriptAssets.Add(bucket.guid); + continue; + } + + var implicitAsset = new BuildLayout.DataFromOtherAsset(); + implicitAsset.AssetPath = assetPath; + implicitAsset.AssetGuid = bucket.guid; + implicitAsset.SerializedSize = bucket.CalcObjectSize(); + implicitAsset.StreamedSize = bucket.CalcStreamedSize(); + implicitAsset.ObjectCount = bucket.objs.Count; + implicitAsset.File = file; + assetInFileId = file.OtherAssets.Count; + file.OtherAssets.Add(implicitAsset); + + if (lookup.UsedImplicits.TryGetValue(implicitAsset.AssetGuid, out var dataList)) + dataList.Add(implicitAsset); + else + lookup.UsedImplicits.Add(implicitAsset.AssetGuid, new List(){implicitAsset}); + + guidToOtherData[implicitAsset.AssetGuid] = implicitAsset; + + if (lookup.AssetPathToTypeMap.ContainsKey(implicitAsset.AssetPath)) + implicitAsset.MainAssetType = lookup.AssetPathToTypeMap[implicitAsset.AssetPath]; + else + { + implicitAsset.MainAssetType = BuildLayoutHelpers.GetAssetType(AssetDatabase.GetMainAssetTypeAtPath(implicitAsset.AssetPath)); + lookup.AssetPathToTypeMap[implicitAsset.AssetPath] = implicitAsset.MainAssetType; + } + + Dictionary localIdentifierToObjectName; + if (!guidToObjectNames.TryGetValue(bucket.guid, out localIdentifierToObjectName)) + { + localIdentifierToObjectName = GetObjectsIdForAsset(assetPath); + guidToObjectNames.Add(bucket.guid, localIdentifierToObjectName); + } + + foreach (ObjectSerializedInfo bucketObj in bucket.objs) + { + Type objType = null; + if (objectTypes.TryGetValue(bucketObj.serializedObject, out Type[] types) && types.Length > 0) + objType = types[0]; + + AssetType eType = objType == null ? AssetType.Other : BuildLayoutHelpers.GetAssetType(objType); + if (implicitAsset.IsScene) + { + if (eType == AssetType.Other) + eType = AssetType.SceneObject; + } + + string name = ""; + if (localIdentifierToObjectName.TryGetValue(bucketObj.serializedObject.localIdentifierInFile, out string value)) + name = value; + BuildLayout.ObjectData layoutObject = new BuildLayout.ObjectData() + { + ObjectName = name, + LocalIdentifierInFile = bucketObj.serializedObject.localIdentifierInFile, + AssetType = eType, + SerializedSize = bucketObj.header.size, + StreamedSize = bucketObj.rawData.size + }; + + int objectIndex = implicitAsset.Objects.Count; + implicitAsset.Objects.Add(layoutObject); + fData.Add(bucketObj.serializedObject, layoutObject, assetInFileId, objectIndex); + } + + if (!guidToPulledInBuckets.TryGetValue(implicitAsset.AssetGuid, + out List bucketList)) + bucketList = guidToPulledInBuckets[implicitAsset.AssetGuid] = new List(); + bucketList.Add(implicitAsset); + } + + assetInFileId = file.OtherAssets.Count - 1; + foreach (BuildLayout.ExplicitAsset asset in file.Assets) + { + assetInFileId++; + AssetBucket bucket = buckets[asset.Guid]; + GUID.TryParse(asset.Guid, out GUID guid); + + // size info + asset.SerializedSize = bucket.CalcObjectSize(); + asset.StreamedSize = bucket.CalcStreamedSize(); + + // asset hash + if (m_Results.AssetResults.TryGetValue(guid, out var data)) + asset.AssetHash = data.Hash; + + // asset type + if (lookup.AssetPathToTypeMap.ContainsKey(asset.AssetPath)) + asset.MainAssetType = lookup.AssetPathToTypeMap[asset.AssetPath]; + else + { + System.Type type = AssetDatabase.GetMainAssetTypeAtPath(asset.AssetPath); + asset.MainAssetType = BuildLayoutHelpers.GetAssetType(type); + lookup.AssetPathToTypeMap[asset.AssetPath] = asset.MainAssetType; + } + + if (asset.MainAssetType == AssetType.GameObject) + { +#if UNITY_2022_2_OR_NEWER + Type importerType = AssetDatabase.GetImporterType(asset.AssetPath); + if (importerType == typeof(ModelImporter)) + asset.MainAssetType = AssetType.Model; + else if (importerType != null) +#endif + asset.MainAssetType = AssetType.Prefab; + } + + if (asset.IsScene) + { + CollectObjectsForScene(bucket, asset); + } + else + { + Dictionary localIdentifierToObjectName; + if (!guidToObjectNames.TryGetValue(bucket.guid, out localIdentifierToObjectName)) + { + localIdentifierToObjectName = GetObjectsIdForAsset(asset.AssetPath); + guidToObjectNames.Add(bucket.guid, localIdentifierToObjectName); + } + + CollectObjectsForAsset(bucket, objectTypes, asset, localIdentifierToObjectName, fData, assetInFileId); + } + } + + HashSet explicitAssetsAddedAsExternal = new HashSet(); + // Add references + foreach (BuildLayout.ExplicitAsset asset in file.Assets) + { + IEnumerable refs = null; + if (m_DependencyData.AssetInfo.TryGetValue(new GUID(asset.Guid), out AssetLoadInfo info)) + refs = info.referencedObjects; + else + refs = m_DependencyData.SceneInfo[new GUID(asset.Guid)].referencedObjects; + + foreach (string refGUID in refs.Select(x => x.guid.Empty() ? x.filePath : x.guid.ToString()).Distinct()) + { + if (MonoScriptAssets.Contains(refGUID)) + continue; + if (guidToOtherData.TryGetValue(refGUID, out BuildLayout.DataFromOtherAsset dfoa)) + { + dfoa.ReferencingAssets.Add(asset); + asset.InternalReferencedOtherAssets.Add(dfoa); + } + else if (buckets.TryGetValue(refGUID, out AssetBucket refBucket) && refBucket.ExplictAsset != null) + { + refBucket.ExplictAsset.ReferencingAssets.Add(asset); + asset.InternalReferencedExplicitAssets.Add(refBucket.ExplictAsset); + } + else if (lookup.GuidToExplicitAsset.TryGetValue(refGUID, out BuildLayout.ExplicitAsset refAsset)) + { + refAsset.ReferencingAssets.Add(asset); + asset.ExternallyReferencedAssets.Add(refAsset); + if (explicitAssetsAddedAsExternal.Add(refAsset)) + file.ExternalReferences.Add(refAsset); + } + } + } + } + + foreach (BuildLayout.File file in lookup.Files.Values) + { + if (lookup.FileToFileObjectData.TryGetValue(file, out FileObjectData fData)) + { + foreach (BuildLayout.ExplicitAsset asset in file.Assets) + { + if (asset.IsScene && asset.Objects.Count > 0) + { + BuildLayout.ObjectData objectData = asset.Objects[0]; + IEnumerable dependencies = m_DependencyData.SceneInfo[new GUID(asset.Guid)].referencedObjects; + CollectObjectReferences(fData, objectData, file, lookup, dependencies); + } + else + { + foreach (BuildLayout.ObjectData objectData in asset.Objects) + CollectObjectReferences(fData, objectData, file, lookup); + } + } + + foreach (var otherAsset in file.OtherAssets) + { + foreach (BuildLayout.ObjectData objectData in otherAsset.Objects) + { + // TODO see if theres a cached result for this + CollectObjectReferences(fData, objectData, file, lookup); + } + } + } + } + + return lookup; + } + + private static Dictionary GetObjectsIdForAsset(string assetPath) + { + Dictionary localIdentifierToObjectName = new Dictionary(); + var prop = new HierarchyProperty(assetPath, false); + if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(prop.instanceID, out _, out long mainLocalID)) + { + localIdentifierToObjectName[mainLocalID] = prop.name; + if (prop.hasChildren) + { + while (prop.Next(Array.Empty())) + { + if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(prop.instanceID, out _, out long localID)) + localIdentifierToObjectName[localID] = prop.name; + } + } + } + return localIdentifierToObjectName; + } + + private void CollectObjectsForAsset(in AssetBucket bucket, in Dictionary objectTypes, BuildLayout.ExplicitAsset asset, + in Dictionary localIdentifierToObjectName, FileObjectData fileObjectData, int assetInFileId) + { + foreach (ObjectSerializedInfo bucketObj in bucket.objs) + { + Type objType = null; + if (objectTypes.TryGetValue(bucketObj.serializedObject, out Type[] types) && types.Length > 0) + objType = types[0]; + + AssetType eType = objType == null ? AssetType.Other : BuildLayoutHelpers.GetAssetType(objType); + if (IsComponentType(eType)) + eType = AssetType.Component; + string componentName = ""; + + if (asset.IsScene && (eType == AssetType.Other || eType == AssetType.Component)) + eType = GetSceneObjectType(bucketObj.serializedObject.filePath.Remove(0, 6)); + if (eType == AssetType.Component) + componentName = objType.Name; + + string name = ""; + if (localIdentifierToObjectName.TryGetValue(bucketObj.serializedObject.localIdentifierInFile, out string value)) + name = value; + + BuildLayout.ObjectData layoutObject = new BuildLayout.ObjectData() + { + ObjectName = name, + ComponentName = componentName, + LocalIdentifierInFile = bucketObj.serializedObject.localIdentifierInFile, + AssetType = eType, + SerializedSize = bucketObj.header.size, + StreamedSize = bucketObj.rawData.size + }; + + int objectIndex = asset.Objects.Count; + asset.Objects.Add(layoutObject); + fileObjectData.Add(bucketObj.serializedObject, layoutObject, assetInFileId, objectIndex); + } + } + + private static bool IsComponentType(AssetType eType) + { + if (eType == AssetType.Transform || + eType == AssetType.GameObject || + eType == AssetType.Camera || + eType == AssetType.Light || + eType == AssetType.MeshFilter || + eType == AssetType.MeshRenderer || + eType == AssetType.SphereCollider || + eType == AssetType.AudioListener || + eType == AssetType.BoxCollider || + eType == AssetType.BoxCollider2D + || + eType == AssetType.MonoBehaviour) + { + // old components that should not have been in the enum, treat all as component type + return true; + } + + return false; + } + + private void CollectObjectsForScene(in AssetBucket bucket, BuildLayout.ExplicitAsset asset) + { + Dictionary TypeToObjectData = new Dictionary(); + foreach (ObjectSerializedInfo bucketObj in bucket.objs) + { + AssetType eType = GetSceneObjectType(bucketObj.serializedObject.filePath.Remove(0, 6)); + if (!TypeToObjectData.TryGetValue(eType, out BuildLayout.ObjectData layoutObject)) + { + layoutObject = new BuildLayout.ObjectData() + { + ObjectName = eType.ToString(), + LocalIdentifierInFile = TypeToObjectData.Count + 1, + AssetType = eType, + SerializedSize = bucketObj.header.size, + StreamedSize = bucketObj.rawData.size + }; + TypeToObjectData.Add(eType, layoutObject); + } + else + { + layoutObject.SerializedSize += bucketObj.header.size; + layoutObject.StreamedSize += bucketObj.rawData.size; + } + } + + // main scene object + asset.Objects.Add(new BuildLayout.ObjectData() + { + ObjectName = "Main", + LocalIdentifierInFile = 0, + AssetType = AssetType.SceneObject, + SerializedSize = 0, + StreamedSize = 0 + }); + + foreach (BuildLayout.ObjectData layoutObject in TypeToObjectData.Values) + { + asset.Objects.Add(layoutObject); + } + } + + private void CollectObjectReferences(FileObjectData fileObjectLookup, BuildLayout.ObjectData objectData, BuildLayout.File fileData, LayoutLookupTables lookup, + IEnumerable dependencies = null) + { + // get the ObjectIdentification object for the objectData + if (dependencies == null && fileObjectLookup.TryGetObjectIdentifier(objectData, out var objId)) + { + m_ObjectDependencyData.ObjectDependencyMap.TryGetValue(objId, out List dependenciesFromMap); + dependencies = dependenciesFromMap; + } + + if (dependencies != null) + { + int assetIdOffset = fileData.Assets.Count + fileData.OtherAssets.Count; + Dictionary> assetIndices = new Dictionary>(); // TODO I don't like this is allocated so much + HashSet indices; + foreach (ObjectIdentifier dependency in dependencies) + { + if (fileObjectLookup.TryGetObjectReferenceData(dependency, out (int, int)val)) + { + // object dependency within this file was found + if (assetIndices.TryGetValue(val.Item1, out indices)) + indices.Add(val.Item2); + else + assetIndices[val.Item1] = new HashSet(){val.Item2}; + } + else // if not in fileObjectLookup, not a dependency on this file, need to find in another file + { + if (lookup.GuidToExplicitAsset.TryGetValue(dependency.guid.ToString(), out BuildLayout.ExplicitAsset referencedAsset)) + { + var otherFData = lookup.FileToFileObjectData[referencedAsset.File]; + if (otherFData.TryGetObjectReferenceData(dependency, out val)) + { + val.Item1 = -1; + for (int i = 0; i < fileData.ExternalReferences.Count; ++i) + { + if (fileData.ExternalReferences[i] == referencedAsset) + { + val.Item1 = i + assetIdOffset; + break; + } + } + + if (val.Item1 >= 0) + { + if (assetIndices.TryGetValue(val.Item1, out indices)) + indices.Add(val.Item2); + else + assetIndices[val.Item1] = new HashSet(){val.Item2}; + } + } + } // can be false for built in shared bundles + } + } + + foreach (KeyValuePair> assetRefData in assetIndices) + { + objectData.References.Add(new BuildLayout.ObjectReference() {AssetId = assetRefData.Key, ObjectIds = new List(assetRefData.Value)}); + } + } + } + + private BuildLayout GenerateBuildLayout(AddressableAssetsBuildContext aaContext, LayoutLookupTables lookup) + { + BuildLayout layout = new BuildLayout(); + layout.BuildStart = aaContext.buildStartTime; + + layout.LocalCatalogBuildPath = aaContext.Settings.DefaultGroup.GetSchema().BuildPath.GetValue(aaContext.Settings); + layout.RemoteCatalogBuildPath = aaContext.Settings.RemoteCatalogBuildPath.GetValue(aaContext.Settings); + + AddressableAssetSettings aaSettings = aaContext.Settings; + if (m_ContentCatalogData != null) + layout.BuildResultHash = m_ContentCatalogData.m_BuildResultHash; + + using (m_Log.ScopedStep(LogLevel.Info, "Generate Basic Information")) + { + SetLayoutMetaData(layout, aaSettings); + layout.AddressablesEditorSettings = GetAddressableEditorSettings(aaSettings); + layout.AddressablesRuntimeSettings = GetAddressableRuntimeSettings(aaContext, m_ContentCatalogData); + } + + if (IsContentUpdateBuild) + layout.BuildType = BuildType.UpdateBuild; + else + layout.BuildType = BuildType.NewBuild; + + // Map from GUID to AddrssableAssetEntry + lookup.GuidToEntry = aaContext.assetEntries.ToDictionary(x => x.guid, x => x); + + // create groups + foreach (AddressableAssetGroup group in aaSettings.groups) + { + if (group.Name != group.name) + { + Debug.LogWarningFormat( + "Group name in settings does not match name in group asset, reset group name: \"{0}\" to \"{1}\"", + group.name, group.Name); + group.name = group.Name; + } + + var grp = new BuildLayout.Group(); + grp.Name = group.Name; + grp.Guid = group.Guid; + if (group.IsDefaultGroup()) + layout.DefaultGroup = grp; + + foreach (AddressableAssetGroupSchema schema in group.Schemas) + { + var sd = GenerateSchemaData(schema, aaSettings); + + BundledAssetGroupSchema bSchema = schema as BundledAssetGroupSchema; + if (bSchema != null) + { + for (int i = 0; i < sd.KvpDetails.Count; ++i) + { + if (sd.KvpDetails[i].Item1 == "BundleMode") + { + string modeStr = bSchema.BundleMode.ToString(); + sd.KvpDetails[i] = new Tuple("PackingMode", modeStr); + grp.PackingMode = modeStr; + break; + } + } + + lookup.GroupNameToBuildPath[group.name] = bSchema.BuildPath.GetValue(aaSettings); + } + + grp.Schemas.Add(sd); + } + + lookup.GroupLookup.Add(group.Guid, grp); + layout.Groups.Add(grp); + } + + // Create a lookup for bundle update states + foreach (ContentCatalogDataEntry entry in aaContext.locations) + { + if (entry.Data is AssetBundleRequestOptions options) + { + lookup.BundleNameToRequestOptions.Add(options.BundleName, options); + lookup.BundleNameToCatalogEntry.Add(options.BundleName, entry); + } + } + + if (IsContentUpdateBuild) + { + foreach (CachedBundleState prevState in m_AddressablesInput.PreviousContentState.cachedBundles) + { + if (prevState.data is AssetBundleRequestOptions options) + lookup.BundleNameToPreviousRequestOptions.Add(options.BundleName, options); + } + } + + using (m_Log.ScopedStep(LogLevel.Info, "Correlate Bundles to groups")) + { + foreach (BuildLayout.Bundle b in lookup.Bundles.Values) + CorrelateBundleToAssetGroup(layout, b, lookup, aaContext); + } + + using (m_Log.ScopedStep(LogLevel.Info, "Apply Addressable info to layout data")) + ApplyAddressablesInformationToExplicitAssets(layout, lookup); + using (m_Log.ScopedStep(LogLevel.Info, "Process additional bundle data")) + PostProcessBundleData(lookup); + using (m_Log.ScopedStep(LogLevel.Info, "Generating implicit inclusion data")) + AddImplicitAssetsToLayout(lookup, layout); + + SetDuration(layout); + return layout; + } + + BuildLayout.SchemaData GenerateSchemaData(AddressableAssetGroupSchema schema, AddressableAssetSettings aaSettings) + { + var sd = new BuildLayout.SchemaData(); + sd.Guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(schema)); + Type schemaType = schema.GetType(); + sd.Type = schemaType.Name; + + var properties = schemaType.GetProperties(); + + foreach (PropertyInfo property in properties) + { + if (!property.PropertyType.IsSerializable || !property.CanRead) + continue; + string propertyName = property.Name; + if (propertyName == "name" || propertyName == "hideFlags") + continue; + + if (property.PropertyType.IsPrimitive || property.PropertyType.IsEnum) + { + object propertyObject = property.GetValue(schema); + if (propertyObject != null) + sd.KvpDetails.Add(new Tuple(propertyName, propertyObject.ToString())); + } + else if (property.PropertyType == typeof(string)) + { + if (property.GetValue(schema) is string stringValue) + sd.KvpDetails.Add(new Tuple(propertyName, stringValue)); + } + else if (property.PropertyType == typeof(SerializedType)) + { + SerializedType serializeTypeValue = (SerializedType)property.GetValue(schema); + sd.KvpDetails.Add(new Tuple(propertyName, serializeTypeValue.ClassName)); + } + else if (property.PropertyType == typeof(ProfileValueReference)) + { + if (property.GetValue(schema) is ProfileValueReference profileValue) + sd.KvpDetails.Add( + new Tuple(propertyName, profileValue.GetValue(aaSettings))); + } + } + + return sd; + } + + void CorrelateBundleToAssetGroup(BuildLayout layout, BuildLayout.Bundle b, LayoutLookupTables lookup, AddressableAssetsBuildContext aaContext) + { + int indexFrom = b.Name.IndexOf(".bundle", StringComparison.Ordinal); + string nameWithoutExtension = indexFrom > 0 ? b.Name.Remove(indexFrom) : b.Name; + b.InternalName = nameWithoutExtension; + if (aaContext.bundleToAssetGroup.TryGetValue(b.Name, out var grpName)) + { + var assetGroup = lookup.GroupLookup[grpName]; + b.Name = m_BundleNameRemap[b.Name]; + b.Group = assetGroup; + lookup.FilenameToBundle[b.Name] = b; + var filePath = Path.Combine(lookup.GroupNameToBuildPath[assetGroup.Name], b.Name); + + b.FileSize = GetFileSizeFromPath(filePath, out bool success); + if (!success) + Debug.LogWarning($"AssetBundle {b.Name} from Addressable Group \"{assetGroup.Name}\" was detected as part of the build, but the file could not be found. Filesize of this AssetBundle will be 0 in BuildLayout."); + + assetGroup.Bundles.Add(b); + } + else + { + // bundleToAssetGroup doesn't contain the builtin bundles. The builtin content is built using values from the default group + AddressableAssetGroup defaultGroup = aaContext.Settings.DefaultGroup; + b.Name = m_BundleNameRemap[b.Name]; + b.Group = lookup.GroupLookup[defaultGroup.Guid]; // should this be set? + lookup.FilenameToBundle[b.Name] = b; + + b.FileSize = GetFileSizeFromPath(Path.Combine(lookup.GroupNameToBuildPath[defaultGroup.Name], b.Name), out bool success); + if (!success) + Debug.LogWarning($"Built in assetBundle {b.Name} was detected as part of the build, but the file could not be found. Filesize of this AssetBundle will be 0 in BuildLayout."); + + layout.BuiltInBundles.Add(b); + } + } + + void PostProcessBundleData(LayoutLookupTables lookup) + { + HashSet rootBundles = new HashSet(lookup.Bundles.Values); + foreach (BuildLayout.Bundle b in lookup.Bundles.Values) + { + SetBundleDataFromCatalogEntry(b, lookup); + GenerateBundleDependencyAndEfficiencyInformation(b, rootBundles); + } + + CalculateBundleEfficiencies(rootBundles); + } + + internal static void CalculateBundleEfficiencies(IEnumerable rootBundles) + { + Dictionary bundleDependencyCache = new Dictionary(); + foreach (BuildLayout.Bundle b in rootBundles) + CalculateEfficiency(b, bundleDependencyCache); + } + + /// + /// Calculates the Efficiency of bundle and all bundles below it in the dependency tree and caches the results. + /// Example: There are 3 bundles A, B, and C, that are each 10 MB on disk. A depends on 2 MB worth of assets in B, and B depends on 4 MB worth of assets in C. + /// The Efficiency of the dependencyLink from A->B would be 2/10 -> 20% and the ExpandedEfficiency of A->B would be (2 + 4)/(10 + 10) -> 6/20 -> 30% + /// + /// the root of the dependency tree that the CalculateEfficiency call will start from. + /// Cache of all bundle dependencies that have already been calculated + internal static void CalculateEfficiency(BuildLayout.Bundle bundle, Dictionary bundleDependencyCache = null) + { + Stack stk = new Stack(); + Queue q = new Queue(); + HashSet seenBundles = new HashSet(); + + if (bundleDependencyCache == null) + bundleDependencyCache = new Dictionary(); + + q.Enqueue(bundle); + + // Populate the stack of BundleDependencies with the lowest depth BundleDependencies being at the top of the stack + while (q.Count > 0) + { + var curBundle = q.Dequeue(); + foreach (var bd in curBundle.BundleDependencies) + { + if (bundleDependencyCache.ContainsKey(bd)) + break; + + if (!seenBundles.Contains(curBundle)) + { + q.Enqueue(bd.DependencyBundle); + stk.Push(bd); + } + } + seenBundles.Add(curBundle); + } + + // Get the required information out of each BundleDependency, caching the necessary info for each as you work your way up the tree + while (stk.Count > 0) + { + var curBd = stk.Pop(); + + ulong totalReferencedAssetFilesize = 0; + ulong totalDependentAssetFilesize = 0; + foreach (var bd in curBd.DependencyBundle.BundleDependencies) + { + if (bundleDependencyCache.TryGetValue(bd, out var ei)) + { + totalReferencedAssetFilesize += ei.referencedAssetFileSize; + totalDependentAssetFilesize += ei.totalAssetFileSize; + } + } + + var newEfficiencyInfo = new BuildLayout.Bundle.EfficiencyInfo() + { + referencedAssetFileSize = curBd.referencedAssetsFileSize + totalReferencedAssetFilesize, + totalAssetFileSize = curBd.DependencyBundle.FileSize + totalDependentAssetFilesize, + }; + + curBd.Efficiency = newEfficiencyInfo.totalAssetFileSize > 0 ? (float)curBd.referencedAssetsFileSize / curBd.DependencyBundle.FileSize : 1f; + curBd.ExpandedEfficiency = newEfficiencyInfo.totalAssetFileSize > 0 ? (float)newEfficiencyInfo.referencedAssetFileSize / newEfficiencyInfo.totalAssetFileSize : 1f; + bundleDependencyCache[curBd] = newEfficiencyInfo; + } + } + + void SetBundleDataFromCatalogEntry(BuildLayout.Bundle b, LayoutLookupTables lookup) + { + if (lookup.BundleNameToCatalogEntry.TryGetValue(b.InternalName, out var entry)) + { + b.LoadPath = entry.InternalId; + b.Provider = entry.Provider; + b.ResultType = entry.ResourceType.Name; + } + + if (lookup.BundleNameToPreviousRequestOptions.TryGetValue(b.InternalName, out var prevOptions)) + { + if (m_BuildBundleResults.BundleInfos.TryGetValue(b.Name, out var currentBundleDetails)) + { + if (currentBundleDetails.Hash.ToString() != prevOptions.Hash) + { + b.BuildStatus = BundleBuildStatus.Modified; + if (entry?.Data is AssetBundleRequestOptions currentOptions) + if (currentOptions.Hash == prevOptions.Hash) + b.BuildStatus = BundleBuildStatus.ModifiedUpdatePrevented; + } + else + { + b.BuildStatus = BundleBuildStatus.Unmodified; + } + } + } + } + + void ApplyAddressablesInformationToExplicitAssets(BuildLayout layout, LayoutLookupTables lookup) + { + HashSet loadPathsForBundle = new HashSet(); + foreach (var bundle in BuildLayoutHelpers.EnumerateBundles(layout)) + { + loadPathsForBundle.Clear(); + for (int fileIndex = 0; fileIndex < bundle.Files.Count; ++fileIndex) + { + foreach (BuildLayout.ExplicitAsset rootAsset in bundle.Files[fileIndex].Assets) + { + if (lookup.GuidToEntry.TryGetValue(rootAsset.Guid, out AddressableAssetEntry rootEntry)) + { + ApplyAddressablesInformationToExplicitAsset(lookup, rootAsset, rootEntry, loadPathsForBundle); + } + } + } + } + } + + private static void ApplyAddressablesInformationToExplicitAsset(LayoutLookupTables lookup, BuildLayout.ExplicitAsset rootAsset, AddressableAssetEntry rootEntry, HashSet loadPathsForBundle) + { + rootAsset.AddressableName = rootEntry.address; + rootAsset.MainAssetType = BuildLayoutHelpers.GetAssetType(rootEntry.MainAssetType); + rootAsset.InternalId = rootEntry.GetAssetLoadPath(true, loadPathsForBundle); + rootAsset.Labels = new string[rootEntry.labels.Count]; + rootEntry.labels.CopyTo(rootAsset.Labels); + rootAsset.GroupGuid = rootEntry.parentGroup.Guid; + + if (rootAsset.Bundle == null) + { + Debug.LogError($"Failed to get bundle information for AddressableAssetEntry: {rootEntry.AssetPath}"); + return; + } + + foreach (BuildLayout.ExplicitAsset referencedAsset in rootAsset.ExternallyReferencedAssets) + { + if (referencedAsset.Bundle == null) + { + Debug.LogError($"Failed to get bundle information for AddressableAssetEntry: {rootEntry.AssetPath}"); + continue; + } + + // Create the dependency between rootAssets bundle and referenced Assets bundle, + rootAsset.Bundle.UpdateBundleDependency(rootAsset, referencedAsset); + } + } + + void GenerateBundleDependencyAndEfficiencyInformation(BuildLayout.Bundle b, HashSet rootBundles) + { + b.ExpandedDependencyFileSize = 0; + b.DependencyFileSize = 0; + foreach (var dependency in b.Dependencies) + { + dependency.DependentBundles.Add(b); + rootBundles.Remove(dependency); + b.DependencyFileSize += dependency.FileSize; + } + + foreach (var expandedDependency in b.ExpandedDependencies) + b.ExpandedDependencyFileSize += expandedDependency.FileSize; + + foreach (var file in b.Files) + b.AssetCount += file.Assets.Count; + + b.SerializeBundleToBundleDependency(); + } + + void AddImplicitAssetsToLayout(LayoutLookupTables lookup, BuildLayout layout) + { + foreach (KeyValuePair> pair in lookup.UsedImplicits) + { + if (pair.Value.Count <= 1) + continue; + + BuildLayout.AssetDuplicationData assetDuplication = new BuildLayout.AssetDuplicationData(); + assetDuplication.AssetGuid = pair.Key; + bool hasDuplicatedObjects = false; + + foreach (BuildLayout.DataFromOtherAsset implicitData in pair.Value) + { + foreach (BuildLayout.ObjectData objectData in implicitData.Objects) + { + var existing = assetDuplication.DuplicatedObjects.Find(data => data.LocalIdentifierInFile == objectData.LocalIdentifierInFile); + if (existing != null) + existing.IncludedInBundleFiles.Add(implicitData.File); + else + { + assetDuplication.DuplicatedObjects.Add( + new BuildLayout.ObjectDuplicationData() + { + IncludedInBundleFiles = new List {implicitData.File}, + LocalIdentifierInFile = objectData.LocalIdentifierInFile + }); + hasDuplicatedObjects = true; + } + } + } + + if (!hasDuplicatedObjects) + continue; + + for (int i = assetDuplication.DuplicatedObjects.Count - 1; i >= 0; --i) + { + if (assetDuplication.DuplicatedObjects[i].IncludedInBundleFiles.Count <= 1) + assetDuplication.DuplicatedObjects.RemoveAt(i); + } + + if (assetDuplication.DuplicatedObjects.Count > 0) + layout.DuplicatedAssets.Add(assetDuplication); + } + } + + private static void SetDuration(BuildLayout layout) + { + var duration = DateTime.Now - layout.BuildStart; + layout.Duration = duration.TotalSeconds; + } + + static BuildLayout.AddressablesEditorData GetAddressableEditorSettings(AddressableAssetSettings aaSettings) + { + BuildLayout.AddressablesEditorData editorSettings = new BuildLayout.AddressablesEditorData(); + editorSettings.SettingsHash = aaSettings.currentHash.ToString(); + + editorSettings.DisableSubAssetRepresentations = aaSettings.DisableVisibleSubAssetRepresentations; + editorSettings.MaxConcurrentWebRequests = aaSettings.MaxConcurrentWebRequests; + editorSettings.NonRecursiveBuilding = aaSettings.NonRecursiveBuilding; + editorSettings.ContiguousBundles = aaSettings.ContiguousBundles; + editorSettings.UniqueBundleIds = aaSettings.UniqueBundleIds; + + if (aaSettings.ShaderBundleNaming == ShaderBundleNaming.Custom) + editorSettings.ShaderBundleNaming = aaSettings.ShaderBundleCustomNaming; + else + editorSettings.ShaderBundleNaming = aaSettings.ShaderBundleNaming.ToString(); + if (aaSettings.MonoScriptBundleNaming == MonoScriptBundleNaming.Custom) + editorSettings.MonoScriptBundleNaming = aaSettings.MonoScriptBundleCustomNaming; + else + editorSettings.MonoScriptBundleNaming = aaSettings.MonoScriptBundleNaming.ToString(); + editorSettings.StripUnityVersionFromBundleBuild = aaSettings.StripUnityVersionFromBundleBuild; + + editorSettings.BuildRemoteCatalog = aaSettings.BuildRemoteCatalog; + if (aaSettings.BuildRemoteCatalog) + editorSettings.RemoteCatalogLoadPath = aaSettings.RemoteCatalogLoadPath.GetValue(aaSettings); + editorSettings.CatalogRequestsTimeout = aaSettings.CatalogRequestsTimeout; + editorSettings.BundleLocalCatalog = aaSettings.BundleLocalCatalog; + editorSettings.OptimizeCatalogSize = aaSettings.OptimizeCatalogSize; + editorSettings.DisableCatalogUpdateOnStartup = aaSettings.DisableCatalogUpdateOnStartup; + + var profile = aaSettings.profileSettings.GetProfile(aaSettings.activeProfileId); + editorSettings.ActiveProfile = new BuildLayout.Profile() + { + Id = profile.id, + Name = profile.profileName + }; + + editorSettings.ActiveProfile.Values = new BuildLayout.StringPair[profile.values.Count]; + for (int i = 0; i < profile.values.Count; ++i) + editorSettings.ActiveProfile.Values[i] = (new BuildLayout.StringPair() + {Key = profile.values[i].id, Value = profile.values[i].value}); + + return editorSettings; + } + + private static void SetLayoutMetaData(BuildLayout layoutOut, AddressableAssetSettings aaSettings) + { + layoutOut.UnityVersion = Application.unityVersion; + PackageManager.PackageInfo info = PackageManager.PackageInfo.FindForAssembly(typeof(BuildLayoutPrinter).Assembly); + if (info != null) + layoutOut.PackageVersion = $"{info.name}: {info.version}"; + layoutOut.BuildTarget = EditorUserBuildSettings.activeBuildTarget; + layoutOut.BuildScript = aaSettings.ActivePlayerDataBuilder.Name; + layoutOut.PlayerBuildVersion = aaSettings.PlayerBuildVersion; + } + + static BuildLayout.AddressablesRuntimeData GetAddressableRuntimeSettings(AddressableAssetsBuildContext aaContext, ContentCatalogData contentCatalog) + { + if (aaContext.runtimeData == null) + { + Debug.LogError("Could not get runtime data for Addressables BuildReport"); + return null; + } + + BuildLayout.AddressablesRuntimeData runtimeSettings = new BuildLayout.AddressablesRuntimeData(); + runtimeSettings.ProfilerEvents = aaContext.runtimeData.ProfileEvents; + runtimeSettings.LogResourceManagerExceptions = aaContext.runtimeData.LogResourceManagerExceptions; + + runtimeSettings.CatalogLoadPaths = new List(); + foreach (ResourceLocationData catalogLocation in aaContext.runtimeData.CatalogLocations) + runtimeSettings.CatalogLoadPaths.Add(catalogLocation.InternalId); + if (contentCatalog != null) + runtimeSettings.CatalogHash = contentCatalog.localHash; + + return runtimeSettings; + } + + /// + /// Runs the build task with the injected context. + /// + /// The success or failure ReturnCode + public ReturnCode Run() + { + BuildLayout layout = CreateBuildLayout(); + + string destinationPath = TimeStampedReportPath(layout.BuildStart); + using (m_Log.ScopedStep(LogLevel.Info, "Writing BuildReport File")) + layout.WriteToFile(destinationPath, k_PrettyPrint); + + if (ProjectConfigData.BuildLayoutReportFileFormat == ProjectConfigData.ReportFileFormat.TXT) + { + using (m_Log.ScopedStep(LogLevel.Info, "Writing Layout Text File")) + { + string txtFilePath = GetLayoutFilePathForFormat(ProjectConfigData.ReportFileFormat.TXT); + using (FileStream s = File.Open(txtFilePath, FileMode.Create)) + BuildLayoutPrinter.WriteBundleLayout(s, layout); + Debug.Log($"Text build layout written to {txtFilePath} and json build layout written to {destinationPath}"); + } + } + else + { + string legacyJsonFilePath = GetLayoutFilePathForFormat(ProjectConfigData.ReportFileFormat.JSON); + Directory.CreateDirectory(Path.GetDirectoryName(legacyJsonFilePath)); + if (File.Exists(legacyJsonFilePath)) + File.Delete(legacyJsonFilePath); + File.Copy(destinationPath, legacyJsonFilePath); + Debug.Log($"Json build layout written to {legacyJsonFilePath}"); + } + + ProjectConfigData.AddBuildReportFilePath(destinationPath); + s_LayoutCompleteCallback?.Invoke(destinationPath, layout); + return ReturnCode.Success; + } + + /// + /// Creates an Error report for the error provided + /// + /// Build error string + /// The current build context + /// Previous content state, used to determine whether a new or build update was performed. + public static void GenerateErrorReport(string error, AddressableAssetsBuildContext aaContext, AddressablesContentState previousContentState) + { + if (aaContext == null) + return; + AddressableAssetSettings aaSettings = aaContext.Settings; + if (aaSettings == null) + return; + + BuildLayout layout = new BuildLayout(); + layout.BuildStart = aaContext.buildStartTime; + layout.BuildError = error; + SetLayoutMetaData(layout, aaSettings); + layout.AddressablesEditorSettings = GetAddressableEditorSettings(aaSettings); + + if (previousContentState != null) + layout.BuildType = BuildType.UpdateBuild; + else + layout.BuildType = BuildType.NewBuild; + + string destinationPath = TimeStampedReportPath(layout.BuildStart); + layout.WriteToFile(destinationPath, k_PrettyPrint); + } + } +} diff --git a/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs.meta b/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs.meta index 372ab980..71e7ff3e 100644 --- a/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs.meta +++ b/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: d34ce007ffbd4e74c9151022c3fb56df -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: d34ce007ffbd4e74c9151022c3fb56df +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs b/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs index c56e2f2d..b7665c15 100644 --- a/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs +++ b/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs @@ -1,76 +1,76 @@ -using System; -using UnityEditor.Build.Pipeline; -using UnityEditor.Build.Pipeline.Injector; -using UnityEditor.Build.Pipeline.Interfaces; - -namespace UnityEditor.AddressableAssets.Build.BuildPipelineTasks -{ - /// - /// The BuildTask used to extract write data from the build. - /// - public class ExtractDataTask : IBuildTask - { - /// - /// The ExtractDataTask version. - /// - public int Version - { - get { return 1; } - } - - /// - /// Get the injected dependency data of the task. - /// - public IDependencyData DependencyData - { - get { return m_DependencyData; } - } - - /// - /// Get the injected write data of the task. - /// - public IBundleWriteData WriteData - { - get { return m_WriteData; } - } - - /// - /// Get the injected build cache of the task. - /// - public IBuildCache BuildCache - { - get { return m_BuildCache; } - } - - /// - /// The build context of the task. - /// - public IBuildContext BuildContext - { - get { return m_BuildContext; } - } - -#pragma warning disable 649 - [InjectContext(ContextUsage.In)] - IDependencyData m_DependencyData; - - [InjectContext(ContextUsage.In)] - IBundleWriteData m_WriteData; - - [InjectContext(ContextUsage.In)] - IBuildCache m_BuildCache; - - [InjectContext(ContextUsage.In)] - internal IBuildContext m_BuildContext; -#pragma warning restore 649 - - /// - /// Runs the ExtractDataTask. The data for this task is all injected context so no operations are performed in the Run step. - /// - /// Success. - public ReturnCode Run() - { - return ReturnCode.Success; - } - } -} +using System; +using UnityEditor.Build.Pipeline; +using UnityEditor.Build.Pipeline.Injector; +using UnityEditor.Build.Pipeline.Interfaces; + +namespace UnityEditor.AddressableAssets.Build.BuildPipelineTasks +{ + /// + /// The BuildTask used to extract write data from the build. + /// + public class ExtractDataTask : IBuildTask + { + /// + /// The ExtractDataTask version. + /// + public int Version + { + get { return 1; } + } + + /// + /// Get the injected dependency data of the task. + /// + public IDependencyData DependencyData + { + get { return m_DependencyData; } + } + + /// + /// Get the injected write data of the task. + /// + public IBundleWriteData WriteData + { + get { return m_WriteData; } + } + + /// + /// Get the injected build cache of the task. + /// + public IBuildCache BuildCache + { + get { return m_BuildCache; } + } + + /// + /// The build context of the task. + /// + public IBuildContext BuildContext + { + get { return m_BuildContext; } + } + +#pragma warning disable 649 + [InjectContext(ContextUsage.In)] + IDependencyData m_DependencyData; + + [InjectContext(ContextUsage.In)] + IBundleWriteData m_WriteData; + + [InjectContext(ContextUsage.In)] + IBuildCache m_BuildCache; + + [InjectContext(ContextUsage.In)] + internal IBuildContext m_BuildContext; +#pragma warning restore 649 + + /// + /// Runs the ExtractDataTask. The data for this task is all injected context so no operations are performed in the Run step. + /// + /// Success. + public ReturnCode Run() + { + return ReturnCode.Success; + } + } +} diff --git a/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs.meta b/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs.meta index 0af45ddc..93bdf4ba 100644 --- a/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs.meta +++ b/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 9dafe60ff4149624880b04d0cea88719 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 9dafe60ff4149624880b04d0cea88719 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs b/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs index dbc6229c..0e9bb2d2 100644 --- a/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs +++ b/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs @@ -1,384 +1,384 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEditor.AddressableAssets.Build.DataBuilders; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.AddressableAssets.Settings.GroupSchemas; -using UnityEditor.Build.Content; -using UnityEditor.Build.Pipeline; -using UnityEditor.Build.Pipeline.Injector; -using UnityEditor.Build.Pipeline.Interfaces; -using UnityEngine; -using UnityEngine.AddressableAssets.ResourceLocators; -using UnityEngine.ResourceManagement.ResourceProviders; -using UnityEngine.ResourceManagement.Util; -using static UnityEditor.AddressableAssets.Settings.AddressablesFileEnumeration; - -namespace UnityEditor.AddressableAssets.Build.BuildPipelineTasks -{ - /// - /// The BuildTask used to create location lists for Addressable assets. - /// - public class GenerateLocationListsTask : IBuildTask - { - const int k_Version = 1; - - /// - /// The GenerateLocationListsTask version. - /// - public int Version - { - get { return k_Version; } - } - -#pragma warning disable 649 - [InjectContext(ContextUsage.In)] - IAddressableAssetsBuildContext m_AaBuildContext; - - [InjectContext] - IBundleWriteData m_WriteData; - - [InjectContext] - IDependencyData m_DependencyData; - - [InjectContext(ContextUsage.In, true)] - IBuildLogger m_Log; - - [InjectContext(ContextUsage.In)] - IBuildParameters m_Parameters; - -#pragma warning restore 649 - - /// - /// Runs the build task with the injected context. - /// - /// The success or failure ReturnCode - public ReturnCode Run() - { - Input input = new Input(); - var aaContext = (AddressableAssetsBuildContext)m_AaBuildContext; - input.FileToBundle = m_WriteData.FileToBundle; - input.AssetToFiles = m_WriteData.AssetToFiles; - input.AssetToAssetInfo = m_DependencyData != null ? m_DependencyData.AssetInfo : null; - input.Logger = m_Log; - input.Settings = aaContext.Settings; - input.BundleToAssetGroup = aaContext.bundleToAssetGroup; - input.AddressableAssetEntries = aaContext.assetEntries; - input.Target = m_Parameters.Target; - - Output output = ProcessInput(input); - - if (aaContext.locations == null) - aaContext.locations = output.Locations; - else - aaContext.locations.AddRange(output.Locations); - - if (aaContext.GuidToCatalogLocation == null) - aaContext.GuidToCatalogLocation = output.GuidToLocation; - else foreach (KeyValuePair> pair in output.GuidToLocation) - aaContext.GuidToCatalogLocation[pair.Key] = pair.Value; - - aaContext.assetGroupToBundles = output.AssetGroupToBundles; - if (aaContext.providerTypes == null) - aaContext.providerTypes = output.ProviderTypes; - else - aaContext.providerTypes.UnionWith(output.ProviderTypes); - aaContext.bundleToExpandedBundleDependencies = output.BundleToExpandedBundleDependencies; - aaContext.bundleToImmediateBundleDependencies = output.BundleToImmediateBundleDependencies; - - return ReturnCode.Success; - } - - /// - /// Storage for data gathered by the build pipeline. - /// - public struct Input - { - /// - /// Mapping from serialized filename to the bundle name - /// - public Dictionary FileToBundle; - - /// - /// Mapping of an asset to all the serialized files needed to load it. The first entry is the file that contains the asset itself. - /// - public Dictionary> AssetToFiles; - - /// - /// Map of Guid to AssetLoadInfo - /// - public Dictionary AssetToAssetInfo; - - /// - /// The logger used during the build. - /// - public IBuildLogger Logger; - - /// - /// The current AddressableAssetSettings to be processed. - /// - public AddressableAssetSettings Settings; - - /// - /// Mapping of the AssetBundle to the AddressableAssetGroup it was derived from - /// - public Dictionary BundleToAssetGroup; - - /// - /// All the AddressableAssetEntries to process - /// - public List AddressableAssetEntries; - - /// - /// The BuildTarget to build for. - /// - public BuildTarget Target; - } - - /// - /// Storage for location data, including: dependencies, locations, and provider types. - /// - public struct Output - { - /// - /// Content Catalog entries that were built into the Catalog. - /// - public List Locations; - - /// - /// A mapping of Asset GUID's to resulting ContentCatalogDataEntry entries. - /// - internal Dictionary> GuidToLocation; - - /// - /// A mapping of AddressableAssetGroups to the AssetBundles generated from its data. - /// - public Dictionary> AssetGroupToBundles; - - /// - /// A hash set of all the provider types included in the build. - /// - public HashSet ProviderTypes; - - /// - /// A mapping of AssetBundles to the direct dependencies - /// - public Dictionary> BundleToImmediateBundleDependencies; - - /// - /// A mapping of AssetBundles to their expanded dependencies. - /// - public Dictionary> BundleToExpandedBundleDependencies; - } - - static AddressableAssetGroup GetGroupFromBundle(string bundleName, Dictionary bundleToAssetGroupGUID, AddressableAssetSettings settings) - { - if (!bundleToAssetGroupGUID.TryGetValue(bundleName, out string groupGuid)) - return settings.DefaultGroup; - return settings.FindGroup(g => g != null && g.Guid == groupGuid); - } - - static TValue GetOrCreate(IDictionary dict, TKey key) where TValue : new() - { - TValue val; - - if (!dict.TryGetValue(key, out val)) - { - val = new TValue(); - dict.Add(key, val); - } - - return val; - } - - class BundleEntry - { - public string BundleName; - public HashSet Dependencies = new HashSet(); - public HashSet ExpandedDependencies; - public List Assets = new List(); - public AddressableAssetGroup Group; - public HashSet AssetInternalIds = new HashSet(); - } - - static private void ExpandDependencies(BundleEntry entry) - { - HashSet visited = new HashSet(); - Queue toVisit = new Queue(); - toVisit.Enqueue(entry); - while (toVisit.Count > 0) - { - BundleEntry cur = toVisit.Dequeue(); - visited.Add(cur); - foreach (BundleEntry dep in cur.Dependencies) - if (!visited.Contains(dep)) - toVisit.Enqueue(dep); - } - - entry.ExpandedDependencies = visited; - } - - static BundleEntry GetOrCreateBundleEntry(string bundleName, Dictionary bundleToEntry) - { - if (!bundleToEntry.TryGetValue(bundleName, out BundleEntry e)) - bundleToEntry.Add(bundleName, e = new BundleEntry() {BundleName = bundleName}); - return e; - } - - /// - /// Processes the Input data from the build and returns an organized struct of information, including dependencies and catalog loctions. - /// - /// Data captured as part of the build process. - /// An object that contains organized information about dependencies and catalog locations. - public static Output ProcessInput(Input input) - { - var locations = new List(); - var assetGroupToBundles = new Dictionary>(); - var bundleToEntry = new Dictionary(); - var providerTypes = new HashSet(); - - // Create a bundle entry for every bundle that our assets could reference - foreach (List files in input.AssetToFiles.Values) - files.ForEach(x => GetOrCreateBundleEntry(input.FileToBundle[x], bundleToEntry)); - - // build list of assets each bundle has as well as the dependent bundles - using (input.Logger.ScopedStep(LogLevel.Info, "Calculate Bundle Dependencies")) - { - foreach (KeyValuePair> k in input.AssetToFiles) - { - string bundle = input.FileToBundle[k.Value[0]]; - BundleEntry bundleEntry = bundleToEntry[bundle]; - - bundleEntry.Assets.Add(k.Key); - bundleEntry.Dependencies.UnionWith(k.Value.Select(x => bundleToEntry[input.FileToBundle[x]])); - } - } - - using (input.Logger.ScopedStep(LogLevel.Info, "ExpandDependencies")) - { - foreach (BundleEntry bEntry in bundleToEntry.Values) - ExpandDependencies(bEntry); - } - - // Assign each bundle a group - foreach (BundleEntry bEntry in bundleToEntry.Values) - bEntry.Group = GetGroupFromBundle(bEntry.BundleName, input.BundleToAssetGroup, input.Settings); - - // Create a location for each bundle - foreach (BundleEntry bEntry in bundleToEntry.Values) - { - string bundleProvider = GetBundleProviderName(bEntry.Group); - string bundleInternalId = GetLoadPath(bEntry.Group, bEntry.BundleName, input.Target); - locations.Add(new ContentCatalogDataEntry(typeof(IAssetBundleResource), bundleInternalId, bundleProvider, new object[] {bEntry.BundleName})); - } - - Dictionary> guidToLocation = new Dictionary>(); - using (input.Logger.ScopedStep(LogLevel.Info, "Calculate Locations")) - { - // build a mapping of asset guid to AddressableAssetEntry - Dictionary guidToEntry = input.AddressableAssetEntries.ToDictionary(x => x.guid, x => x); - - foreach (BundleEntry bEntry in bundleToEntry.Values) - { - string assetProvider = GetAssetProviderName(bEntry.Group); - var schema = bEntry.Group.GetSchema(); - foreach (GUID assetGUID in bEntry.Assets) - { - if (guidToEntry.TryGetValue(assetGUID.ToString(), out AddressableAssetEntry entry)) - { - int indexAddedStart = locations.Count; - entry.CreateCatalogEntries(locations, true, assetProvider, bEntry.ExpandedDependencies.Select(x => x.BundleName), null, input.AssetToAssetInfo, providerTypes, - schema.IncludeAddressInCatalog, schema.IncludeGUIDInCatalog, schema.IncludeLabelsInCatalog, bEntry.AssetInternalIds); - if (indexAddedStart < locations.Count) - guidToLocation.Add(assetGUID, locations.GetRange(indexAddedStart, locations.Count-indexAddedStart)); - } - } - } - } - - // create the assetGroupToBundles mapping - foreach (BundleEntry bEntry in bundleToEntry.Values) - GetOrCreate(assetGroupToBundles, bEntry.Group).Add(bEntry.BundleName); - - var output = new Output(); - output.Locations = locations; - output.GuidToLocation = guidToLocation; - output.ProviderTypes = providerTypes; - output.AssetGroupToBundles = assetGroupToBundles; - output.BundleToImmediateBundleDependencies = bundleToEntry.Values.ToDictionary(x => x.BundleName, x => x.Dependencies.Select(y => y.BundleName).ToList()); - output.BundleToExpandedBundleDependencies = - bundleToEntry.Values.ToDictionary(x => x.BundleName, x => x.ExpandedDependencies.Where(y => !x.Dependencies.Contains(y)).Select(y => y.BundleName).ToList()); - return output; - } - - /// - /// Runs the build task with a give context and write data. - /// - /// The addressables build context. - /// The write data used to generate the location lists. - /// The success or failure ReturnCode - [Obsolete("This method uses nonoptimized code. Use nonstatic version Run() instead.")] - public static ReturnCode Run(IAddressableAssetsBuildContext aaBuildContext, IBundleWriteData writeData) - { - var task = new GenerateLocationListsTask(); - task.m_AaBuildContext = aaBuildContext; - task.m_WriteData = writeData; - return task.Run(); - } - - internal static string GetBundleProviderName(AddressableAssetGroup group) - { - return group.GetSchema().GetBundleCachedProviderId(); - } - - internal static string GetAssetProviderName(AddressableAssetGroup group) - { - return group.GetSchema().GetAssetCachedProviderId(); - } - - internal static string GetLoadPath(AddressableAssetGroup group, string name, BuildTarget target) - { - var bagSchema = group.GetSchema(); - if (bagSchema == null || bagSchema.LoadPath == null) - { - Debug.LogError("Unable to determine load path for " + name + ". Check that your default group is not '" + AddressableAssetSettings.PlayerDataGroupName + "'"); - return string.Empty; - } - - string loadPath = bagSchema.LoadPath.GetValue(group.Settings); - loadPath = loadPath.Replace('\\', '/'); - if (loadPath.EndsWith("/")) - loadPath += name; - else - loadPath = loadPath + "/" + name; - - if (!string.IsNullOrEmpty(bagSchema.UrlSuffix)) - loadPath += bagSchema.UrlSuffix; - if (!ResourceManagerConfig.ShouldPathUseWebRequest(loadPath) && !bagSchema.UseUnityWebRequestForLocalBundles) - { - char separator = PathSeparatorForPlatform(target); - if (separator != '/') - loadPath = loadPath.Replace('/', separator); - } - - return loadPath; - } - - internal static char PathSeparatorForPlatform(BuildTarget target) - { - switch (target) - { - case BuildTarget.StandaloneWindows64: - case BuildTarget.StandaloneWindows: - case BuildTarget.XboxOne: - return '\\'; - case BuildTarget.GameCoreXboxOne: - return '\\'; - case BuildTarget.Android: - return '/'; - default: - return '/'; - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.AddressableAssets.Build.DataBuilders; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEditor.Build.Content; +using UnityEditor.Build.Pipeline; +using UnityEditor.Build.Pipeline.Injector; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEngine; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.ResourceManagement.Util; +using static UnityEditor.AddressableAssets.Settings.AddressablesFileEnumeration; + +namespace UnityEditor.AddressableAssets.Build.BuildPipelineTasks +{ + /// + /// The BuildTask used to create location lists for Addressable assets. + /// + public class GenerateLocationListsTask : IBuildTask + { + const int k_Version = 1; + + /// + /// The GenerateLocationListsTask version. + /// + public int Version + { + get { return k_Version; } + } + +#pragma warning disable 649 + [InjectContext(ContextUsage.In)] + IAddressableAssetsBuildContext m_AaBuildContext; + + [InjectContext] + IBundleWriteData m_WriteData; + + [InjectContext] + IDependencyData m_DependencyData; + + [InjectContext(ContextUsage.In, true)] + IBuildLogger m_Log; + + [InjectContext(ContextUsage.In)] + IBuildParameters m_Parameters; + +#pragma warning restore 649 + + /// + /// Runs the build task with the injected context. + /// + /// The success or failure ReturnCode + public ReturnCode Run() + { + Input input = new Input(); + var aaContext = (AddressableAssetsBuildContext)m_AaBuildContext; + input.FileToBundle = m_WriteData.FileToBundle; + input.AssetToFiles = m_WriteData.AssetToFiles; + input.AssetToAssetInfo = m_DependencyData != null ? m_DependencyData.AssetInfo : null; + input.Logger = m_Log; + input.Settings = aaContext.Settings; + input.BundleToAssetGroup = aaContext.bundleToAssetGroup; + input.AddressableAssetEntries = aaContext.assetEntries; + input.Target = m_Parameters.Target; + + Output output = ProcessInput(input); + + if (aaContext.locations == null) + aaContext.locations = output.Locations; + else + aaContext.locations.AddRange(output.Locations); + + if (aaContext.GuidToCatalogLocation == null) + aaContext.GuidToCatalogLocation = output.GuidToLocation; + else foreach (KeyValuePair> pair in output.GuidToLocation) + aaContext.GuidToCatalogLocation[pair.Key] = pair.Value; + + aaContext.assetGroupToBundles = output.AssetGroupToBundles; + if (aaContext.providerTypes == null) + aaContext.providerTypes = output.ProviderTypes; + else + aaContext.providerTypes.UnionWith(output.ProviderTypes); + aaContext.bundleToExpandedBundleDependencies = output.BundleToExpandedBundleDependencies; + aaContext.bundleToImmediateBundleDependencies = output.BundleToImmediateBundleDependencies; + + return ReturnCode.Success; + } + + /// + /// Storage for data gathered by the build pipeline. + /// + public struct Input + { + /// + /// Mapping from serialized filename to the bundle name + /// + public Dictionary FileToBundle; + + /// + /// Mapping of an asset to all the serialized files needed to load it. The first entry is the file that contains the asset itself. + /// + public Dictionary> AssetToFiles; + + /// + /// Map of Guid to AssetLoadInfo + /// + public Dictionary AssetToAssetInfo; + + /// + /// The logger used during the build. + /// + public IBuildLogger Logger; + + /// + /// The current AddressableAssetSettings to be processed. + /// + public AddressableAssetSettings Settings; + + /// + /// Mapping of the AssetBundle to the AddressableAssetGroup it was derived from + /// + public Dictionary BundleToAssetGroup; + + /// + /// All the AddressableAssetEntries to process + /// + public List AddressableAssetEntries; + + /// + /// The BuildTarget to build for. + /// + public BuildTarget Target; + } + + /// + /// Storage for location data, including: dependencies, locations, and provider types. + /// + public struct Output + { + /// + /// Content Catalog entries that were built into the Catalog. + /// + public List Locations; + + /// + /// A mapping of Asset GUID's to resulting ContentCatalogDataEntry entries. + /// + internal Dictionary> GuidToLocation; + + /// + /// A mapping of AddressableAssetGroups to the AssetBundles generated from its data. + /// + public Dictionary> AssetGroupToBundles; + + /// + /// A hash set of all the provider types included in the build. + /// + public HashSet ProviderTypes; + + /// + /// A mapping of AssetBundles to the direct dependencies + /// + public Dictionary> BundleToImmediateBundleDependencies; + + /// + /// A mapping of AssetBundles to their expanded dependencies. + /// + public Dictionary> BundleToExpandedBundleDependencies; + } + + static AddressableAssetGroup GetGroupFromBundle(string bundleName, Dictionary bundleToAssetGroupGUID, AddressableAssetSettings settings) + { + if (!bundleToAssetGroupGUID.TryGetValue(bundleName, out string groupGuid)) + return settings.DefaultGroup; + return settings.FindGroup(g => g != null && g.Guid == groupGuid); + } + + static TValue GetOrCreate(IDictionary dict, TKey key) where TValue : new() + { + TValue val; + + if (!dict.TryGetValue(key, out val)) + { + val = new TValue(); + dict.Add(key, val); + } + + return val; + } + + class BundleEntry + { + public string BundleName; + public HashSet Dependencies = new HashSet(); + public HashSet ExpandedDependencies; + public List Assets = new List(); + public AddressableAssetGroup Group; + public HashSet AssetInternalIds = new HashSet(); + } + + static private void ExpandDependencies(BundleEntry entry) + { + HashSet visited = new HashSet(); + Queue toVisit = new Queue(); + toVisit.Enqueue(entry); + while (toVisit.Count > 0) + { + BundleEntry cur = toVisit.Dequeue(); + visited.Add(cur); + foreach (BundleEntry dep in cur.Dependencies) + if (!visited.Contains(dep)) + toVisit.Enqueue(dep); + } + + entry.ExpandedDependencies = visited; + } + + static BundleEntry GetOrCreateBundleEntry(string bundleName, Dictionary bundleToEntry) + { + if (!bundleToEntry.TryGetValue(bundleName, out BundleEntry e)) + bundleToEntry.Add(bundleName, e = new BundleEntry() {BundleName = bundleName}); + return e; + } + + /// + /// Processes the Input data from the build and returns an organized struct of information, including dependencies and catalog loctions. + /// + /// Data captured as part of the build process. + /// An object that contains organized information about dependencies and catalog locations. + public static Output ProcessInput(Input input) + { + var locations = new List(); + var assetGroupToBundles = new Dictionary>(); + var bundleToEntry = new Dictionary(); + var providerTypes = new HashSet(); + + // Create a bundle entry for every bundle that our assets could reference + foreach (List files in input.AssetToFiles.Values) + files.ForEach(x => GetOrCreateBundleEntry(input.FileToBundle[x], bundleToEntry)); + + // build list of assets each bundle has as well as the dependent bundles + using (input.Logger.ScopedStep(LogLevel.Info, "Calculate Bundle Dependencies")) + { + foreach (KeyValuePair> k in input.AssetToFiles) + { + string bundle = input.FileToBundle[k.Value[0]]; + BundleEntry bundleEntry = bundleToEntry[bundle]; + + bundleEntry.Assets.Add(k.Key); + bundleEntry.Dependencies.UnionWith(k.Value.Select(x => bundleToEntry[input.FileToBundle[x]])); + } + } + + using (input.Logger.ScopedStep(LogLevel.Info, "ExpandDependencies")) + { + foreach (BundleEntry bEntry in bundleToEntry.Values) + ExpandDependencies(bEntry); + } + + // Assign each bundle a group + foreach (BundleEntry bEntry in bundleToEntry.Values) + bEntry.Group = GetGroupFromBundle(bEntry.BundleName, input.BundleToAssetGroup, input.Settings); + + // Create a location for each bundle + foreach (BundleEntry bEntry in bundleToEntry.Values) + { + string bundleProvider = GetBundleProviderName(bEntry.Group); + string bundleInternalId = GetLoadPath(bEntry.Group, bEntry.BundleName, input.Target); + locations.Add(new ContentCatalogDataEntry(typeof(IAssetBundleResource), bundleInternalId, bundleProvider, new object[] {bEntry.BundleName})); + } + + Dictionary> guidToLocation = new Dictionary>(); + using (input.Logger.ScopedStep(LogLevel.Info, "Calculate Locations")) + { + // build a mapping of asset guid to AddressableAssetEntry + Dictionary guidToEntry = input.AddressableAssetEntries.ToDictionary(x => x.guid, x => x); + + foreach (BundleEntry bEntry in bundleToEntry.Values) + { + string assetProvider = GetAssetProviderName(bEntry.Group); + var schema = bEntry.Group.GetSchema(); + foreach (GUID assetGUID in bEntry.Assets) + { + if (guidToEntry.TryGetValue(assetGUID.ToString(), out AddressableAssetEntry entry)) + { + int indexAddedStart = locations.Count; + entry.CreateCatalogEntries(locations, true, assetProvider, bEntry.ExpandedDependencies.Select(x => x.BundleName), null, input.AssetToAssetInfo, providerTypes, + schema.IncludeAddressInCatalog, schema.IncludeGUIDInCatalog, schema.IncludeLabelsInCatalog, bEntry.AssetInternalIds); + if (indexAddedStart < locations.Count) + guidToLocation.Add(assetGUID, locations.GetRange(indexAddedStart, locations.Count-indexAddedStart)); + } + } + } + } + + // create the assetGroupToBundles mapping + foreach (BundleEntry bEntry in bundleToEntry.Values) + GetOrCreate(assetGroupToBundles, bEntry.Group).Add(bEntry.BundleName); + + var output = new Output(); + output.Locations = locations; + output.GuidToLocation = guidToLocation; + output.ProviderTypes = providerTypes; + output.AssetGroupToBundles = assetGroupToBundles; + output.BundleToImmediateBundleDependencies = bundleToEntry.Values.ToDictionary(x => x.BundleName, x => x.Dependencies.Select(y => y.BundleName).ToList()); + output.BundleToExpandedBundleDependencies = + bundleToEntry.Values.ToDictionary(x => x.BundleName, x => x.ExpandedDependencies.Where(y => !x.Dependencies.Contains(y)).Select(y => y.BundleName).ToList()); + return output; + } + + /// + /// Runs the build task with a give context and write data. + /// + /// The addressables build context. + /// The write data used to generate the location lists. + /// The success or failure ReturnCode + [Obsolete("This method uses nonoptimized code. Use nonstatic version Run() instead.")] + public static ReturnCode Run(IAddressableAssetsBuildContext aaBuildContext, IBundleWriteData writeData) + { + var task = new GenerateLocationListsTask(); + task.m_AaBuildContext = aaBuildContext; + task.m_WriteData = writeData; + return task.Run(); + } + + internal static string GetBundleProviderName(AddressableAssetGroup group) + { + return group.GetSchema().GetBundleCachedProviderId(); + } + + internal static string GetAssetProviderName(AddressableAssetGroup group) + { + return group.GetSchema().GetAssetCachedProviderId(); + } + + internal static string GetLoadPath(AddressableAssetGroup group, string name, BuildTarget target) + { + var bagSchema = group.GetSchema(); + if (bagSchema == null || bagSchema.LoadPath == null) + { + Debug.LogError("Unable to determine load path for " + name + ". Check that your default group is not '" + AddressableAssetSettings.PlayerDataGroupName + "'"); + return string.Empty; + } + + string loadPath = bagSchema.LoadPath.GetValue(group.Settings); + loadPath = loadPath.Replace('\\', '/'); + if (loadPath.EndsWith("/")) + loadPath += name; + else + loadPath = loadPath + "/" + name; + + if (!string.IsNullOrEmpty(bagSchema.UrlSuffix)) + loadPath += bagSchema.UrlSuffix; + if (!ResourceManagerConfig.ShouldPathUseWebRequest(loadPath) && !bagSchema.UseUnityWebRequestForLocalBundles) + { + char separator = PathSeparatorForPlatform(target); + if (separator != '/') + loadPath = loadPath.Replace('/', separator); + } + + return loadPath; + } + + internal static char PathSeparatorForPlatform(BuildTarget target) + { + switch (target) + { + case BuildTarget.StandaloneWindows64: + case BuildTarget.StandaloneWindows: + case BuildTarget.XboxOne: + return '\\'; + case BuildTarget.GameCoreXboxOne: + return '\\'; + case BuildTarget.Android: + return '/'; + default: + return '/'; + } + } + } +} diff --git a/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs.meta b/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs.meta index ae4072e1..4ed43f20 100644 --- a/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs.meta +++ b/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: b19f99025db4a1e44a095aa3f1284c54 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: b19f99025db4a1e44a095aa3f1284c54 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/BuildUtility.cs b/Editor/Build/BuildUtility.cs index 206220ac..121c3753 100644 --- a/Editor/Build/BuildUtility.cs +++ b/Editor/Build/BuildUtility.cs @@ -1,109 +1,109 @@ -using System.Collections.Generic; -using UnityEditor.AddressableAssets.Settings.GroupSchemas; -using UnityEditor.Build.Pipeline.Utilities; -using UnityEditor.Compilation; -using UnityEditor.SceneManagement; -using UnityEngine.SceneManagement; - -namespace UnityEditor.AddressableAssets.Build -{ - /// - /// Utility class for the Addressables Build Content process. - /// - public class BuildUtility - { - static HashSet s_EditorAssemblies = null; - - static HashSet editorAssemblies - { - get - { - if (s_EditorAssemblies == null) - { - s_EditorAssemblies = new HashSet(); - foreach (var assembly in CompilationPipeline.GetAssemblies()) - { - if ((assembly.flags & AssemblyFlags.EditorAssembly) != 0) - s_EditorAssemblies.Add(assembly.name); - } - } - - return s_EditorAssemblies; - } - } - - /// - /// Determines if the given assembly is an editor assembly. - /// - /// The assembly. - /// Returns true if the assembly is an editor assembly. Returns false otherwise. - public static bool IsEditorAssembly(System.Reflection.Assembly assembly) - { - var splitName = assembly.FullName.Split(','); - return splitName.Length > 0 && editorAssemblies.Contains(splitName[0]); - } - - /// - /// Creates a new bundle name using its hash and a given naming style. - /// - /// The bundle naming style. - /// The bundle hash. - /// The original bundle name. - /// Returns the new bundle name. - public static string GetNameWithHashNaming(BundledAssetGroupSchema.BundleNamingStyle schemaBundleNaming, string hash, string sourceBundleName) - { - string result = sourceBundleName; - switch (schemaBundleNaming) - { - case BundledAssetGroupSchema.BundleNamingStyle.AppendHash: - result = sourceBundleName.Replace(".bundle", "_" + hash + ".bundle"); - break; - case BundledAssetGroupSchema.BundleNamingStyle.NoHash: - break; - case BundledAssetGroupSchema.BundleNamingStyle.OnlyHash: - result = hash + ".bundle"; - break; - case BundledAssetGroupSchema.BundleNamingStyle.FileNameHash: - result = HashingMethods.Calculate(result) + ".bundle"; - break; - } - - return result; - } - - /// - /// Used during the build to check for unsaved scenes and provide a user popup if there are any. - /// - /// True if there were no unsaved scenes, or if user hits "Save and Continue" on popup. - /// False if any scenes were unsaved, and user hits "Cancel" on popup. - public static bool CheckModifiedScenesAndAskToSave() - { - var dirtyScenes = new List(); - - for (int i = 0; i < SceneManager.sceneCount; ++i) - { - var scene = SceneManager.GetSceneAt(i); - if (scene.isDirty) - { - dirtyScenes.Add(scene); - } - } - - if (dirtyScenes.Count > 0) - { - if (EditorUtility.DisplayDialog( - "Unsaved Scenes", "Modified Scenes must be saved to continue.", - "Save and Continue", "Cancel")) - { - EditorSceneManager.SaveScenes(dirtyScenes.ToArray()); - } - else - { - return false; - } - } - - return true; - } - } -} +using System.Collections.Generic; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEditor.Build.Pipeline.Utilities; +using UnityEditor.Compilation; +using UnityEditor.SceneManagement; +using UnityEngine.SceneManagement; + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// Utility class for the Addressables Build Content process. + /// + public class BuildUtility + { + static HashSet s_EditorAssemblies = null; + + static HashSet editorAssemblies + { + get + { + if (s_EditorAssemblies == null) + { + s_EditorAssemblies = new HashSet(); + foreach (var assembly in CompilationPipeline.GetAssemblies()) + { + if ((assembly.flags & AssemblyFlags.EditorAssembly) != 0) + s_EditorAssemblies.Add(assembly.name); + } + } + + return s_EditorAssemblies; + } + } + + /// + /// Determines if the given assembly is an editor assembly. + /// + /// The assembly. + /// Returns true if the assembly is an editor assembly. Returns false otherwise. + public static bool IsEditorAssembly(System.Reflection.Assembly assembly) + { + var splitName = assembly.FullName.Split(','); + return splitName.Length > 0 && editorAssemblies.Contains(splitName[0]); + } + + /// + /// Creates a new bundle name using its hash and a given naming style. + /// + /// The bundle naming style. + /// The bundle hash. + /// The original bundle name. + /// Returns the new bundle name. + public static string GetNameWithHashNaming(BundledAssetGroupSchema.BundleNamingStyle schemaBundleNaming, string hash, string sourceBundleName) + { + string result = sourceBundleName; + switch (schemaBundleNaming) + { + case BundledAssetGroupSchema.BundleNamingStyle.AppendHash: + result = sourceBundleName.Replace(".bundle", "_" + hash + ".bundle"); + break; + case BundledAssetGroupSchema.BundleNamingStyle.NoHash: + break; + case BundledAssetGroupSchema.BundleNamingStyle.OnlyHash: + result = hash + ".bundle"; + break; + case BundledAssetGroupSchema.BundleNamingStyle.FileNameHash: + result = HashingMethods.Calculate(result) + ".bundle"; + break; + } + + return result; + } + + /// + /// Used during the build to check for unsaved scenes and provide a user popup if there are any. + /// + /// True if there were no unsaved scenes, or if user hits "Save and Continue" on popup. + /// False if any scenes were unsaved, and user hits "Cancel" on popup. + public static bool CheckModifiedScenesAndAskToSave() + { + var dirtyScenes = new List(); + + for (int i = 0; i < SceneManager.sceneCount; ++i) + { + var scene = SceneManager.GetSceneAt(i); + if (scene.isDirty) + { + dirtyScenes.Add(scene); + } + } + + if (dirtyScenes.Count > 0) + { + if (EditorUtility.DisplayDialog( + "Unsaved Scenes", "Modified Scenes must be saved to continue.", + "Save and Continue", "Cancel")) + { + EditorSceneManager.SaveScenes(dirtyScenes.ToArray()); + } + else + { + return false; + } + } + + return true; + } + } +} diff --git a/Editor/Build/BuildUtility.cs.meta b/Editor/Build/BuildUtility.cs.meta index 21c97f90..74a28fd1 100644 --- a/Editor/Build/BuildUtility.cs.meta +++ b/Editor/Build/BuildUtility.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: befd95e3f3af5eb49bf7c53d00cb4d44 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: befd95e3f3af5eb49bf7c53d00cb4d44 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/CcdBuildEvents.cs b/Editor/Build/CcdBuildEvents.cs index 8bc1f381..a250dcba 100644 --- a/Editor/Build/CcdBuildEvents.cs +++ b/Editor/Build/CcdBuildEvents.cs @@ -1,912 +1,1014 @@ -#if ENABLE_CCD -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using Unity.Services.Ccd.Management; -using Unity.Services.Ccd.Management.Models; -using Unity.Services.Core; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.AddressableAssets.Settings.GroupSchemas; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.AddressableAssets.ResourceLocators; - -namespace UnityEditor.AddressableAssets.Build -{ - /// - /// CCD Events used for building Addressables content with CCD. - /// - public class CcdBuildEvents - { - static CcdBuildEvents s_Instance; - - /// - /// The static instance of CcdBuildEvents. - /// - public static CcdBuildEvents Instance - { - get - { - if (s_Instance == null) - { - s_Instance = new CcdBuildEvents(); - s_Instance.RegisterNewBuildEvents(); - s_Instance.RegisterUpdateBuildEvents(); - } - return s_Instance; - } - } - - const string k_ContentStatePath = "addressables_content_state.bin"; - - internal void RegisterNewBuildEvents() - { - OnPreBuildEvents += s_Instance.VerifyBuildVersion; - OnPreBuildEvents += s_Instance.RefreshDataSources; - OnPreBuildEvents += s_Instance.VerifyTargetBucket; - OnPostBuildEvents += s_Instance.UploadContentState; - OnPostBuildEvents += s_Instance.UploadAndRelease; - } - - internal void RegisterUpdateBuildEvents() - { - OnPreUpdateEvents += s_Instance.VerifyBuildVersion; - OnPreUpdateEvents += s_Instance.RefreshDataSources; - OnPreUpdateEvents += s_Instance.DownloadContentStateBin; - OnPreUpdateEvents += s_Instance.VerifyTargetBucket; - OnPostUpdateEvents += s_Instance.UploadContentState; - OnPostUpdateEvents += s_Instance.UploadAndRelease; - } - - /// - /// Pre Addressables build event. - /// - public delegate Task PreEvent(AddressablesDataBuilderInput input); - - /// - /// Pre new build events. - /// Default events: - /// - /// - /// - public static event PreEvent OnPreBuildEvents; - - /// - /// Pre update build events. - /// Default events: - /// - /// - /// - /// - public static event PreEvent OnPreUpdateEvents; - - /// - /// Post Addressables build event. - /// - public delegate Task PostEvent(AddressablesDataBuilderInput input, - AddressablesPlayerBuildResult result); - - /// - /// Post new build events. - /// Default events: - /// - /// - /// - public static event PostEvent OnPostBuildEvents; - - /// - /// Post update build events. - /// Default events: - /// - /// - /// - public static event PostEvent OnPostUpdateEvents; - - internal async Task OnPreEvent(bool isUpdate, AddressablesDataBuilderInput input) - { - if (isUpdate) - { - return await InvokePreEvent(OnPreUpdateEvents, input); - } - return await InvokePreEvent(OnPreBuildEvents, input); - } - - internal async Task InvokePreEvent(PreEvent events, AddressablesDataBuilderInput input) - { - if (events == null) - { - - return true; - } - - var total = events.GetInvocationList().Length; - for (var i = 0; i < total; i++) - { - var e = (PreEvent)events.GetInvocationList()[i]; - var shouldContinue = await e.Invoke(input); - if (!shouldContinue) - { - return false; - } - } - return true; - } - - internal async Task OnPostEvent(bool isUpdate, AddressablesDataBuilderInput input, - AddressablesPlayerBuildResult result) - { - if (isUpdate) - { - return await InvokePostEvent(OnPostUpdateEvents, input, result); - } - return await InvokePostEvent(OnPostBuildEvents, input, result); - } - - internal async Task InvokePostEvent(PostEvent events, AddressablesDataBuilderInput input, - AddressablesPlayerBuildResult result) - { - if (events == null) - return true; - - var total = events.GetInvocationList().Length; - for (var i = 0; i < total; i++) - { - var e = (PostEvent)events.GetInvocationList()[i]; - var shouldContinue = await e.Invoke(input, result); - if (!shouldContinue) - { - // if a post-build step adds an error we have to log it manually - if (result != null && !string.IsNullOrEmpty(result.Error)) - { - Debug.LogError(result.Error); - } - - return false; - } - } - - return true; - - } - - /// - /// Prepend an event to the pre new build events. - /// - /// Pre build event - public static void PrependPreBuildEvent(PreEvent newEvent) - { - Delegate[] oldEvents = OnPreBuildEvents?.GetInvocationList(); - OnPreBuildEvents = newEvent; - if (oldEvents != null) - foreach (var t in oldEvents) - { - OnPreBuildEvents += (PreEvent)(t); - } - } - - /// - /// Prepend an event to the post new build events. - /// - /// Post build event - public static void PrependPostBuildEvent(PostEvent newEvent) - { - Delegate[] oldEvents = OnPostBuildEvents?.GetInvocationList(); - OnPostBuildEvents = newEvent; - if (oldEvents != null) - foreach (var t in oldEvents) - { - OnPostBuildEvents += (PostEvent)(t); - } - } - - /// - /// Prepend an event to the pre update build events. - /// - /// Pre build event - public static void PrependPreUpdateEvent(PreEvent newEvent) - { - Delegate[] oldEvents = OnPreUpdateEvents?.GetInvocationList(); - OnPreUpdateEvents = newEvent; - if (oldEvents != null) - foreach (var t in oldEvents) - { - OnPreUpdateEvents += (PreEvent)(t); - } - } - - /// - /// Prepend an event to the post update build events. - /// - /// Post build event - public static void PrependPostUpdateEvent(PostEvent newEvent) - { - Delegate[] oldEvents = OnPostUpdateEvents?.GetInvocationList(); - OnPostUpdateEvents = newEvent; - if (oldEvents != null) - foreach (var t in oldEvents) - { - OnPostUpdateEvents += (PostEvent)(t); - } - } - - public async Task VerifyBuildVersion(AddressablesDataBuilderInput input) - { - if (string.IsNullOrWhiteSpace(input.AddressableSettings.OverridePlayerVersion)) - { - Addressables.LogWarning("When using CCD it is recommended that you set a 'Player Version Override' in Addressables Settings. You can have it use the Player build version by setting it to [UnityEditor.PlayerSettings.bundleVersion]."); - Addressables.LogWarning("Documentation on how to disable this warning is available in the example DisableBuildWarnings.cs."); - } - return true; - } - - /// - /// Update the CCD data source settings. - /// - /// Addressables data builder context - /// - public async Task RefreshDataSources(AddressablesDataBuilderInput input) - { - try - { - var projectId = CloudProjectSettings.projectId; - await ProfileDataSourceSettings.UpdateCCDDataSourcesAsync(projectId, true); - } - catch (Exception e) - { - Debug.LogError(e.ToString()); - return false; - } - return true; - } - - internal async Task LoopGroups(AddressableAssetSettings settings, Func> action) - { - var tasks = new List>(); - foreach (var group in settings.groups) - { - if (group == null) - { - continue; - } - - var schema = group.GetSchema(); - if (schema == null) - { - continue; - } - tasks.Add(action(settings, group, schema)); - } - var results = await Task.WhenAll(tasks.ToArray()); - foreach (var result in results) - { - // if any fail, all fail - if (result == false) - { - return false; - } - } - return true; - } - - /// - /// Verify that the targeted CCD bucket exists or create it. - /// - /// Addressables data builder context - /// - public async Task VerifyTargetBucket(AddressablesDataBuilderInput input) - { - if (input.AddressableSettings == null) - { - string error; - if (EditorApplication.isUpdating) - error = "Addressable Asset Settings does not exist. EditorApplication.isUpdating was true."; - else if (EditorApplication.isCompiling) - error = "Addressable Asset Settings does not exist. EditorApplication.isCompiling was true."; - else - error = "Addressable Asset Settings does not exist. Failed to create."; - Debug.LogError(error); - return false; - } - - if (!hasRemoteGroups(input.AddressableSettings)) - { - Debug.LogWarning("No Addressable Asset Groups have been marked remote or the current profile is not using CCD."); - if (input.AddressableSettings.BuildRemoteCatalog) - { - Debug.LogWarning("A remote catalog will be built without any remote Asset Bundles."); - } - - } - - // Reclean directory before every build - if (Directory.Exists(AddressableAssetSettings.kCCDBuildDataPath)) - { - Directory.Delete(AddressableAssetSettings.kCCDBuildDataPath, true); - } - - return await LoopGroups(input.AddressableSettings, verifyTargetBucket); - } - - internal bool hasRemoteGroups(AddressableAssetSettings settings) - { - foreach (var group in settings.groups) - { - if (group == null) - { - continue; - } - - var schema = group.GetSchema(); - if (schema == null) - { - continue; - } - var foundGroupType = GetGroupType(settings, schema); - if (isCCDGroup(foundGroupType)) - { - return true; - } - } - return false; - } - - internal bool isCCDGroup(ProfileGroupType groupType) - { - - if (groupType == null) - { - return false; - } - if (IsUsingManager(groupType)) - { - return true; - } - return groupType.GroupTypePrefix.StartsWith("CCD"); - } - - internal async Task verifyTargetBucket(AddressableAssetSettings settings, AddressableAssetGroup group, BundledAssetGroupSchema schema) - { - AddressableAssetSettings.NullifyBundleFileIds(group); - - // if not using the manager try to lookup the bucket and verify it's not promotion only - var existingGroupType = GetDefaultGroupType(ProfileDataSourceSettings.GetSettings()); - if (!IsUsingManager(settings, schema)) - { - if (existingGroupType != null) - { - var promotionOnly = IsPromotionOnlyBucket(settings, schema); - if (promotionOnly) - { - Debug.LogError("Cannot upload to Promotion Only bucket."); - return false; - } - } - return true; - } - - // CcdManagedData.ConfigState.Override means it has been overriden by the customer at build time - if (settings.m_CcdManagedData.State == CcdManagedData.ConfigState.Override) - { - return true; - } - - // Target bucket should only be verified if Automatic profile type - settings.m_CcdManagedData.EnvironmentId = ProfileDataSourceSettings.GetSettings().currentEnvironment.id; - settings.m_CcdManagedData.EnvironmentName = ProfileDataSourceSettings.GetSettings().currentEnvironment.name; - - // existing automatic bucket loaded from cache - if (existingGroupType != null) - { - var promotionOnly = IsPromotionOnlyBucket(settings, schema); - if (promotionOnly) - { - Debug.LogError("Cannot upload to Promotion Only bucket."); - return false; - } - settings.m_CcdManagedData.BucketId = existingGroupType - .GetVariableBySuffix($"{nameof(CcdBucket)}{nameof(CcdBucket.Id)}").Value; - settings.m_CcdManagedData.Badge = existingGroupType - .GetVariableBySuffix($"{nameof(CcdBadge)}{nameof(CcdBadge.Name)}").Value; - } - // otherwise try to create - else - { - try - { - var api = CcdManagement.Instance; - var createdBucket = await CreateManagedBucket(api, ProfileDataSourceSettings.GetSettings().currentEnvironment.id, - EditorUserBuildSettings.activeBuildTarget.ToString()); - if (createdBucket.Attributes.PromoteOnly) - { - Debug.LogError("Cannot upload to Promotion Only bucket."); - return false; - } - settings.m_CcdManagedData.BucketId = createdBucket.Id.ToString(); - settings.m_CcdManagedData.Badge = "latest"; - } - catch (Exception e) - { - Debug.LogError(e.ToString()); - return false; - } - } - - return true; - } - - /// - /// Download addressables_content_state.bin from the CCD managed bucket. - /// - /// Addressables data builder context - /// - public async Task DownloadContentStateBin(AddressablesDataBuilderInput input) - { - if (!input.AddressableSettings.BuildRemoteCatalog) - { - Debug.LogWarning("Not downloading content state because 'Build Remote Catalog' is not checked in Addressable Asset Settings. This will disable content updates"); - return true; - } - - var settings = input.AddressableSettings; - var groupType = getRemoteCatalogGroupType(settings); - if (groupType == null) - { - Debug.LogError("Could not find remote catalog paths"); - return false; - } - - if (!this.isCCDGroup(groupType)) - { - Debug.LogError("Content state could not be downloaded as the remote catalog is not targeting CCD"); - return false; - } - - try - { - SetEnvironmentId(settings, groupType); - var bucketId = GetBucketId(settings, groupType); - if (bucketId == null) - { - Debug.LogError("Content state could not be downloaded as no bucket was specified. This is populated for managed profiles in the VerifyBucket event."); - return false; - } - var api = CcdManagement.Instance; - var ccdEntry = await GetEntryByPath(api, new Guid(bucketId), k_ContentStatePath); - if (ccdEntry != null) - { - var contentStream = await api.GetContentAsync(new EntryOptions(new Guid(bucketId), ccdEntry.Entryid)); - - var contentStatePath = Path.Combine(settings.GetContentStateBuildPath(), k_ContentStatePath); - if (!Directory.Exists(contentStatePath)) - Directory.CreateDirectory(Path.GetDirectoryName(contentStatePath)); - else if (File.Exists(contentStatePath)) - File.Delete(contentStatePath); - - using (var fileStream = File.Create(contentStatePath)) - { - contentStream.CopyTo(fileStream); - } - } - } - catch (Exception e) - { - Debug.LogError(e.ToString()); - return false; - } - return true; - } - - /// - /// Upload content to the CCD managed bucket and create a release. - /// - /// Addressables data builder context - /// Addressables build result - /// - public async Task UploadAndRelease(AddressablesDataBuilderInput input, - AddressablesPlayerBuildResult result) - { - // Verify files exist that need uploading - var foundRemoteContent = result.FileRegistry?.GetFilePaths() - .Any(path => path.StartsWith(AddressableAssetSettings.kCCDBuildDataPath)) == true; - - if (!foundRemoteContent) - { - Debug.LogWarning( - "Skipping upload and release as no remote content was found to upload. Ensure you have at least one content group's 'Build & Load Path' set to Remote."); - return false; - } - - try - { - //Getting files - Debug.Log("Creating and uploading entries"); - var startDirectory = new DirectoryInfo(AddressableAssetSettings.kCCDBuildDataPath); - var buildData = CreateData(startDirectory); - - - //Creating a release for each bucket - var defaultEnvironmentId = ProfileDataSourceSettings.GetSettings().currentEnvironment.id; - - await UploadAndRelease(CcdManagement.Instance, input.AddressableSettings, defaultEnvironmentId, buildData); - } - catch (Exception e) - { - Debug.LogError(e.ToString()); - return false; - } - - return true; - } - - private ProfileGroupType getRemoteCatalogGroupType(AddressableAssetSettings settings) - { - var buildPath = settings.RemoteCatalogBuildPath; - var loadPath = settings.RemoteCatalogLoadPath; - var groupType = GetGroupType(settings, buildPath, loadPath); - return groupType; - - } - - - /// - /// Upload addressables_content_state.bin to the CCD managed bucket. - /// - /// Addressables data builder context - /// Addressables build result - /// - public async Task UploadContentState(AddressablesDataBuilderInput input, - AddressablesPlayerBuildResult result) - { - - if (!input.AddressableSettings.BuildRemoteCatalog) - { - Debug.LogWarning("Not uploading content state, because 'Build Remote Catalog' is not checked in Addressable Asset Settings. This will disable content updates"); - return true; - } - - var settings = input.AddressableSettings; - var groupType = getRemoteCatalogGroupType(settings); - if (groupType == null) - { - Debug.LogError("Could not find remote catalog paths"); - return false; - } - - if (!this.isCCDGroup(groupType)) - { - Debug.LogError("Content state could not be uploaded as the remote catalog is not targeting CCD"); - return false; - } - - try - { - SetEnvironmentId(settings, groupType); - var bucketId = GetBucketId(settings, groupType); - if (bucketId == null) - { - Debug.LogError("Content state could not be uploaded as no bucket was specified. This is populated for managed profiles in the VerifyBucket event."); - return false; - } - var api = CcdManagement.Instance; - - var contentStatePath = Path.Combine(settings.GetContentStateBuildPath(), k_ContentStatePath); - if (!File.Exists(contentStatePath)) - { - Debug.LogError($"Content state file is missing {contentStatePath}"); - return false; - } - var contentHash = AddressableAssetUtility.GetMd5Hash(contentStatePath); - - using (var stream = File.OpenRead(contentStatePath)) - { - - var entryModelOptions = new EntryModelOptions(k_ContentStatePath, contentHash, (int)stream.Length) - { - UpdateIfExists = true - }; - var createdEntry = await api.CreateOrUpdateEntryByPathAsync( - new EntryByPathOptions(new Guid(bucketId), k_ContentStatePath), - entryModelOptions); - - var uploadContentOptions = new UploadContentOptions( - new Guid(bucketId), createdEntry.Entryid, stream); - await api.UploadContentAsync(uploadContentOptions); - } - } - catch (Exception e) - { - Debug.LogError(e.ToString()); - return false; - } - return true; - } - - internal bool IsPromotionOnlyBucket(AddressableAssetSettings settings, BundledAssetGroupSchema schema) - { - if (schema != null) - { - var foundGroupType = GetGroupType(settings, schema); - if (foundGroupType != null && foundGroupType.GroupTypePrefix.StartsWith("CCD")) - { - if (bool.Parse(foundGroupType.GetVariableBySuffix(nameof(CcdBucket.Attributes.PromoteOnly)).Value)) - { - Debug.LogError("Cannot upload to Promotion Only bucket."); - return true; - } - } - - } - return false; - } - - internal ProfileGroupType GetGroupType(AddressableAssetSettings settings, BundledAssetGroupSchema schema) - { - - return GetGroupType(settings, schema.BuildPath, schema.LoadPath); - } - - internal ProfileGroupType GetGroupType(AddressableAssetSettings settings, ProfileValueReference buildPath, ProfileValueReference loadPath) - { - // we need the "unresolved" value since we're tring to match it to its original type - Debug.Log("Loading from active profile id " + settings.activeProfileId); - var buildPathValue = settings.profileSettings.GetValueById(settings.activeProfileId, buildPath.Id); - var loadPathValue = settings.profileSettings.GetValueById(settings.activeProfileId, loadPath.Id); - Debug.Log(loadPathValue); - if (buildPathValue == null || loadPathValue == null) - { - return null; - } - - var groupType = new ProfileGroupType("temp"); - groupType.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kBuildPath, buildPathValue)); - groupType.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kLoadPath, loadPathValue)); - return ProfileDataSourceSettings.GetSettings().FindGroupType(groupType); - } - - - internal bool IsUsingManager(AddressableAssetSettings settings, BundledAssetGroupSchema schema) - { - var groupType = GetGroupType(settings, schema); - return IsUsingManager(groupType); - } - - internal bool IsUsingManager(ProfileGroupType groupType) - { - if (groupType == null) - { - return false; - } - return groupType.GroupTypePrefix == AddressableAssetSettings.CcdManagerGroupTypePrefix; - } - - internal void SetEnvironmentId(AddressableAssetSettings settings, ProfileGroupType groupType) - { - string environmentId = null; - if (!IsUsingManager(groupType)) - { - // if not using the manager load the bucketID from the group type - environmentId = groupType.GetVariableBySuffix($"{nameof(ProfileDataSourceSettings.Environment)}{nameof(ProfileDataSourceSettings.Environment.id)}").Value; - } - else if (settings.m_CcdManagedData != null) - { - environmentId = settings.m_CcdManagedData.EnvironmentId; - } - - if (environmentId == null) - { - throw new Exception("unable to determine environment ID."); - } - - CcdManagement.SetEnvironmentId(environmentId); - } - - internal string GetBucketId(AddressableAssetSettings settings, ProfileGroupType groupType) - { - if (!IsUsingManager(groupType)) - { - // if not using the manager load the bucketID from the group type - return groupType.GetVariableBySuffix($"{nameof(CcdBucket)}{nameof(CcdBucket.Id)}").Value; - } - if (settings.m_CcdManagedData != null) - { - return settings.m_CcdManagedData.BucketId; - } - return null; - } - - static ProfileGroupType GetDefaultGroupType(ProfileDataSourceSettings dataSourceSettings) - { - //Find existing bucketId - var groupTypes = dataSourceSettings.GetGroupTypesByPrefix(string.Join( - ProfileGroupType.k_PrefixSeparator.ToString(), "CCD", dataSourceSettings.currentEnvironment.projectGenesisId, - dataSourceSettings.currentEnvironment.id)); - return groupTypes.FirstOrDefault(gt => - gt.GetVariableBySuffix($"{nameof(CcdBucket)}{nameof(CcdBucket.Name)}").Value == - EditorUserBuildSettings.activeBuildTarget.ToString()); - } - - async Task CreateManagedBucket(ICcdManagementServiceSdk api, string envId, string bucketName) - { - CcdBucket ccdBucket; - try - { - CcdManagement.SetEnvironmentId(envId); - ccdBucket = await api.CreateBucketAsync( - new CreateBucketOptions(bucketName)); - } - catch (CcdManagementException e) - { - if (e.ErrorCode == CcdManagementErrorCodes.AlreadyExists) - { - var buckets = await ProfileDataSourceSettings.GetAllBucketsAsync(envId); - ccdBucket = buckets.First(bucket => - bucket.Value.Name == EditorUserBuildSettings.activeBuildTarget.ToString()).Value; - } - else - { - throw; - } - } - return ccdBucket; - } - - async Task GetEntryByPath(ICcdManagementServiceSdk api, Guid bucketId, string path) - { - CcdEntry ccdEntry = null; - try - { - ccdEntry = await api.GetEntryByPathAsync(new EntryByPathOptions(bucketId, path)); - } - catch (CcdManagementException e) - { - if (e.ErrorCode != CommonErrorCodes.NotFound) - { - throw; - } - } - return ccdEntry; - } - - CcdBuildDataFolder CreateData(DirectoryInfo startDirectory) - { - var buildDataFolder = new CcdBuildDataFolder - { - Name = AddressableAssetSettings.kCCDBuildDataPath, - Location = startDirectory.FullName - }; - buildDataFolder.GetChildren(startDirectory); - return buildDataFolder; - } - - int StartProgress(string description) - { -#if UNITY_2020_1_OR_NEWER - return Progress.Start("CCD", description, Progress.Options.Managed); -#else - Debug.Log(description); - return -1; -#endif - } - - void RemoveProgress(int progressId) - { -#if UNITY_2020_1_OR_NEWER - Progress.Remove(progressId); -#endif - } - - void ReportProgress(int progressId, float progress, string message) - { -#if UNITY_2020_1_OR_NEWER - Progress.Report(progressId, progress, message); -#else - Debug.Log($"[{progress}] {message}"); -#endif - } - - // Do not use Addressable.Log in this method as it may not be executed on the main thread - async Task UploadAndRelease(ICcdManagementServiceSdk api, AddressableAssetSettings settings, string defaultEnvironmentId, CcdBuildDataFolder buildData) - { - var progressId = StartProgress("Upload and Release"); - try - { - foreach (var env in buildData.Environments) - { - CcdManagement.SetEnvironmentId(env.Name); - - if (env.Name == ProfileDataSourceSettings.MANAGED_ENVIRONMENT) - { - CcdManagement.SetEnvironmentId(defaultEnvironmentId); - } - - foreach (var bucket in env.Buckets) - { - Guid bucketId; - var bucketIdString = bucket.Name == ProfileDataSourceSettings.MANAGED_BUCKET - ? settings.m_CcdManagedData.BucketId - : bucket.Name; - if (String.IsNullOrEmpty(bucketIdString)) - { - Debug.LogError($"Invalid bucket ID for {bucket.Name}"); - continue; - } - bucketId = Guid.Parse(bucketIdString); - - foreach (var badge in bucket.Badges) - { - if (badge.Name == ProfileDataSourceSettings.MANAGED_BADGE) - { - badge.Name = "latest"; - } - var entries = new List(); - var total = badge.Files.Count(); - for (var i = 0; i < total; i++) - { - var file = badge.Files[i]; - var contentHash = AddressableAssetUtility.GetMd5Hash(file.FullName); - using (var stream = File.OpenRead(file.FullName)) - { - var entryPath = file.Name; - var entryModelOptions = new EntryModelOptions(entryPath, contentHash, (int)stream.Length) - { - UpdateIfExists = true - }; - ReportProgress(progressId, (i + 1) / total, $"Creating Entry {entryPath}"); - var createdEntry = await api.CreateOrUpdateEntryByPathAsync(new EntryByPathOptions(bucketId, entryPath), - entryModelOptions).ConfigureAwait(false); - Debug.Log($"Created Entry {entryPath}"); - - ReportProgress(progressId, (i + 1) / total, $"Uploading Entry {entryPath}"); - var uploadContentOptions = new UploadContentOptions(bucketId, createdEntry.Entryid, stream); - await api.UploadContentAsync(uploadContentOptions).ConfigureAwait(false); - - ReportProgress(progressId, (i + 1) / total, $"Uploaded Entry {entryPath}"); - entries.Add(new CcdReleaseEntryCreate(createdEntry.Entryid, createdEntry.CurrentVersionid)); - } - } - - // Add content_sate.bin to release if present - var contentStateEntry = await GetEntryByPath(api, bucketId, k_ContentStatePath); - if (contentStateEntry != null) - entries.Add(new CcdReleaseEntryCreate(contentStateEntry.Entryid, contentStateEntry.CurrentVersionid)); - - //Creating release - ReportProgress(progressId, total, "Creating release"); - Debug.Log("Creating release."); - var release = await api.CreateReleaseAsync(new CreateReleaseOptions(bucketId) - { - Entries = entries, - Notes = $"Automated release created for {badge.Name}" - }).ConfigureAwait(false); - Debug.Log($"Release {release.Releaseid} created."); - - //Don't update latest badge (as it always updates) - if (badge.Name != "latest") - { - ReportProgress(progressId, total, "Updating badge"); - Debug.Log("Updating badge."); - var badgeRes = await api.AssignBadgeAsync(new AssignBadgeOptions(bucketId, badge.Name, release.Releaseid)) - .ConfigureAwait(false); - Debug.Log($"Badge {badgeRes.Name} updated."); - } - } - } - } - } - catch (Exception e) - { - Debug.LogError(e.ToString()); - } - finally - { - RemoveProgress(progressId); - } - } - - } -} -#endif - +#if ENABLE_CCD +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Unity.Services.Ccd.Management; +using Unity.Services.Ccd.Management.Models; +using Unity.Services.Core; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.AddressableAssets.ResourceLocators; + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// CCD Events used for building Addressables content with CCD. + /// + public class CcdBuildEvents + { + static CcdBuildEvents s_Instance; + + /// + /// The static instance of CcdBuildEvents. + /// + public static CcdBuildEvents Instance + { + get + { + if (s_Instance == null) + { + s_Instance = new CcdBuildEvents(); + s_Instance.RegisterNewBuildEvents(); + s_Instance.RegisterUpdateBuildEvents(); + } + return s_Instance; + } + } + + const string k_ContentStatePath = "addressables_content_state.bin"; + + internal void RegisterNewBuildEvents() + { + OnPreBuildEvents += s_Instance.VerifyBuildVersion; + OnPreBuildEvents += s_Instance.RefreshDataSources; + OnPreBuildEvents += s_Instance.VerifyTargetBucket; + OnPostBuildEvents += s_Instance.UploadContentState; + OnPostBuildEvents += s_Instance.UploadAndRelease; + } + + internal void RegisterUpdateBuildEvents() + { + OnPreUpdateEvents += s_Instance.VerifyBuildVersion; + OnPreUpdateEvents += s_Instance.RefreshDataSources; + OnPreUpdateEvents += s_Instance.DownloadContentStateBin; + OnPreUpdateEvents += s_Instance.VerifyTargetBucket; + OnPostUpdateEvents += s_Instance.UploadContentState; + OnPostUpdateEvents += s_Instance.UploadAndRelease; + } + + /// + /// Pre Addressables build event. + /// + public delegate Task PreEvent(AddressablesDataBuilderInput input); + + /// + /// Pre new build events. + /// Default events: + /// + /// + /// + public static event PreEvent OnPreBuildEvents; + + /// + /// Pre update build events. + /// Default events: + /// + /// + /// + /// + public static event PreEvent OnPreUpdateEvents; + + /// + /// Post Addressables build event. + /// + public delegate Task PostEvent(AddressablesDataBuilderInput input, + AddressablesPlayerBuildResult result); + + /// + /// Post new build events. + /// Default events: + /// + /// + /// + public static event PostEvent OnPostBuildEvents; + + /// + /// Post update build events. + /// Default events: + /// + /// + /// + public static event PostEvent OnPostUpdateEvents; + + internal async Task OnPreEvent(bool isUpdate, AddressablesDataBuilderInput input) + { + if (isUpdate) + { + return await InvokePreEvent(OnPreUpdateEvents, input); + } + return await InvokePreEvent(OnPreBuildEvents, input); + } + + internal async Task InvokePreEvent(PreEvent events, AddressablesDataBuilderInput input) + { + if (events == null) + { + + return true; + } + + var total = events.GetInvocationList().Length; + for (var i = 0; i < total; i++) + { + var e = (PreEvent)events.GetInvocationList()[i]; + var shouldContinue = await e.Invoke(input); + if (!shouldContinue) + { + return false; + } + } + return true; + } + + internal async Task OnPostEvent(bool isUpdate, AddressablesDataBuilderInput input, + AddressablesPlayerBuildResult result) + { + if (isUpdate) + { + return await InvokePostEvent(OnPostUpdateEvents, input, result); + } + return await InvokePostEvent(OnPostBuildEvents, input, result); + } + + internal async Task InvokePostEvent(PostEvent events, AddressablesDataBuilderInput input, + AddressablesPlayerBuildResult result) + { + if (events == null) + return true; + + var total = events.GetInvocationList().Length; + for (var i = 0; i < total; i++) + { + var e = (PostEvent)events.GetInvocationList()[i]; + var shouldContinue = await e.Invoke(input, result); + if (!shouldContinue) + { + // if a post-build step adds an error we have to log it manually + if (result != null && !string.IsNullOrEmpty(result.Error)) + { + Addressables.LogError(result.Error); + } + + return false; + } + } + + return true; + + } + + /// + /// Prepend an event to the pre new build events. + /// + /// Pre build event + public static void PrependPreBuildEvent(PreEvent newEvent) + { + Delegate[] oldEvents = OnPreBuildEvents?.GetInvocationList(); + OnPreBuildEvents = newEvent; + if (oldEvents != null) + foreach (var t in oldEvents) + { + OnPreBuildEvents += (PreEvent)(t); + } + } + + /// + /// Prepend an event to the post new build events. + /// + /// Post build event + public static void PrependPostBuildEvent(PostEvent newEvent) + { + Delegate[] oldEvents = OnPostBuildEvents?.GetInvocationList(); + OnPostBuildEvents = newEvent; + if (oldEvents != null) + foreach (var t in oldEvents) + { + OnPostBuildEvents += (PostEvent)(t); + } + } + + /// + /// Prepend an event to the pre update build events. + /// + /// Pre build event + public static void PrependPreUpdateEvent(PreEvent newEvent) + { + Delegate[] oldEvents = OnPreUpdateEvents?.GetInvocationList(); + OnPreUpdateEvents = newEvent; + if (oldEvents != null) + foreach (var t in oldEvents) + { + OnPreUpdateEvents += (PreEvent)(t); + } + } + + /// + /// Prepend an event to the post update build events. + /// + /// Post build event + public static void PrependPostUpdateEvent(PostEvent newEvent) + { + Delegate[] oldEvents = OnPostUpdateEvents?.GetInvocationList(); + OnPostUpdateEvents = newEvent; + if (oldEvents != null) + foreach (var t in oldEvents) + { + OnPostUpdateEvents += (PostEvent)(t); + } + } + + internal void ConfigureCcdManagement(AddressableAssetSettings settings, string environmentId) + { + CcdManagement.SetEnvironmentId(environmentId); +#if CCD_REQUEST_LOGGING + CcdManagement.LogRequests = settings.CCDLogRequests; + CcdManagement.LogRequestHeaders = settings.CCDLogRequestHeaders; +#endif + } + + public Task VerifyBuildVersion(AddressablesDataBuilderInput input) + { + if (string.IsNullOrWhiteSpace(input.AddressableSettings.OverridePlayerVersion)) + { + Addressables.LogWarning("When using CCD it is recommended that you set a 'Player Version Override' in Addressables Settings. You can have it use the Player build version by setting it to [UnityEditor.PlayerSettings.bundleVersion]."); + Addressables.LogWarning("Documentation on how to disable this warning is available in the example DisableBuildWarnings.cs."); + } + return Task.FromResult(true); + } + + /// + /// Update the CCD data source settings. + /// + /// Addressables data builder context + /// + public async Task RefreshDataSources(AddressablesDataBuilderInput input) + { + return await RefreshDataSources(); + } + internal async Task RefreshDataSources() + { + try + + { + var projectId = CloudProjectSettings.projectId; + await ProfileDataSourceSettings.UpdateCCDDataSourcesAsync(projectId, true); + } + catch (Exception e) + { + Addressables.LogError(e.ToString()); + return false; + } + return true; + } + + internal async Task LoopGroups(AddressableAssetSettings settings, Func> action) + { + var tasks = new List>(); + foreach (var group in settings.groups) + { + if (group == null) + { + continue; + } + + var schema = group.GetSchema(); + if (schema == null) + { + continue; + } + tasks.Add(action(settings, group, schema)); + } + var results = await Task.WhenAll(tasks.ToArray()); + foreach (var result in results) + { + // if any fail, all fail + if (result == false) + { + return false; + } + } + return true; + } + + /// + /// Verify that the targeted CCD bucket exists or create it. + /// + /// Addressables data builder context + /// + public async Task VerifyTargetBucket(AddressablesDataBuilderInput input) + { + try + { + if (input.AddressableSettings == null) + { + string error; + if (EditorApplication.isUpdating) + error = "Addressable Asset Settings does not exist. EditorApplication.isUpdating was true."; + else if (EditorApplication.isCompiling) + error = "Addressable Asset Settings does not exist. EditorApplication.isCompiling was true."; + else + error = "Addressable Asset Settings does not exist. Failed to create."; + Addressables.LogError(error); + return false; + } + + if (!hasRemoteGroups(input.AddressableSettings)) + { + Addressables.LogWarning("No Addressable Asset Groups have been marked remote or the current profile is not using CCD."); + if (input.AddressableSettings.BuildRemoteCatalog) + { + Addressables.LogWarning("A remote catalog will be built without any remote Asset Bundles."); + } + } + + if (input.AddressableSettings.BuildRemoteCatalog) + { + var dataSource = getRemoteCatalogDataSource(input.AddressableSettings); + var success = await verifyTargetBucket(input.AddressableSettings, "Remote Catalog", dataSource); + if (!success) + { + return false; + } + } + + // Reclean directory before every build + if (Directory.Exists(AddressableAssetSettings.kCCDBuildDataPath)) + { + Directory.Delete(AddressableAssetSettings.kCCDBuildDataPath, true); + } + } + catch (Exception e) + { + Addressables.LogError($"Unable to verify target bucket: {e.Message}"); + return false; + } + + return await LoopGroups(input.AddressableSettings, verifyTargetBucket); + } + + internal bool hasRemoteGroups(AddressableAssetSettings settings) + { + foreach (var group in settings.groups) + { + if (group == null) + { + continue; + } + + var schema = group.GetSchema(); + if (schema == null) + { + continue; + } + var dataSource = GetDataSource(settings, schema); + if (isCCDGroup(dataSource)) + { + return true; + } + } + return false; + } + + internal bool isCCDGroup(ProfileGroupType dataSource) + { + + if (dataSource == null) + { + return false; + } + if (IsUsingManager(dataSource)) + { + return true; + } + return dataSource.GroupTypePrefix.StartsWith("CCD"); + } + + internal async Task verifyTargetBucket(AddressableAssetSettings settings, AddressableAssetGroup group, BundledAssetGroupSchema schema) + { + AddressableAssetSettings.NullifyBundleFileIds(group); + var dataSource = GetDataSource(settings, schema); + return await verifyTargetBucket(settings, group.Name, dataSource); + + } + internal async Task verifyTargetBucket(AddressableAssetSettings settings, string groupName, ProfileGroupType dataSource) + { + try + { + + // if not using the manager try to lookup the bucket and verify it's not promotion only + if (!IsUsingManager(dataSource)) + { + if (dataSource == null) + { + return true; + } + var promotionOnly = IsPromotionOnlyBucket(dataSource); + if (promotionOnly) + { + Addressables.LogError("Cannot upload to Promotion Only bucket."); + return false; + } + return true; + } + + // CcdManagedData.ConfigState.Override means it has been overriden by the customer at build time + if (settings.m_CcdManagedData.State == CcdManagedData.ConfigState.Override) + { + return true; + } + + + // existing automatic bucket loaded from cache + var bucketIdVariable = dataSource + .GetVariableBySuffix($"{nameof(CcdBucket)}{nameof(CcdBucket.Id)}"); + if (bucketIdVariable != null) + { + var promotionOnly = IsPromotionOnlyBucket(dataSource); + if (promotionOnly) + { + Debug.LogError("Cannot upload to Promotion Only bucket."); + return false; + } + + PopulateCcdManagedData(settings, settings.activeProfileId); + return true; + } + + // otherwise try to create + CcdManagement.SetEnvironmentId(settings.m_CcdManagedData.EnvironmentId); + await CreateManagedBucket(EditorUserBuildSettings.activeBuildTarget.ToString()); + // we created a bucket so refresh our data sources so we ensure they're up to date + await RefreshDataSources(); + + PopulateCcdManagedData(settings, settings.activeProfileId); + + // I should put this value into the data source list + return true; + } + catch (Exception e) + { + Addressables.LogError($"Unable to verify target bucket for {groupName}: {e.Message}"); + return false; + } + } + + public void PopulateCcdManagedData(AddressableAssetSettings settings, string profileId) + { + // reset the state data + settings.m_CcdManagedData = new CcdManagedData(); + var buildPath = settings.profileSettings.GetVariableId(AddressableAssetSettings.kRemoteBuildPath); + var loadPath = settings.profileSettings.GetVariableId(AddressableAssetSettings.kRemoteLoadPath); + if (buildPath == null || loadPath == null) + { + Addressables.Log($"Not populating CCD managed data. No remote paths are configured for profile {settings.profileSettings.GetProfileName(profileId)}."); + return; + } + + var dataSource = GetDataSource(settings, buildPath, loadPath); + if (dataSource == null) + { + Addressables.Log($"Not populating CCD managed data. Data source not found. Try refreshing data sources in the profile window."); + return; + } + + if (!IsUsingManager(dataSource)) + { + return; + } + + var bucketIdVariable = dataSource + .GetVariableBySuffix($"{nameof(CcdBucket)}{nameof(CcdBucket.Id)}"); + if (bucketIdVariable == null) + { + Addressables.Log("Not populating CCD managed data. No bucket ID found. Try refreshing data sources in the profile window."); + return; + } + settings.m_CcdManagedData.BucketId = bucketIdVariable.Value; + settings.m_CcdManagedData.Badge = dataSource + .GetVariableBySuffix($"{nameof(CcdBadge)}{nameof(CcdBadge.Name)}").Value; + + + // Target bucket should only be verified if Automatic profile type + settings.m_CcdManagedData.EnvironmentId = ProfileDataSourceSettings.GetSettings().GetEnvironmentId(settings.profileSettings, profileId); + settings.m_CcdManagedData.EnvironmentName = ProfileDataSourceSettings.GetSettings().GetEnvironmentName(settings.profileSettings, profileId); + } + + /// + /// Download addressables_content_state.bin from the CCD managed bucket. + /// + /// Addressables data builder context + /// + public async Task DownloadContentStateBin(AddressablesDataBuilderInput input) + { + if (!input.AddressableSettings.BuildRemoteCatalog) + { + Addressables.LogWarning("Not downloading content state because 'Build Remote Catalog' is not checked in Addressable Asset Settings. This will disable content updates"); + return true; + } + + var settings = input.AddressableSettings; + var dataSource = getRemoteCatalogDataSource(settings); + if (dataSource == null) + { + Addressables.LogError("Could not find remote catalog paths. Ensure your profile's remote catalog load path is configured for CCD and that the bucket exists."); + return false; + } + + if (!this.isCCDGroup(dataSource)) + { + Addressables.LogError("Content state could not be downloaded as the remote catalog is not targeting CCD"); + return false; + } + + try + { + SetEnvironmentId(settings, dataSource); + var bucketId = GetBucketId(settings, dataSource); + if (bucketId == null) + { + Addressables.LogError("Content state could not be downloaded as no bucket was specified. This is populated for managed profiles in the VerifyTargetBucket event."); + return false; + } + var api = CcdManagement.Instance; + CcdEntry ccdEntry; + try + { + ccdEntry = await GetEntryByPath(api, new Guid(bucketId), k_ContentStatePath); + } + catch (Exception e) + { + Addressables.LogError($"Unable to get entry for content state {k_ContentStatePath}: {e.Message}"); + return false; + + } + + if (ccdEntry != null) + { + var contentStream = await api.GetContentAsync(new EntryOptions(new Guid(bucketId), ccdEntry.Entryid)); + + var contentStatePath = Path.Combine(settings.GetContentStateBuildPath(), k_ContentStatePath); + if (!Directory.Exists(contentStatePath)) + Directory.CreateDirectory(Path.GetDirectoryName(contentStatePath)); + else if (File.Exists(contentStatePath)) + File.Delete(contentStatePath); + + using (var fileStream = File.Create(contentStatePath)) + { + contentStream.CopyTo(fileStream); + } + } + } + catch (Exception e) + { + Addressables.LogError($"Unable to upload content state {k_ContentStatePath}: {e.Message}"); + return false; + } + return true; + } + + /// + /// Upload content to the CCD managed bucket and create a release. + /// + /// Addressables data builder context + /// Addressables build result + /// + public async Task UploadAndRelease(AddressablesDataBuilderInput input, + AddressablesPlayerBuildResult result) + { + // Verify files exist that need uploading + var foundRemoteContent = result.FileRegistry?.GetFilePaths() + .Any(path => path.StartsWith(AddressableAssetSettings.kCCDBuildDataPath)) == true; + + if (!foundRemoteContent) + { + Addressables.LogWarning( + "Skipping upload and release as no remote content was found to upload. Ensure you have at least one content group's 'Build & Load Path' set to Remote."); + return false; + } + + try + { + //Getting files + Addressables.Log("Creating and uploading entries"); + var startDirectory = new DirectoryInfo(AddressableAssetSettings.kCCDBuildDataPath); + var buildData = CreateData(startDirectory); + + + //Creating a release for each bucket + var defaultEnvironmentId = ProfileDataSourceSettings.GetSettings().GetEnvironmentId(input.AddressableSettings.profileSettings, input.AddressableSettings.activeProfileId); + + await UploadAndRelease(CcdManagement.Instance, input.AddressableSettings, defaultEnvironmentId, buildData); + } + catch (Exception e) + { + Addressables.LogError(e.ToString()); + return false; + } + + return true; + } + + private ProfileGroupType getRemoteCatalogDataSource(AddressableAssetSettings settings) + { + var buildPath = settings.RemoteCatalogBuildPath; + var loadPath = settings.RemoteCatalogLoadPath; + return GetDataSource(settings, buildPath.Id, loadPath.Id); + } + + + /// + /// Upload addressables_content_state.bin to the CCD managed bucket. + /// + /// Addressables data builder context + /// Addressables build result + /// + public async Task UploadContentState(AddressablesDataBuilderInput input, + AddressablesPlayerBuildResult result) + { + + if (!input.AddressableSettings.BuildRemoteCatalog) + { + Addressables.LogWarning("Not uploading content state, because 'Build Remote Catalog' is not checked in Addressable Asset Settings. This will disable content updates"); + return true; + } + + var settings = input.AddressableSettings; + var dataSource = getRemoteCatalogDataSource(settings); + if (dataSource == null) + { + Addressables.LogError("Could not find remote catalog paths. Ensure your profile's remote catalog load path is configured for CCD and that the bucket exists."); + return false; + } + + if (!this.isCCDGroup(dataSource)) + { + Addressables.LogError("Content state could not be uploaded as the remote catalog is not targeting CCD"); + return false; + } + + try + { + SetEnvironmentId(settings, dataSource); + var bucketId = GetBucketId(settings, dataSource); + if (bucketId == null) + { + Addressables.LogError("Content state could not be uploaded as no bucket was specified. This is populated for managed profiles in the VerifyBucket event."); + return false; + } + var api = CcdManagement.Instance; + + var contentStatePath = Path.Combine(settings.GetContentStateBuildPath(), k_ContentStatePath); + if (!File.Exists(contentStatePath)) + { + Addressables.LogError($"Content state file is missing {contentStatePath}"); + return false; + } + var contentHash = AddressableAssetUtility.GetMd5Hash(contentStatePath); + + using (var stream = File.OpenRead(contentStatePath)) + { + + var entryModelOptions = new EntryModelOptions(k_ContentStatePath, contentHash, (int)stream.Length) + { + UpdateIfExists = true + }; + CcdEntry createdEntry; + try + { + createdEntry = await api.CreateOrUpdateEntryByPathAsync( + new EntryByPathOptions(new Guid(bucketId), k_ContentStatePath), + entryModelOptions); + } + catch (Exception e) + { + Addressables.LogError($"Unable to create entry for content state: {e.Message}"); + return false; + } + + try + { + var uploadContentOptions = new UploadContentOptions( + new Guid(bucketId), createdEntry.Entryid, stream); + await api.UploadContentAsync(uploadContentOptions); + } + catch (Exception e) + { + Addressables.LogError($"Unable to upload content state: {e.Message}"); + return false; + } + } + } + catch (Exception e) + { + Addressables.LogError(e.ToString()); + return false; + } + return true; + } + + internal bool IsPromotionOnlyBucket(ProfileGroupType dataSource) + { + if (dataSource != null && dataSource.GroupTypePrefix.StartsWith("CCD")) + { + if (bool.Parse(dataSource.GetVariableBySuffix(nameof(CcdBucket.Attributes.PromoteOnly)).Value)) + { + Addressables.LogError("Cannot upload to Promotion Only bucket."); + return true; + } + } + return false; + } + + internal ProfileGroupType GetDataSource(AddressableAssetSettings settings, BundledAssetGroupSchema schema) + { + return GetDataSource(settings, schema.BuildPath.Id, schema.LoadPath.Id); + } + + internal ProfileGroupType GetDataSource(AddressableAssetSettings settings, string buildPathId, string loadPathId) + { + var groupType = GetGroupType(settings, buildPathId, loadPathId); + if (!IsUsingManager(groupType)) + { + return groupType; + } + + var groupTypes = ProfileDataSourceSettings.GetSettings().GetGroupTypesByPrefix(string.Join( + ProfileGroupType.k_PrefixSeparator.ToString(), "CCD", CloudProjectSettings.projectId, + ProfileDataSourceSettings.GetSettings().GetEnvironmentId(settings.profileSettings, settings.activeProfileId))); + var automaticGroupType = groupTypes.FirstOrDefault(gt => + gt.GetVariableBySuffix($"{nameof(CcdBucket)}{nameof(CcdBucket.Name)}").Value == + EditorUserBuildSettings.activeBuildTarget.ToString()); + if (automaticGroupType == null) + { + // the bucket does not yet exist + return groupType; + } + + // set this value so we can check with IsUsingManager + automaticGroupType.GroupTypePrefix = AddressableAssetSettings.CcdManagerGroupTypePrefix; + return automaticGroupType; + } + + internal ProfileGroupType GetGroupType(AddressableAssetSettings settings, string buildPathId, string loadPathId) + { + // This data is populated in the RefreshDataSources event + // we need the "unresolved" value since we're tring to match it to its original type + var buildPathValue = settings.profileSettings.GetValueById(settings.activeProfileId, buildPathId); + var loadPathValue = settings.profileSettings.GetValueById(settings.activeProfileId, loadPathId); + if (buildPathValue == null || loadPathValue == null) + { + return null; + } + + var tempGroupType = new ProfileGroupType("temp"); + tempGroupType.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kBuildPath, buildPathValue)); + tempGroupType.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kLoadPath, loadPathValue)); + return ProfileDataSourceSettings.GetSettings().FindGroupType(tempGroupType); + } + + + internal bool IsUsingManager(ProfileGroupType dataSource) + { + if (dataSource == null) + { + return false; + } + return dataSource.GroupTypePrefix == AddressableAssetSettings.CcdManagerGroupTypePrefix; + } + + internal void SetEnvironmentId(AddressableAssetSettings settings, ProfileGroupType groupType) + { + string environmentId = null; + if (!IsUsingManager(groupType)) + { + // if not using the manager load the bucketID from the group type + environmentId = groupType.GetVariableBySuffix($"{nameof(ProfileDataSourceSettings.Environment)}{nameof(ProfileDataSourceSettings.Environment.id)}").Value; + } + else if (settings.m_CcdManagedData != null) + { + environmentId = settings.m_CcdManagedData.EnvironmentId; + } + + if (environmentId == null) + { + throw new Exception("unable to determine environment ID."); + } + + ConfigureCcdManagement(settings, environmentId); + } + + internal string GetBucketId(AddressableAssetSettings settings, ProfileGroupType dataSource) + { + if (!IsUsingManager(dataSource)) + { + // if not using the manager load the bucketID from the group type + return dataSource.GetVariableBySuffix($"{nameof(CcdBucket)}{nameof(CcdBucket.Id)}").Value; + } + if (settings.m_CcdManagedData != null) + { + return settings.m_CcdManagedData.BucketId; + } + return null; + } + + async Task CreateManagedBucket(string bucketName) + { + CcdBucket ccdBucket; + try + { + ccdBucket = await CcdManagement.Instance.CreateBucketAsync( + new CreateBucketOptions(bucketName)); + } + catch (CcdManagementException e) + { + if (e.ErrorCode == CcdManagementErrorCodes.AlreadyExists) + { + var buckets = await ProfileDataSourceSettings.GetAllBucketsAsync(); + ccdBucket = buckets.First(bucket => + bucket.Value.Name == EditorUserBuildSettings.activeBuildTarget.ToString()).Value; + } + else + { + throw; + } + } + return ccdBucket; + } + + async Task GetEntryByPath(ICcdManagementServiceSdk api, Guid bucketId, string path) + { + CcdEntry ccdEntry = null; + try + { + ccdEntry = await api.GetEntryByPathAsync(new EntryByPathOptions(bucketId, path)); + } + catch (CcdManagementException e) + { + if (e.ErrorCode != CommonErrorCodes.NotFound) + { + throw; + } + } + return ccdEntry; + } + + CcdBuildDataFolder CreateData(DirectoryInfo startDirectory) + { + var buildDataFolder = new CcdBuildDataFolder + { + Name = AddressableAssetSettings.kCCDBuildDataPath, + Location = startDirectory.FullName + }; + buildDataFolder.GetChildren(startDirectory); + return buildDataFolder; + } + + int StartProgress(string description) + { +#if UNITY_2020_1_OR_NEWER + return Progress.Start("CCD", description, Progress.Options.Managed); +#else + Addressables.Log(description); + return -1; +#endif + } + + void RemoveProgress(int progressId) + { +#if UNITY_2020_1_OR_NEWER + Progress.Remove(progressId); +#endif + } + + void ReportProgress(int progressId, float progress, string message) + { +#if UNITY_2020_1_OR_NEWER + Progress.Report(progressId, progress, message); +#else + Addressables.Log($"[{progress}] {message}"); +#endif + } + + async Task UploadAndRelease(ICcdManagementServiceSdk api, AddressableAssetSettings settings, string defaultEnvironmentId, CcdBuildDataFolder buildData) + { + var progressId = StartProgress("Upload and Release"); + try + { + foreach (var env in buildData.Environments) + { + + CcdManagement.SetEnvironmentId(env.Name); + + if (env.Name == ProfileDataSourceSettings.MANAGED_ENVIRONMENT) + { + ConfigureCcdManagement(settings, defaultEnvironmentId); + } + + foreach (var bucket in env.Buckets) + { + Guid bucketId; + var bucketIdString = bucket.Name == ProfileDataSourceSettings.MANAGED_BUCKET + ? settings.m_CcdManagedData.BucketId + : bucket.Name; + if (String.IsNullOrEmpty(bucketIdString)) + { + Addressables.LogError($"Invalid bucket ID for {bucket.Name}"); + continue; + } + bucketId = Guid.Parse(bucketIdString); + + foreach (var badge in bucket.Badges) + { + if (badge.Name == ProfileDataSourceSettings.MANAGED_BADGE) + { + badge.Name = "latest"; + } + var entries = new List(); + var total = badge.Files.Count(); + for (var i = 0; i < total; i++) + { + var file = badge.Files[i]; + var contentHash = AddressableAssetUtility.GetMd5Hash(file.FullName); + using (var stream = File.OpenRead(file.FullName)) + { + var entryPath = file.Name; + var entryModelOptions = new EntryModelOptions(entryPath, contentHash, (int)stream.Length) + { + UpdateIfExists = true + }; + ReportProgress(progressId, (i + 1) / total, $"Creating Entry {entryPath}"); + CcdEntry createdEntry; + try + { + createdEntry = await api.CreateOrUpdateEntryByPathAsync(new EntryByPathOptions(bucketId, entryPath), + entryModelOptions).ConfigureAwait(false); + } + catch (Exception e) + { + throw new Exception($"Unable to create entry for {entryPath}: {e.Message}", e); + } + + Addressables.Log($"Created Entry {entryPath}"); + + ReportProgress(progressId, (i + 1) / total, $"Uploading Entry {entryPath}"); + var uploadContentOptions = new UploadContentOptions(bucketId, createdEntry.Entryid, stream); + await api.UploadContentAsync(uploadContentOptions).ConfigureAwait(false); + + ReportProgress(progressId, (i + 1) / total, $"Uploaded Entry {entryPath}"); + entries.Add(new CcdReleaseEntryCreate(createdEntry.Entryid, createdEntry.CurrentVersionid)); + } + } + + // Add content_sate.bin to release if present + var contentStateEntry = await GetEntryByPath(api, bucketId, k_ContentStatePath); + if (contentStateEntry != null) + entries.Add(new CcdReleaseEntryCreate(contentStateEntry.Entryid, contentStateEntry.CurrentVersionid)); + + //Creating release + ReportProgress(progressId, total, "Creating release"); + Addressables.Log("Creating release."); + var release = await api.CreateReleaseAsync(new CreateReleaseOptions(bucketId) + { + Entries = entries, + Notes = $"Automated release created for {badge.Name}" + }).ConfigureAwait(false); + Addressables.Log($"Release {release.Releaseid} created."); + + //Don't update latest badge (as it always updates) + if (badge.Name != "latest") + { + ReportProgress(progressId, total, "Updating badge"); + Addressables.Log("Updating badge."); + var badgeRes = await api.AssignBadgeAsync(new AssignBadgeOptions(bucketId, badge.Name, release.Releaseid)) + .ConfigureAwait(false); + Addressables.Log($"Badge {badgeRes.Name} updated."); + } + } + } + } + } + finally + { + RemoveProgress(progressId); + } + } + + } +} +#endif + diff --git a/Editor/Build/CcdBuildEvents.cs.meta b/Editor/Build/CcdBuildEvents.cs.meta index c4aa1add..74b6c3a0 100644 --- a/Editor/Build/CcdBuildEvents.cs.meta +++ b/Editor/Build/CcdBuildEvents.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 49f93c268e0343869a5a30defb8e5d51 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 49f93c268e0343869a5a30defb8e5d51 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/ContentUpdateScript.cs b/Editor/Build/ContentUpdateScript.cs index 17ab5586..4504eea8 100644 --- a/Editor/Build/ContentUpdateScript.cs +++ b/Editor/Build/ContentUpdateScript.cs @@ -1,1093 +1,1093 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Runtime.Serialization.Formatters.Binary; -using System.Text; -using UnityEditor.AddressableAssets.Build.DataBuilders; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.AddressableAssets.Settings.GroupSchemas; -using UnityEditor.Build.Content; -using UnityEditor.Build.Pipeline.Interfaces; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.AddressableAssets.ResourceLocators; -using UnityEngine.ResourceManagement.ResourceProviders; -using UnityEngine.ResourceManagement.Util; - -#if ENABLE_CCD -using Unity.Services.Ccd.Management; -#endif - -namespace UnityEditor.AddressableAssets.Build -{ - /// - /// Option for how to deal with automatically checking for content update restrictions as part of the Update a Previous Build workflow. - /// - public enum CheckForContentUpdateRestrictionsOptions - { - /// - /// If assets are modified that have been previously built in a Cannot Change Post Release group, - /// the build will be paused and the Update Restrictions Check window is opened - /// - ListUpdatedAssetsWithRestrictions = 0, - - /// - /// If assets are modified that have been previously built in a Cannot Change Post Release group, the Content Update build will fail. - /// - FailBuild = 1, - - /// - /// Updating a previous build does not automatically run the Check for Update Restrictions rule. - /// - Disabled = 2 - } - -#if ENABLE_CCD - /// - /// This is used to determine the behavior of Update a Previous Build when taking advantage of the Build & Release feature. - /// - public enum BuildAndReleaseContentStateBehavior - { - /// - /// Uses the Previous Content State bin file path set in the AddressableAssetSettings - /// - UsePresetLocation = 0, - /// - /// Pulls the Previous Content State bin from the associated Cloud Content Delivery bucket set in the profile variables. - /// - UseCCDBucket = 1 - - } -#endif - - /// - /// The given state of an Asset. Represented by its guid and hash. - /// - [Serializable] - public struct AssetState : IEquatable - { - /// - /// Asset states GUID. - /// - public GUID guid; - - /// - /// Asset State hash. - /// - public Hash128 hash; - - /// - /// Check if one asset state is equal to another. - /// - /// Right hand side of comparision. - /// Returns true if the Asset States are equal to one another. - public bool Equals(AssetState other) - { - return guid == other.guid && hash == other.hash; - } - } - - /// - /// The Cached Asset State of an Addressable Asset. - /// - [Serializable] - public class CachedAssetState : IEquatable - { - /// - /// The Asset State. - /// - public AssetState asset; - - /// - /// The Asset State of all dependencies. - /// - public AssetState[] dependencies; - - /// - /// The guid for the group the cached asset state belongs to. - /// - public string groupGuid; - - /// - /// The name of the cached asset states bundle file. - /// - public string bundleFileId; - - /// - /// The cached asset state data. - /// - public object data; - - /// - /// Checks if one cached asset state is equal to another given the asset state and dependency state. - /// - /// Right hand side of comparision. - /// Returns true if the cached asset states are equal to one another. - public bool Equals(CachedAssetState other) - { - bool result = other != null && asset.Equals(other.asset); - result &= dependencies != null && other.dependencies != null; - result &= dependencies.Length == other.dependencies.Length; - var index = 0; - while (result && index < dependencies.Length) - { - result &= dependencies[index].Equals(other.dependencies[index]); - index++; - } - - return result; - } - } - - /// - /// Cached state of asset bundles. - /// - [Serializable] - public class CachedBundleState - { - /// - /// The name of the cached asset states bundle file. - /// - public string bundleFileId; - - /// - /// The cached bundle state data. - /// - public object data; - } - - /// - /// Data stored with each build that is used to generated content updates. - /// - [Serializable] - public class AddressablesContentState - { - /// - /// The version that the player was built with. This is usually set to AddressableAssetSettings.PlayerBuildVersion. - /// - [SerializeField] - public string playerVersion; - - /// - /// The version of the unity editor used to build the player. - /// - [SerializeField] - public string editorVersion; - - /// - /// Dependency information for all assets in the build that have been marked StaticContent. - /// - [SerializeField] - public CachedAssetState[] cachedInfos; - - /// - /// The path of a remote catalog. This is the only place the player knows to look for an updated catalog. - /// - [SerializeField] - public string remoteCatalogLoadPath; - - /// - /// Information about asset bundles created for the build. - /// - [SerializeField] - public CachedBundleState[] cachedBundles; - } - - internal struct ContentUpdateUsageData - { - public string ContentUpdateInterruptMessage; - public bool UsingCCD; - } - - internal struct ContentUpdateBuildData - { - public string Error; - public double BuildDuration; - } - - /// - /// Contains methods used for the content update workflow. - /// - public static class ContentUpdateScript - { - internal static readonly string FirstTimeUpdatePreviousBuild = nameof(FirstTimeUpdatePreviousBuild); - - /// - /// Contains build information used for updating assets. - /// - public struct ContentUpdateContext - { - /// - /// The mapping of an asset's guid to its cached asset state. - /// - public Dictionary GuidToPreviousAssetStateMap; - - /// - /// The mapping of an asset's or bundle's internal id to its catalog entry. - /// - public Dictionary IdToCatalogDataEntryMap; - - /// - /// The mapping of a bundle's name to its internal bundle id. - /// - public Dictionary BundleToInternalBundleIdMap; - - /// - /// Stores the asset bundle write information. - /// - public IBundleWriteData WriteData; - - /// - /// Stores the cached build data. - /// - public AddressablesContentState ContentState; - - /// - /// Stores the paths of the files created during a build. - /// - public FileRegistry Registry; - - /// - /// The list of asset state information gathered from the previous build. - /// - public List PreviousAssetStateCarryOver; - } - - private static string m_BinFileCachePath = "Library/com.unity.addressables/AddressablesBinFileDownload/addressables_content_state.bin"; - - /// - /// If the previous content state file location is a remote location, this path is where the file is downloaded to as part of a - /// content update build. In the event of a fresh build where the previous state file build path is remote, this is the location the - /// file is built to. - /// - public static string PreviousContentStateFileCachePath - { - get { return m_BinFileCachePath; } - set { m_BinFileCachePath = value; } - } - - static bool GetAssetState(GUID asset, out AssetState assetState) - { - assetState = new AssetState(); - if (asset.Empty()) - return false; - - var path = AssetDatabase.GUIDToAssetPath(asset.ToString()); - if (string.IsNullOrEmpty(path)) - return false; - - var hash = AssetDatabase.GetAssetDependencyHash(path); - if (!hash.isValid) - return false; - - assetState.guid = asset; - assetState.hash = hash; - return true; - } - - static bool GetCachedAssetStateForData(GUID asset, string bundleFileId, string groupGuid, object data, IEnumerable dependencies, out CachedAssetState cachedAssetState) - { - cachedAssetState = null; - - AssetState assetState; - if (!GetAssetState(asset, out assetState)) - return false; - - var visited = new HashSet(); - visited.Add(asset); - var dependencyStates = new List(); - foreach (var dependency in dependencies) - { - if (!visited.Add(dependency)) - continue; - - AssetState dependencyState; - if (!GetAssetState(dependency, out dependencyState)) - continue; - dependencyStates.Add(dependencyState); - } - - cachedAssetState = new CachedAssetState(); - cachedAssetState.asset = assetState; - cachedAssetState.dependencies = dependencyStates.ToArray(); - cachedAssetState.groupGuid = groupGuid; - cachedAssetState.bundleFileId = bundleFileId; - cachedAssetState.data = data; - - return true; - } - - static bool HasAssetOrDependencyChanged(CachedAssetState cachedInfo) - { - CachedAssetState newCachedInfo; - if (!GetCachedAssetStateForData(cachedInfo.asset.guid, cachedInfo.bundleFileId, cachedInfo.groupGuid, cachedInfo.data, cachedInfo.dependencies.Select(x => x.guid), out newCachedInfo)) - return true; - return !cachedInfo.Equals(newCachedInfo); - } - - /// - /// Save the content update information for a set of AddressableAssetEntry objects. - /// - /// File to write content stat info to. If file already exists, it will be deleted before the new file is created. - /// The entries to save. - /// The raw dependency information generated from the build. - /// The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion. - /// The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur. - /// True if the file is saved, false otherwise. - [Obsolete] - public static bool SaveContentState(string path, List entries, IDependencyData dependencyData, string playerVersion, string remoteCatalogPath) - { - return SaveContentState(new List(), path, entries, dependencyData, playerVersion, remoteCatalogPath); - } - - /// - /// Save the content update information for a set of AddressableAssetEntry objects. - /// - /// The ContentCatalogDataEntry locations that were built into the Content Catalog. - /// File to write content stat info to. If file already exists, it will be deleted before the new file is created. - /// The entries to save. - /// The raw dependency information generated from the build. - /// The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion. - /// The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur. - /// True if the file is saved, false otherwise. - public static bool SaveContentState(List locations, string path, List entries, IDependencyData dependencyData, string playerVersion, - string remoteCatalogPath) - { - return SaveContentState(locations, path, entries, dependencyData, playerVersion, remoteCatalogPath, null); - } - - /// - /// Save the content update information for a set of AddressableAssetEntry objects. - /// - /// The ContentCatalogDataEntry locations that were built into the Content Catalog. - /// File to write content stat info to. If file already exists, it will be deleted before the new file is created. - /// The entries to save. - /// The raw dependency information generated from the build. - /// The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion. - /// The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur. - /// Cached state that needs to carry over from the previous build. This mainly affects Content Update. - /// True if the file is saved, false otherwise. - public static bool SaveContentState(List locations, string path, List entries, IDependencyData dependencyData, string playerVersion, - string remoteCatalogPath, List carryOverCacheState) - { - return SaveContentState(locations, null, path, entries, dependencyData, playerVersion, remoteCatalogPath, carryOverCacheState); - } - - /// - /// Save the content update information for a set of AddressableAssetEntry objects. - /// - /// The ContentCatalogDataEntry locations that were built into the Content Catalog. - /// Mapping of asset Guid to catalog locations entries for lookup of extra data. - /// File to write content stat info to. If file already exists, it will be deleted before the new file is created. - /// The entries to save. - /// The raw dependency information generated from the build. - /// The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion. - /// The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur. - /// Cached state that needs to carry over from the previous build. This mainly affects Content Update. - /// True if the file is saved, false otherwise. - internal static bool SaveContentState(List locations, Dictionary> guidToCatalogLocation, string path, List entries, IDependencyData dependencyData, string playerVersion, - string remoteCatalogPath, List carryOverCacheState) - { - try - { - var cachedInfos = GetCachedAssetStates(guidToCatalogLocation, entries, dependencyData); - - var cachedBundleInfos = new List(); - foreach (ContentCatalogDataEntry ccEntry in locations) - { - if (typeof(IAssetBundleResource).IsAssignableFrom(ccEntry.ResourceType)) - cachedBundleInfos.Add(new CachedBundleState() {bundleFileId = ccEntry.InternalId, data = ccEntry.Data}); - } - - if (carryOverCacheState != null) - { - foreach (var cs in carryOverCacheState) - cachedInfos.Add(cs); - } - - var cacheData = new AddressablesContentState - { - cachedInfos = cachedInfos.ToArray(), - playerVersion = playerVersion, - editorVersion = Application.unityVersion, - remoteCatalogLoadPath = remoteCatalogPath, - cachedBundles = cachedBundleInfos.ToArray() - }; - var formatter = new BinaryFormatter(); - if (File.Exists(path)) - File.Delete(path); - var dir = Path.GetDirectoryName(path); - if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) - Directory.CreateDirectory(dir); - var stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write); - formatter.Serialize(stream, cacheData); - stream.Flush(); - stream.Close(); - stream.Dispose(); - return true; - } - catch (UnauthorizedAccessException uae) - { - if (!AddressableAssetUtility.IsVCAssetOpenForEdit(path)) - Debug.LogErrorFormat("Cannot access the file {0}. It may be locked by version control.", path); - else - Debug.LogException(uae); - return false; - } - catch (Exception e) - { - Debug.LogException(e); - return false; - } - } - - static IList GetCachedAssetStates(Dictionary> guidToCatalogLocation, - List entries, IDependencyData dependencyData) - { - IList gatheredCachedInfos = new List(); - - Dictionary guidToEntries = new Dictionary(); - foreach (AddressableAssetEntry entry in entries) - if (!guidToEntries.ContainsKey(entry.guid)) - guidToEntries[entry.guid] = entry; - - foreach (KeyValuePair assetData in dependencyData.AssetInfo) - GetCachedAssetState(guidToCatalogLocation, guidToEntries, assetData.Key, assetData.Value.referencedObjects, gatheredCachedInfos); - foreach (KeyValuePair sceneData in dependencyData.SceneInfo) - GetCachedAssetState(guidToCatalogLocation, guidToEntries, sceneData.Key, sceneData.Value.referencedObjects, gatheredCachedInfos); - - return gatheredCachedInfos; - } - - private static void GetCachedAssetState(Dictionary> guidToCatalogLocation, - Dictionary guidToEntries, GUID guid, - IReadOnlyCollection dependencies, IList cachedInfos) - { - guidToEntries.TryGetValue(guid.ToString(), out AddressableAssetEntry addressableEntry); - List catalogLocationsForSceneGuid = null; - guidToCatalogLocation?.TryGetValue(guid, out catalogLocationsForSceneGuid); - - if (addressableEntry != null) - { - object catalogData = catalogLocationsForSceneGuid != null && catalogLocationsForSceneGuid.Count > 0 - ? catalogLocationsForSceneGuid[0].Data - : null; - - if (GetCachedAssetStateForData(guid, addressableEntry.BundleFileId, - addressableEntry.parentGroup.Guid, catalogData, - dependencies.Select(x => x.guid), - out CachedAssetState cachedAssetState)) - cachedInfos.Add(cachedAssetState); - } - } - - /// - /// Gets the path of the cache data from a selected build. - /// - /// If true, the user is allowed to browse for a specific file. - /// The path of the previous state .bin file used to detect changes from the previous build to the content update build. - public static string GetContentStateDataPath(bool browse) - { - return GetContentStateDataPath(browse, null); - } - - internal static string GetContentStateDataPath(bool browse, AddressableAssetSettings settings) - { - if (settings == null) - settings = AddressableAssetSettingsDefaultObject.Settings; - var profileSettings = settings == null ? null : settings.profileSettings; - string assetPath = profileSettings != null ? profileSettings.EvaluateString(settings.activeProfileId, settings.ContentStateBuildPath) : ""; - - if (string.IsNullOrEmpty(assetPath)) - { - assetPath = settings != null - ? settings.GetContentStateBuildPath() - : Path.Combine(AddressableAssetSettingsDefaultObject.kDefaultConfigFolder, PlatformMappingService.GetPlatformPathSubFolder()); - } - - if (browse) - { - if (string.IsNullOrEmpty(assetPath)) - assetPath = Application.dataPath; - - assetPath = EditorUtility.OpenFilePanel("Build Data File", Path.GetDirectoryName(assetPath), "bin"); - - if (string.IsNullOrEmpty(assetPath)) - return null; - - return assetPath; - } - - if (!ResourceManagerConfig.ShouldPathUseWebRequest(assetPath)) - { - try - { - Directory.CreateDirectory(assetPath); - } - catch (Exception e) - { - Debug.LogError(e.Message + "\nCheck \"Content State Build Path\" in Addressables settings. Falling back to config folder location."); - assetPath = Path.Combine(AddressableAssetSettingsDefaultObject.kDefaultConfigFolder, - PlatformMappingService.GetPlatformPathSubFolder()); - Directory.CreateDirectory(assetPath); - } - } - -#if ENABLE_CCD - switch(settings.BuildAndReleaseBinFileOption) - { - case BuildAndReleaseContentStateBehavior.UsePresetLocation: - //do nothing - break; - case BuildAndReleaseContentStateBehavior.UseCCDBucket: - assetPath = settings.RemoteCatalogLoadPath.GetValue(settings); - break; - } -#endif - - var path = Path.Combine(assetPath, "addressables_content_state.bin"); - return path; - } - - /// - /// Downloads the content state bin to a temporary directory - /// - /// The url of the bin file - /// The temp path the bin file was downloaded to. - internal static string DownloadBinFileToTempLocation(string url) - { - if (!Directory.Exists(ContentUpdateScript.PreviousContentStateFileCachePath)) - Directory.CreateDirectory(Path.GetDirectoryName(ContentUpdateScript.PreviousContentStateFileCachePath)); - else if (File.Exists(ContentUpdateScript.PreviousContentStateFileCachePath)) - File.Delete(ContentUpdateScript.PreviousContentStateFileCachePath); - - try - { - var bytes = new WebClient().DownloadData(url); - File.WriteAllBytes(ContentUpdateScript.PreviousContentStateFileCachePath, bytes); - } - catch - { - //Do nothing, nothing will get downloaded and the users can select a file manually if they want. - } - - return ContentUpdateScript.PreviousContentStateFileCachePath; - } - - /// - /// Loads cache data from a specific location - /// - /// - /// The ContentState object. - public static AddressablesContentState LoadContentState(string contentStateDataPath) - { - if (string.IsNullOrEmpty(contentStateDataPath)) - { - Debug.LogErrorFormat("Unable to load cache data from {0}.", contentStateDataPath); - return null; - } - - var stream = new FileStream(contentStateDataPath, FileMode.Open, FileAccess.Read); - var formatter = new BinaryFormatter(); - var cacheData = formatter.Deserialize(stream) as AddressablesContentState; - if (cacheData == null) - { - Addressables.LogError( - "Invalid hash data file. This file is usually named addressables_content_state.bin and is saved in the same folder as your source AddressableAssetsSettings.asset file."); - return null; - } - - stream.Dispose(); - return cacheData; - } - - static bool s_StreamingAssetsExists; - static string kStreamingAssetsPath = "Assets/StreamingAssets"; - - internal static void Cleanup(bool deleteStreamingAssetsFolderIfEmpty, bool cleanBuildPath) - { - if (cleanBuildPath) - { - DirectoryUtility.DeleteDirectory(Addressables.BuildPath, onlyIfEmpty: false, recursiveDelete: true); - } - - if (deleteStreamingAssetsFolderIfEmpty) - { - DirectoryUtility.DeleteDirectory(kStreamingAssetsPath, onlyIfEmpty: true); - } - } - - /// - /// Builds player content using the player content version from a specified cache file. - /// - /// The settings object to use for the build. - /// The path of the cache data to use. - /// The build operation. - public static AddressablesPlayerBuildResult BuildContentUpdate(AddressableAssetSettings settings, string contentStateDataPath) - { - var cacheData = LoadContentState(contentStateDataPath); - if (!IsCacheDataValid(settings, cacheData)) - return null; - - s_StreamingAssetsExists = Directory.Exists("Assets/StreamingAssets"); - var context = new AddressablesDataBuilderInput(settings, cacheData.playerVersion); - context.IsContentUpdateBuild = true; - context.PreviousContentState = cacheData; - - Cleanup(!s_StreamingAssetsExists, false); - - SceneManagerState.Record(); - var result = settings.ActivePlayerDataBuilder.BuildData(context); - if (!string.IsNullOrEmpty(result.Error)) - Debug.LogError(result.Error); - SceneManagerState.Restore(); - return result; - } - - internal static bool IsCacheDataValid(AddressableAssetSettings settings, AddressablesContentState cacheData) - { - if (cacheData == null) - return false; - - if (cacheData.editorVersion != Application.unityVersion) - Addressables.LogWarningFormat("Building content update with Unity editor version `{0}`, data was created with version `{1}`. This may result in incompatible data.", - Application.unityVersion, cacheData.editorVersion); - - if (string.IsNullOrEmpty(cacheData.remoteCatalogLoadPath)) - { - Addressables.LogError("Previous build had 'Build Remote Catalog' disabled. You cannot update a player that has no remote catalog specified"); - return false; - } - - if (!settings.BuildRemoteCatalog) - { - Addressables.LogError("Current settings have 'Build Remote Catalog' disabled. You cannot update a player that has no remote catalog to look to."); - return false; - } - - if (cacheData.remoteCatalogLoadPath != settings.RemoteCatalogLoadPath.GetValue(settings)) - { - Addressables.LogErrorFormat( - "Current 'Remote Catalog Load Path' does not match load path of original player. Player will only know to look up catalog at original location. Original: {0} Current: {1}", - cacheData.remoteCatalogLoadPath, settings.RemoteCatalogLoadPath.GetValue(settings)); - return false; - } - - return true; - } - - /// - /// Get all modified addressable asset entries in groups that have BundledAssetGroupSchema and ContentUpdateGroupSchema with static content enabled. - /// This includes any Addressable dependencies that are affected by the modified entries. - /// - /// Addressable asset settings. - /// The cache data path. - /// A list of all modified entries and dependencies (list is empty if there are none); null if failed to load cache data. - public static List GatherModifiedEntries(AddressableAssetSettings settings, string cacheDataPath) - { - HashSet retVal = new HashSet(); - var entriesMap = GatherModifiedEntriesWithDependencies(settings, cacheDataPath); - foreach (var entry in entriesMap.Keys) - { - if (!retVal.Contains(entry)) - retVal.Add(entry); - - foreach (var dependency in entriesMap[entry]) - if (!retVal.Contains(dependency)) - retVal.Add(dependency); - } - - return retVal.ToList(); - } - - internal static void GatherExplicitModifiedEntries(AddressableAssetSettings settings, ref Dictionary> dependencyMap, - AddressablesContentState cacheData) - { - List noBundledAssetGroupSchema = new List(); - List noStaticContent = new List(); - - var allEntries = new List(); - settings.GetAllAssets(allEntries, false, g => - { - if (g == null) - return false; - - if (!g.HasSchema()) - { - noBundledAssetGroupSchema.Add(g.Name); - return false; - } - - if (!g.HasSchema()) - { - noStaticContent.Add(g.Name); - return false; - } - - if (!g.GetSchema().StaticContent) - { - noStaticContent.Add(g.Name); - return false; - } - - g.FlaggedDuringContentUpdateRestriction = false; - return true; - }); - - StringBuilder builder = new StringBuilder(); - builder.AppendFormat("Skipping Prepare for Content Update on {0} group(s):\n\n", - noBundledAssetGroupSchema.Count + noStaticContent.Count); - - - AddInvalidGroupsToLogMessage(builder, noBundledAssetGroupSchema, "Group Did Not Contain BundledAssetGroupSchema"); - AddInvalidGroupsToLogMessage(builder, noStaticContent, "Static Content Not Enabled In Schemas"); - - Debug.Log(builder.ToString()); - - var entryToCacheInfo = new Dictionary(); - foreach (var cacheInfo in cacheData.cachedInfos) - if (cacheInfo != null) - entryToCacheInfo[cacheInfo.asset.guid.ToString()] = cacheInfo; - var modifiedEntries = new List(); - foreach (var entry in allEntries) - { - if (!entryToCacheInfo.TryGetValue(entry.guid, out CachedAssetState cachedInfo) || HasAssetOrDependencyChanged(cachedInfo)) - { - Type mainType = AddressableAssetUtility.MapEditorTypeToRuntimeType(entry.MainAssetType, false); - if ((mainType == null || mainType == typeof(DefaultAsset)) && !entry.IsInResources) - { - entry.FlaggedDuringContentUpdateRestriction = false; - } - else - { - modifiedEntries.Add(entry); - entry.FlaggedDuringContentUpdateRestriction = true; - entry.parentGroup.FlaggedDuringContentUpdateRestriction = true; - } - } - else - entry.FlaggedDuringContentUpdateRestriction = false; - } - - AddAllDependentScenesFromModifiedEntries(modifiedEntries); - foreach (var entry in modifiedEntries) - { - if (!dependencyMap.ContainsKey(entry)) - dependencyMap.Add(entry, new List()); - } - } - - internal static void ClearContentUpdateNotifications(AddressableAssetGroup assetGroup) - { - if (assetGroup == null) - return; - - if (assetGroup.FlaggedDuringContentUpdateRestriction) - { - ClearContentUpdateFlagForEntries(assetGroup.entries); - assetGroup.FlaggedDuringContentUpdateRestriction = false; - } - } - - static void ClearContentUpdateFlagForEntries(ICollection entries) - { - foreach (var e in entries) - { - if (e != null) - e.FlaggedDuringContentUpdateRestriction = false; - if (e.IsFolder) - { - List folderEntries = new List(); - e.GatherFolderEntries(folderEntries, true, true, null); - ClearContentUpdateFlagForEntries(folderEntries); - } - } - } - - /// - /// Get a Dictionary of all modified values and their dependencies. Dependencies will be Addressable and part of a group - /// with static content enabled. - /// - /// Addressable asset settings. - /// The cache data path. - /// A dictionary mapping explicit changed entries to their dependencies. - public static Dictionary> GatherModifiedEntriesWithDependencies(AddressableAssetSettings settings, string cachePath) - { - var modifiedData = new Dictionary>(); - AddressablesContentState cacheData = LoadContentState(cachePath); - if (cacheData == null) - return modifiedData; - - GatherExplicitModifiedEntries(settings, ref modifiedData, cacheData); - GetStaticContentDependenciesForEntries(settings, ref modifiedData, GetGroupGuidToCacheBundleNameMap(cacheData)); - GetEntriesDependentOnModifiedEntries(settings, ref modifiedData); - return modifiedData; - } - - internal static void GetEntriesDependentOnModifiedEntries(AddressableAssetSettings settings, ref Dictionary> dependencyMap) - { - var groups = GetStaticGroups(settings); - Dictionary entryToDependencies = new Dictionary(); - foreach (AddressableAssetGroup group in groups) - { - foreach (AddressableAssetEntry entry in group.entries) - { - string[] dependencies = AssetDatabase.GetDependencies(entry.AssetPath); - entryToDependencies.Add(entry, dependencies); - } - } - - HashSet modifiedEntries = new HashSet(); - foreach (KeyValuePair> mappedEntry in dependencyMap) - { - modifiedEntries.Add(mappedEntry.Key); - foreach (AddressableAssetEntry dependencyEntry in mappedEntry.Value) - modifiedEntries.Add(dependencyEntry); - } - - // if an entry is dependant on a modified entry, then it too should be modified to reference the moved asset - foreach (AddressableAssetEntry modifiedEntry in modifiedEntries) - { - foreach (KeyValuePair dependency in entryToDependencies) - { - if (dependency.Key != modifiedEntry && - dependency.Value.Contains(modifiedEntry.AssetPath) && - dependencyMap.TryGetValue(modifiedEntry, out var value)) - { - if (!value.Contains(dependency.Key)) - value.Add(dependency.Key); - } - } - } - } - - internal static List GetStaticGroups(AddressableAssetSettings settings) - { - List staticGroups = new List(); - foreach (AddressableAssetGroup group in settings.groups) - { - var staticSchema = group.GetSchema(); - if (staticSchema == null) - continue; - var bundleSchema = group.GetSchema(); - if (bundleSchema == null) - continue; - - if (staticSchema.StaticContent) - staticGroups.Add(group); - } - - return staticGroups; - } - - internal static Dictionary GetGroupGuidToCacheBundleNameMap(AddressablesContentState cacheData) - { - var bundleIdToCacheInfo = new Dictionary(); - foreach (CachedBundleState bundleInfo in cacheData.cachedBundles) - { - if (bundleInfo != null && bundleInfo.data is AssetBundleRequestOptions options) - bundleIdToCacheInfo[bundleInfo.bundleFileId] = options.BundleName; - } - - var groupGuidToCacheBundleName = new Dictionary(); - foreach (CachedAssetState cacheInfo in cacheData.cachedInfos) - { - if (cacheInfo != null && bundleIdToCacheInfo.TryGetValue(cacheInfo.bundleFileId, out string bundleName)) - groupGuidToCacheBundleName[cacheInfo.groupGuid] = bundleName; - } - - return groupGuidToCacheBundleName; - } - - internal static HashSet GetGroupGuidsWithUnchangedBundleName(AddressableAssetSettings settings, Dictionary> dependencyMap, - Dictionary groupGuidToCacheBundleName) - { - var result = new HashSet(); - if (groupGuidToCacheBundleName == null || groupGuidToCacheBundleName.Count == 0) - return result; - - var entryGuidToDeps = new Dictionary>(); - foreach (KeyValuePair> entryToDeps in dependencyMap) - { - entryGuidToDeps.Add(entryToDeps.Key.guid, entryToDeps.Value); - } - - foreach (AddressableAssetGroup group in settings.groups) - { - if (group == null || !group.HasSchema()) - continue; - - var schema = group.GetSchema(); - List bundleInputDefinitions = new List(); - - BuildScriptPackedMode.PrepGroupBundlePacking(group, bundleInputDefinitions, schema, entry => !entryGuidToDeps.ContainsKey(entry.guid)); - BuildScriptPackedMode.HandleBundleNames(bundleInputDefinitions); - - for (int i = 0; i < bundleInputDefinitions.Count; i++) - { - string bundleName = Path.GetFileNameWithoutExtension(bundleInputDefinitions[i].assetBundleName); - if (groupGuidToCacheBundleName.TryGetValue(group.Guid, out string cacheBundleName) && cacheBundleName == bundleName) - result.Add(group.Guid); - } - } - - return result; - } - - internal static void GetStaticContentDependenciesForEntries(AddressableAssetSettings settings, ref Dictionary> dependencyMap, - Dictionary groupGuidToCacheBundleName = null) - { - if (dependencyMap == null) - return; - - Dictionary groupHasStaticContentMap = new Dictionary(); - HashSet groupGuidsWithUnchangedBundleName = GetGroupGuidsWithUnchangedBundleName(settings, dependencyMap, groupGuidToCacheBundleName); - - foreach (AddressableAssetEntry entry in dependencyMap.Keys) - { - //since the entry here is from our list of modified entries we know that it must be a part of a static content group. - //Since it's part of a static content update group we can go ahead and set the value to true in the dictionary without explicitly checking it. - if (!groupHasStaticContentMap.ContainsKey(entry.parentGroup)) - groupHasStaticContentMap.Add(entry.parentGroup, true); - - string[] dependencies = AssetDatabase.GetDependencies(entry.AssetPath); - foreach (string dependency in dependencies) - { - string guid = AssetDatabase.AssetPathToGUID(dependency); - var depEntry = settings.FindAssetEntry(guid, true); - if (depEntry == null) - continue; - if (groupGuidsWithUnchangedBundleName.Contains(depEntry.parentGroup.Guid)) - continue; - - if (!groupHasStaticContentMap.TryGetValue(depEntry.parentGroup, out bool groupHasStaticContentEnabled)) - { - groupHasStaticContentEnabled = depEntry.parentGroup.HasSchema() && - depEntry.parentGroup.GetSchema().StaticContent; - - groupHasStaticContentMap.Add(depEntry.parentGroup, groupHasStaticContentEnabled); - } - - if (!dependencyMap.ContainsKey(depEntry) && groupHasStaticContentEnabled) - { - if (!dependencyMap.ContainsKey(entry)) - dependencyMap.Add(entry, new List()); - dependencyMap[entry].Add(depEntry); - depEntry.FlaggedDuringContentUpdateRestriction = true; - } - } - } - } - - internal static void AddAllDependentScenesFromModifiedEntries(List modifiedEntries) - { - List entriesToAdd = new List(); - //If a scene has changed, all scenes that end up in the same bundle need to be marked as modified due to bundle dependencies - foreach (AddressableAssetEntry entry in modifiedEntries) - { - if (entry.IsScene && !entriesToAdd.Contains(entry)) - { - switch (entry.parentGroup.GetSchema().BundleMode) - { - case BundledAssetGroupSchema.BundlePackingMode.PackTogether: - //Add every scene in the group to modified entries - foreach (AddressableAssetEntry sharedGroupEntry in entry.parentGroup.entries) - { - if (sharedGroupEntry.IsScene && !modifiedEntries.Contains(sharedGroupEntry)) - { - sharedGroupEntry.FlaggedDuringContentUpdateRestriction = true; - entriesToAdd.Add(sharedGroupEntry); - } - } - - break; - - case BundledAssetGroupSchema.BundlePackingMode.PackTogetherByLabel: - foreach (AddressableAssetEntry sharedGroupEntry in entry.parentGroup.entries) - { - //Check if one entry has 0 labels while the other contains labels. The labels union check below will return true in this case. - //That is not the behavior we want. So to avoid that, we check here first. - if (sharedGroupEntry.labels.Count == 0 ^ entry.labels.Count == 0) - continue; - - //Only add if labels are shared - if (sharedGroupEntry.IsScene && !modifiedEntries.Contains(sharedGroupEntry) && sharedGroupEntry.labels.Union(entry.labels).Any()) - { - sharedGroupEntry.FlaggedDuringContentUpdateRestriction = true; - entriesToAdd.Add(sharedGroupEntry); - } - } - - break; - - case BundledAssetGroupSchema.BundlePackingMode.PackSeparately: - //Do nothing. The scene will be in a different bundle. - break; - - default: - break; - } - } - } - - modifiedEntries.AddRange(entriesToAdd); - } - - private static void AddInvalidGroupsToLogMessage(StringBuilder builder, List invalidGroupList, - string headerMessage) - { - if (invalidGroupList.Count > 0) - { - builder.AppendFormat("{0} ({1} groups):\n", headerMessage, invalidGroupList.Count); - int maxList = 15; - for (int i = 0; i < invalidGroupList.Count; i++) - { - if (i > maxList) - { - builder.AppendLine("..."); - break; - } - - builder.AppendLine("-" + invalidGroupList[i]); - } - - builder.AppendLine(""); - } - } - - /// - /// Create a new AddressableAssetGroup with the items and mark it as remote. - /// - /// The settings object. - /// The items to move. - /// The name of the new group. - public static void CreateContentUpdateGroup(AddressableAssetSettings settings, List items, string groupName) - { - var contentGroup = settings.CreateGroup(settings.FindUniqueGroupName(groupName), false, false, true, null); - var schema = contentGroup.AddSchema(); - schema.BuildPath.SetVariableByName(settings, AddressableAssetSettings.kRemoteBuildPath); - schema.LoadPath.SetVariableByName(settings, AddressableAssetSettings.kRemoteLoadPath); - schema.BundleMode = BundledAssetGroupSchema.BundlePackingMode.PackTogether; - contentGroup.AddSchema().StaticContent = false; - settings.MoveEntries(items, contentGroup); - } - - /// - /// Functor to filter AddressableAssetGroups during content update. If the functor returns false, the group is excluded from the update. - /// - public static Func GroupFilterFunc = GroupFilter; - - internal static bool GroupFilter(AddressableAssetGroup g) - { - if (g == null) - return false; - if (!g.HasSchema() || !g.GetSchema().StaticContent) - return false; - if (!g.HasSchema() || !g.GetSchema().IncludeInBuild) - return false; - return true; - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using UnityEditor.AddressableAssets.Build.DataBuilders; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEditor.Build.Content; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.ResourceManagement.Util; + +#if ENABLE_CCD +using Unity.Services.Ccd.Management; +#endif + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// Option for how to deal with automatically checking for content update restrictions as part of the Update a Previous Build workflow. + /// + public enum CheckForContentUpdateRestrictionsOptions + { + /// + /// If assets are modified that have been previously built in a Cannot Change Post Release group, + /// the build will be paused and the Update Restrictions Check window is opened + /// + ListUpdatedAssetsWithRestrictions = 0, + + /// + /// If assets are modified that have been previously built in a Cannot Change Post Release group, the Content Update build will fail. + /// + FailBuild = 1, + + /// + /// Updating a previous build does not automatically run the Check for Update Restrictions rule. + /// + Disabled = 2 + } + +#if ENABLE_CCD + /// + /// This is used to determine the behavior of Update a Previous Build when taking advantage of the Build & Release feature. + /// + public enum BuildAndReleaseContentStateBehavior + { + /// + /// Uses the Previous Content State bin file path set in the AddressableAssetSettings + /// + UsePresetLocation = 0, + /// + /// Pulls the Previous Content State bin from the associated Cloud Content Delivery bucket set in the profile variables. + /// + UseCCDBucket = 1 + + } +#endif + + /// + /// The given state of an Asset. Represented by its guid and hash. + /// + [Serializable] + public struct AssetState : IEquatable + { + /// + /// Asset states GUID. + /// + public GUID guid; + + /// + /// Asset State hash. + /// + public Hash128 hash; + + /// + /// Check if one asset state is equal to another. + /// + /// Right hand side of comparision. + /// Returns true if the Asset States are equal to one another. + public bool Equals(AssetState other) + { + return guid == other.guid && hash == other.hash; + } + } + + /// + /// The Cached Asset State of an Addressable Asset. + /// + [Serializable] + public class CachedAssetState : IEquatable + { + /// + /// The Asset State. + /// + public AssetState asset; + + /// + /// The Asset State of all dependencies. + /// + public AssetState[] dependencies; + + /// + /// The guid for the group the cached asset state belongs to. + /// + public string groupGuid; + + /// + /// The name of the cached asset states bundle file. + /// + public string bundleFileId; + + /// + /// The cached asset state data. + /// + public object data; + + /// + /// Checks if one cached asset state is equal to another given the asset state and dependency state. + /// + /// Right hand side of comparision. + /// Returns true if the cached asset states are equal to one another. + public bool Equals(CachedAssetState other) + { + bool result = other != null && asset.Equals(other.asset); + result &= dependencies != null && other.dependencies != null; + result &= dependencies.Length == other.dependencies.Length; + var index = 0; + while (result && index < dependencies.Length) + { + result &= dependencies[index].Equals(other.dependencies[index]); + index++; + } + + return result; + } + } + + /// + /// Cached state of asset bundles. + /// + [Serializable] + public class CachedBundleState + { + /// + /// The name of the cached asset states bundle file. + /// + public string bundleFileId; + + /// + /// The cached bundle state data. + /// + public object data; + } + + /// + /// Data stored with each build that is used to generated content updates. + /// + [Serializable] + public class AddressablesContentState + { + /// + /// The version that the player was built with. This is usually set to AddressableAssetSettings.PlayerBuildVersion. + /// + [SerializeField] + public string playerVersion; + + /// + /// The version of the unity editor used to build the player. + /// + [SerializeField] + public string editorVersion; + + /// + /// Dependency information for all assets in the build that have been marked StaticContent. + /// + [SerializeField] + public CachedAssetState[] cachedInfos; + + /// + /// The path of a remote catalog. This is the only place the player knows to look for an updated catalog. + /// + [SerializeField] + public string remoteCatalogLoadPath; + + /// + /// Information about asset bundles created for the build. + /// + [SerializeField] + public CachedBundleState[] cachedBundles; + } + + internal struct ContentUpdateUsageData + { + public string ContentUpdateInterruptMessage; + public bool UsingCCD; + } + + internal struct ContentUpdateBuildData + { + public string Error; + public double BuildDuration; + } + + /// + /// Contains methods used for the content update workflow. + /// + public static class ContentUpdateScript + { + internal static readonly string FirstTimeUpdatePreviousBuild = nameof(FirstTimeUpdatePreviousBuild); + + /// + /// Contains build information used for updating assets. + /// + public struct ContentUpdateContext + { + /// + /// The mapping of an asset's guid to its cached asset state. + /// + public Dictionary GuidToPreviousAssetStateMap; + + /// + /// The mapping of an asset's or bundle's internal id to its catalog entry. + /// + public Dictionary IdToCatalogDataEntryMap; + + /// + /// The mapping of a bundle's name to its internal bundle id. + /// + public Dictionary BundleToInternalBundleIdMap; + + /// + /// Stores the asset bundle write information. + /// + public IBundleWriteData WriteData; + + /// + /// Stores the cached build data. + /// + public AddressablesContentState ContentState; + + /// + /// Stores the paths of the files created during a build. + /// + public FileRegistry Registry; + + /// + /// The list of asset state information gathered from the previous build. + /// + public List PreviousAssetStateCarryOver; + } + + private static string m_BinFileCachePath = "Library/com.unity.addressables/AddressablesBinFileDownload/addressables_content_state.bin"; + + /// + /// If the previous content state file location is a remote location, this path is where the file is downloaded to as part of a + /// content update build. In the event of a fresh build where the previous state file build path is remote, this is the location the + /// file is built to. + /// + public static string PreviousContentStateFileCachePath + { + get { return m_BinFileCachePath; } + set { m_BinFileCachePath = value; } + } + + static bool GetAssetState(GUID asset, out AssetState assetState) + { + assetState = new AssetState(); + if (asset.Empty()) + return false; + + var path = AssetDatabase.GUIDToAssetPath(asset.ToString()); + if (string.IsNullOrEmpty(path)) + return false; + + var hash = AssetDatabase.GetAssetDependencyHash(path); + if (!hash.isValid) + return false; + + assetState.guid = asset; + assetState.hash = hash; + return true; + } + + static bool GetCachedAssetStateForData(GUID asset, string bundleFileId, string groupGuid, object data, IEnumerable dependencies, out CachedAssetState cachedAssetState) + { + cachedAssetState = null; + + AssetState assetState; + if (!GetAssetState(asset, out assetState)) + return false; + + var visited = new HashSet(); + visited.Add(asset); + var dependencyStates = new List(); + foreach (var dependency in dependencies) + { + if (!visited.Add(dependency)) + continue; + + AssetState dependencyState; + if (!GetAssetState(dependency, out dependencyState)) + continue; + dependencyStates.Add(dependencyState); + } + + cachedAssetState = new CachedAssetState(); + cachedAssetState.asset = assetState; + cachedAssetState.dependencies = dependencyStates.ToArray(); + cachedAssetState.groupGuid = groupGuid; + cachedAssetState.bundleFileId = bundleFileId; + cachedAssetState.data = data; + + return true; + } + + static bool HasAssetOrDependencyChanged(CachedAssetState cachedInfo) + { + CachedAssetState newCachedInfo; + if (!GetCachedAssetStateForData(cachedInfo.asset.guid, cachedInfo.bundleFileId, cachedInfo.groupGuid, cachedInfo.data, cachedInfo.dependencies.Select(x => x.guid), out newCachedInfo)) + return true; + return !cachedInfo.Equals(newCachedInfo); + } + + /// + /// Save the content update information for a set of AddressableAssetEntry objects. + /// + /// File to write content stat info to. If file already exists, it will be deleted before the new file is created. + /// The entries to save. + /// The raw dependency information generated from the build. + /// The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion. + /// The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur. + /// True if the file is saved, false otherwise. + [Obsolete] + public static bool SaveContentState(string path, List entries, IDependencyData dependencyData, string playerVersion, string remoteCatalogPath) + { + return SaveContentState(new List(), path, entries, dependencyData, playerVersion, remoteCatalogPath); + } + + /// + /// Save the content update information for a set of AddressableAssetEntry objects. + /// + /// The ContentCatalogDataEntry locations that were built into the Content Catalog. + /// File to write content stat info to. If file already exists, it will be deleted before the new file is created. + /// The entries to save. + /// The raw dependency information generated from the build. + /// The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion. + /// The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur. + /// True if the file is saved, false otherwise. + public static bool SaveContentState(List locations, string path, List entries, IDependencyData dependencyData, string playerVersion, + string remoteCatalogPath) + { + return SaveContentState(locations, path, entries, dependencyData, playerVersion, remoteCatalogPath, null); + } + + /// + /// Save the content update information for a set of AddressableAssetEntry objects. + /// + /// The ContentCatalogDataEntry locations that were built into the Content Catalog. + /// File to write content stat info to. If file already exists, it will be deleted before the new file is created. + /// The entries to save. + /// The raw dependency information generated from the build. + /// The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion. + /// The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur. + /// Cached state that needs to carry over from the previous build. This mainly affects Content Update. + /// True if the file is saved, false otherwise. + public static bool SaveContentState(List locations, string path, List entries, IDependencyData dependencyData, string playerVersion, + string remoteCatalogPath, List carryOverCacheState) + { + return SaveContentState(locations, null, path, entries, dependencyData, playerVersion, remoteCatalogPath, carryOverCacheState); + } + + /// + /// Save the content update information for a set of AddressableAssetEntry objects. + /// + /// The ContentCatalogDataEntry locations that were built into the Content Catalog. + /// Mapping of asset Guid to catalog locations entries for lookup of extra data. + /// File to write content stat info to. If file already exists, it will be deleted before the new file is created. + /// The entries to save. + /// The raw dependency information generated from the build. + /// The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion. + /// The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur. + /// Cached state that needs to carry over from the previous build. This mainly affects Content Update. + /// True if the file is saved, false otherwise. + internal static bool SaveContentState(List locations, Dictionary> guidToCatalogLocation, string path, List entries, IDependencyData dependencyData, string playerVersion, + string remoteCatalogPath, List carryOverCacheState) + { + try + { + var cachedInfos = GetCachedAssetStates(guidToCatalogLocation, entries, dependencyData); + + var cachedBundleInfos = new List(); + foreach (ContentCatalogDataEntry ccEntry in locations) + { + if (typeof(IAssetBundleResource).IsAssignableFrom(ccEntry.ResourceType)) + cachedBundleInfos.Add(new CachedBundleState() {bundleFileId = ccEntry.InternalId, data = ccEntry.Data}); + } + + if (carryOverCacheState != null) + { + foreach (var cs in carryOverCacheState) + cachedInfos.Add(cs); + } + + var cacheData = new AddressablesContentState + { + cachedInfos = cachedInfos.ToArray(), + playerVersion = playerVersion, + editorVersion = Application.unityVersion, + remoteCatalogLoadPath = remoteCatalogPath, + cachedBundles = cachedBundleInfos.ToArray() + }; + var formatter = new BinaryFormatter(); + if (File.Exists(path)) + File.Delete(path); + var dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) + Directory.CreateDirectory(dir); + var stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write); + formatter.Serialize(stream, cacheData); + stream.Flush(); + stream.Close(); + stream.Dispose(); + return true; + } + catch (UnauthorizedAccessException uae) + { + if (!AddressableAssetUtility.IsVCAssetOpenForEdit(path)) + Debug.LogErrorFormat("Cannot access the file {0}. It may be locked by version control.", path); + else + Debug.LogException(uae); + return false; + } + catch (Exception e) + { + Debug.LogException(e); + return false; + } + } + + static IList GetCachedAssetStates(Dictionary> guidToCatalogLocation, + List entries, IDependencyData dependencyData) + { + IList gatheredCachedInfos = new List(); + + Dictionary guidToEntries = new Dictionary(); + foreach (AddressableAssetEntry entry in entries) + if (!guidToEntries.ContainsKey(entry.guid)) + guidToEntries[entry.guid] = entry; + + foreach (KeyValuePair assetData in dependencyData.AssetInfo) + GetCachedAssetState(guidToCatalogLocation, guidToEntries, assetData.Key, assetData.Value.referencedObjects, gatheredCachedInfos); + foreach (KeyValuePair sceneData in dependencyData.SceneInfo) + GetCachedAssetState(guidToCatalogLocation, guidToEntries, sceneData.Key, sceneData.Value.referencedObjects, gatheredCachedInfos); + + return gatheredCachedInfos; + } + + private static void GetCachedAssetState(Dictionary> guidToCatalogLocation, + Dictionary guidToEntries, GUID guid, + IReadOnlyCollection dependencies, IList cachedInfos) + { + guidToEntries.TryGetValue(guid.ToString(), out AddressableAssetEntry addressableEntry); + List catalogLocationsForSceneGuid = null; + guidToCatalogLocation?.TryGetValue(guid, out catalogLocationsForSceneGuid); + + if (addressableEntry != null) + { + object catalogData = catalogLocationsForSceneGuid != null && catalogLocationsForSceneGuid.Count > 0 + ? catalogLocationsForSceneGuid[0].Data + : null; + + if (GetCachedAssetStateForData(guid, addressableEntry.BundleFileId, + addressableEntry.parentGroup.Guid, catalogData, + dependencies.Select(x => x.guid), + out CachedAssetState cachedAssetState)) + cachedInfos.Add(cachedAssetState); + } + } + + /// + /// Gets the path of the cache data from a selected build. + /// + /// If true, the user is allowed to browse for a specific file. + /// The path of the previous state .bin file used to detect changes from the previous build to the content update build. + public static string GetContentStateDataPath(bool browse) + { + return GetContentStateDataPath(browse, null); + } + + internal static string GetContentStateDataPath(bool browse, AddressableAssetSettings settings) + { + if (settings == null) + settings = AddressableAssetSettingsDefaultObject.Settings; + var profileSettings = settings == null ? null : settings.profileSettings; + string assetPath = profileSettings != null ? profileSettings.EvaluateString(settings.activeProfileId, settings.ContentStateBuildPath) : ""; + + if (string.IsNullOrEmpty(assetPath)) + { + assetPath = settings != null + ? settings.GetContentStateBuildPath() + : Path.Combine(AddressableAssetSettingsDefaultObject.kDefaultConfigFolder, PlatformMappingService.GetPlatformPathSubFolder()); + } + + if (browse) + { + if (string.IsNullOrEmpty(assetPath)) + assetPath = Application.dataPath; + + assetPath = EditorUtility.OpenFilePanel("Build Data File", Path.GetDirectoryName(assetPath), "bin"); + + if (string.IsNullOrEmpty(assetPath)) + return null; + + return assetPath; + } + + if (!ResourceManagerConfig.ShouldPathUseWebRequest(assetPath)) + { + try + { + Directory.CreateDirectory(assetPath); + } + catch (Exception e) + { + Debug.LogError(e.Message + "\nCheck \"Content State Build Path\" in Addressables settings. Falling back to config folder location."); + assetPath = Path.Combine(AddressableAssetSettingsDefaultObject.kDefaultConfigFolder, + PlatformMappingService.GetPlatformPathSubFolder()); + Directory.CreateDirectory(assetPath); + } + } + +#if ENABLE_CCD + switch(settings.BuildAndReleaseBinFileOption) + { + case BuildAndReleaseContentStateBehavior.UsePresetLocation: + //do nothing + break; + case BuildAndReleaseContentStateBehavior.UseCCDBucket: + assetPath = settings.RemoteCatalogLoadPath.GetValue(settings); + break; + } +#endif + + var path = Path.Combine(assetPath, "addressables_content_state.bin"); + return path; + } + + /// + /// Downloads the content state bin to a temporary directory + /// + /// The url of the bin file + /// The temp path the bin file was downloaded to. + internal static string DownloadBinFileToTempLocation(string url) + { + if (!Directory.Exists(ContentUpdateScript.PreviousContentStateFileCachePath)) + Directory.CreateDirectory(Path.GetDirectoryName(ContentUpdateScript.PreviousContentStateFileCachePath)); + else if (File.Exists(ContentUpdateScript.PreviousContentStateFileCachePath)) + File.Delete(ContentUpdateScript.PreviousContentStateFileCachePath); + + try + { + var bytes = new WebClient().DownloadData(url); + File.WriteAllBytes(ContentUpdateScript.PreviousContentStateFileCachePath, bytes); + } + catch + { + //Do nothing, nothing will get downloaded and the users can select a file manually if they want. + } + + return ContentUpdateScript.PreviousContentStateFileCachePath; + } + + /// + /// Loads cache data from a specific location + /// + /// + /// The ContentState object. + public static AddressablesContentState LoadContentState(string contentStateDataPath) + { + if (string.IsNullOrEmpty(contentStateDataPath)) + { + Debug.LogErrorFormat("Unable to load cache data from {0}.", contentStateDataPath); + return null; + } + + var stream = new FileStream(contentStateDataPath, FileMode.Open, FileAccess.Read); + var formatter = new BinaryFormatter(); + var cacheData = formatter.Deserialize(stream) as AddressablesContentState; + if (cacheData == null) + { + Addressables.LogError( + "Invalid hash data file. This file is usually named addressables_content_state.bin and is saved in the same folder as your source AddressableAssetsSettings.asset file."); + return null; + } + + stream.Dispose(); + return cacheData; + } + + static bool s_StreamingAssetsExists; + static string kStreamingAssetsPath = "Assets/StreamingAssets"; + + internal static void Cleanup(bool deleteStreamingAssetsFolderIfEmpty, bool cleanBuildPath) + { + if (cleanBuildPath) + { + DirectoryUtility.DeleteDirectory(Addressables.BuildPath, onlyIfEmpty: false, recursiveDelete: true); + } + + if (deleteStreamingAssetsFolderIfEmpty) + { + DirectoryUtility.DeleteDirectory(kStreamingAssetsPath, onlyIfEmpty: true); + } + } + + /// + /// Builds player content using the player content version from a specified cache file. + /// + /// The settings object to use for the build. + /// The path of the cache data to use. + /// The build operation. + public static AddressablesPlayerBuildResult BuildContentUpdate(AddressableAssetSettings settings, string contentStateDataPath) + { + var cacheData = LoadContentState(contentStateDataPath); + if (!IsCacheDataValid(settings, cacheData)) + return null; + + s_StreamingAssetsExists = Directory.Exists("Assets/StreamingAssets"); + var context = new AddressablesDataBuilderInput(settings, cacheData.playerVersion); + context.IsContentUpdateBuild = true; + context.PreviousContentState = cacheData; + + Cleanup(!s_StreamingAssetsExists, false); + + SceneManagerState.Record(); + var result = settings.ActivePlayerDataBuilder.BuildData(context); + if (!string.IsNullOrEmpty(result.Error)) + Debug.LogError(result.Error); + SceneManagerState.Restore(); + return result; + } + + internal static bool IsCacheDataValid(AddressableAssetSettings settings, AddressablesContentState cacheData) + { + if (cacheData == null) + return false; + + if (cacheData.editorVersion != Application.unityVersion) + Addressables.LogWarningFormat("Building content update with Unity editor version `{0}`, data was created with version `{1}`. This may result in incompatible data.", + Application.unityVersion, cacheData.editorVersion); + + if (string.IsNullOrEmpty(cacheData.remoteCatalogLoadPath)) + { + Addressables.LogError("Previous build had 'Build Remote Catalog' disabled. You cannot update a player that has no remote catalog specified"); + return false; + } + + if (!settings.BuildRemoteCatalog) + { + Addressables.LogError("Current settings have 'Build Remote Catalog' disabled. You cannot update a player that has no remote catalog to look to."); + return false; + } + + if (cacheData.remoteCatalogLoadPath != settings.RemoteCatalogLoadPath.GetValue(settings)) + { + Addressables.LogErrorFormat( + "Current 'Remote Catalog Load Path' does not match load path of original player. Player will only know to look up catalog at original location. Original: {0} Current: {1}", + cacheData.remoteCatalogLoadPath, settings.RemoteCatalogLoadPath.GetValue(settings)); + return false; + } + + return true; + } + + /// + /// Get all modified addressable asset entries in groups that have BundledAssetGroupSchema and ContentUpdateGroupSchema with static content enabled. + /// This includes any Addressable dependencies that are affected by the modified entries. + /// + /// Addressable asset settings. + /// The cache data path. + /// A list of all modified entries and dependencies (list is empty if there are none); null if failed to load cache data. + public static List GatherModifiedEntries(AddressableAssetSettings settings, string cacheDataPath) + { + HashSet retVal = new HashSet(); + var entriesMap = GatherModifiedEntriesWithDependencies(settings, cacheDataPath); + foreach (var entry in entriesMap.Keys) + { + if (!retVal.Contains(entry)) + retVal.Add(entry); + + foreach (var dependency in entriesMap[entry]) + if (!retVal.Contains(dependency)) + retVal.Add(dependency); + } + + return retVal.ToList(); + } + + internal static void GatherExplicitModifiedEntries(AddressableAssetSettings settings, ref Dictionary> dependencyMap, + AddressablesContentState cacheData) + { + List noBundledAssetGroupSchema = new List(); + List noStaticContent = new List(); + + var allEntries = new List(); + settings.GetAllAssets(allEntries, false, g => + { + if (g == null) + return false; + + if (!g.HasSchema()) + { + noBundledAssetGroupSchema.Add(g.Name); + return false; + } + + if (!g.HasSchema()) + { + noStaticContent.Add(g.Name); + return false; + } + + if (!g.GetSchema().StaticContent) + { + noStaticContent.Add(g.Name); + return false; + } + + g.FlaggedDuringContentUpdateRestriction = false; + return true; + }); + + StringBuilder builder = new StringBuilder(); + builder.AppendFormat("Skipping Prepare for Content Update on {0} group(s):\n\n", + noBundledAssetGroupSchema.Count + noStaticContent.Count); + + + AddInvalidGroupsToLogMessage(builder, noBundledAssetGroupSchema, "Group Did Not Contain BundledAssetGroupSchema"); + AddInvalidGroupsToLogMessage(builder, noStaticContent, "Static Content Not Enabled In Schemas"); + + Debug.Log(builder.ToString()); + + var entryToCacheInfo = new Dictionary(); + foreach (var cacheInfo in cacheData.cachedInfos) + if (cacheInfo != null) + entryToCacheInfo[cacheInfo.asset.guid.ToString()] = cacheInfo; + var modifiedEntries = new List(); + foreach (var entry in allEntries) + { + if (!entryToCacheInfo.TryGetValue(entry.guid, out CachedAssetState cachedInfo) || HasAssetOrDependencyChanged(cachedInfo)) + { + Type mainType = AddressableAssetUtility.MapEditorTypeToRuntimeType(entry.MainAssetType, false); + if ((mainType == null || mainType == typeof(DefaultAsset)) && !entry.IsInResources) + { + entry.FlaggedDuringContentUpdateRestriction = false; + } + else + { + modifiedEntries.Add(entry); + entry.FlaggedDuringContentUpdateRestriction = true; + entry.parentGroup.FlaggedDuringContentUpdateRestriction = true; + } + } + else + entry.FlaggedDuringContentUpdateRestriction = false; + } + + AddAllDependentScenesFromModifiedEntries(modifiedEntries); + foreach (var entry in modifiedEntries) + { + if (!dependencyMap.ContainsKey(entry)) + dependencyMap.Add(entry, new List()); + } + } + + internal static void ClearContentUpdateNotifications(AddressableAssetGroup assetGroup) + { + if (assetGroup == null) + return; + + if (assetGroup.FlaggedDuringContentUpdateRestriction) + { + ClearContentUpdateFlagForEntries(assetGroup.entries); + assetGroup.FlaggedDuringContentUpdateRestriction = false; + } + } + + static void ClearContentUpdateFlagForEntries(ICollection entries) + { + foreach (var e in entries) + { + if (e != null) + e.FlaggedDuringContentUpdateRestriction = false; + if (e.IsFolder) + { + List folderEntries = new List(); + e.GatherFolderEntries(folderEntries, true, true, null); + ClearContentUpdateFlagForEntries(folderEntries); + } + } + } + + /// + /// Get a Dictionary of all modified values and their dependencies. Dependencies will be Addressable and part of a group + /// with static content enabled. + /// + /// Addressable asset settings. + /// The cache data path. + /// A dictionary mapping explicit changed entries to their dependencies. + public static Dictionary> GatherModifiedEntriesWithDependencies(AddressableAssetSettings settings, string cachePath) + { + var modifiedData = new Dictionary>(); + AddressablesContentState cacheData = LoadContentState(cachePath); + if (cacheData == null) + return modifiedData; + + GatherExplicitModifiedEntries(settings, ref modifiedData, cacheData); + GetStaticContentDependenciesForEntries(settings, ref modifiedData, GetGroupGuidToCacheBundleNameMap(cacheData)); + GetEntriesDependentOnModifiedEntries(settings, ref modifiedData); + return modifiedData; + } + + internal static void GetEntriesDependentOnModifiedEntries(AddressableAssetSettings settings, ref Dictionary> dependencyMap) + { + var groups = GetStaticGroups(settings); + Dictionary entryToDependencies = new Dictionary(); + foreach (AddressableAssetGroup group in groups) + { + foreach (AddressableAssetEntry entry in group.entries) + { + string[] dependencies = AssetDatabase.GetDependencies(entry.AssetPath); + entryToDependencies.Add(entry, dependencies); + } + } + + HashSet modifiedEntries = new HashSet(); + foreach (KeyValuePair> mappedEntry in dependencyMap) + { + modifiedEntries.Add(mappedEntry.Key); + foreach (AddressableAssetEntry dependencyEntry in mappedEntry.Value) + modifiedEntries.Add(dependencyEntry); + } + + // if an entry is dependant on a modified entry, then it too should be modified to reference the moved asset + foreach (AddressableAssetEntry modifiedEntry in modifiedEntries) + { + foreach (KeyValuePair dependency in entryToDependencies) + { + if (dependency.Key != modifiedEntry && + dependency.Value.Contains(modifiedEntry.AssetPath) && + dependencyMap.TryGetValue(modifiedEntry, out var value)) + { + if (!value.Contains(dependency.Key)) + value.Add(dependency.Key); + } + } + } + } + + internal static List GetStaticGroups(AddressableAssetSettings settings) + { + List staticGroups = new List(); + foreach (AddressableAssetGroup group in settings.groups) + { + var staticSchema = group.GetSchema(); + if (staticSchema == null) + continue; + var bundleSchema = group.GetSchema(); + if (bundleSchema == null) + continue; + + if (staticSchema.StaticContent) + staticGroups.Add(group); + } + + return staticGroups; + } + + internal static Dictionary GetGroupGuidToCacheBundleNameMap(AddressablesContentState cacheData) + { + var bundleIdToCacheInfo = new Dictionary(); + foreach (CachedBundleState bundleInfo in cacheData.cachedBundles) + { + if (bundleInfo != null && bundleInfo.data is AssetBundleRequestOptions options) + bundleIdToCacheInfo[bundleInfo.bundleFileId] = options.BundleName; + } + + var groupGuidToCacheBundleName = new Dictionary(); + foreach (CachedAssetState cacheInfo in cacheData.cachedInfos) + { + if (cacheInfo != null && bundleIdToCacheInfo.TryGetValue(cacheInfo.bundleFileId, out string bundleName)) + groupGuidToCacheBundleName[cacheInfo.groupGuid] = bundleName; + } + + return groupGuidToCacheBundleName; + } + + internal static HashSet GetGroupGuidsWithUnchangedBundleName(AddressableAssetSettings settings, Dictionary> dependencyMap, + Dictionary groupGuidToCacheBundleName) + { + var result = new HashSet(); + if (groupGuidToCacheBundleName == null || groupGuidToCacheBundleName.Count == 0) + return result; + + var entryGuidToDeps = new Dictionary>(); + foreach (KeyValuePair> entryToDeps in dependencyMap) + { + entryGuidToDeps.Add(entryToDeps.Key.guid, entryToDeps.Value); + } + + foreach (AddressableAssetGroup group in settings.groups) + { + if (group == null || !group.HasSchema()) + continue; + + var schema = group.GetSchema(); + List bundleInputDefinitions = new List(); + + BuildScriptPackedMode.PrepGroupBundlePacking(group, bundleInputDefinitions, schema, entry => !entryGuidToDeps.ContainsKey(entry.guid)); + BuildScriptPackedMode.HandleBundleNames(bundleInputDefinitions); + + for (int i = 0; i < bundleInputDefinitions.Count; i++) + { + string bundleName = Path.GetFileNameWithoutExtension(bundleInputDefinitions[i].assetBundleName); + if (groupGuidToCacheBundleName.TryGetValue(group.Guid, out string cacheBundleName) && cacheBundleName == bundleName) + result.Add(group.Guid); + } + } + + return result; + } + + internal static void GetStaticContentDependenciesForEntries(AddressableAssetSettings settings, ref Dictionary> dependencyMap, + Dictionary groupGuidToCacheBundleName = null) + { + if (dependencyMap == null) + return; + + Dictionary groupHasStaticContentMap = new Dictionary(); + HashSet groupGuidsWithUnchangedBundleName = GetGroupGuidsWithUnchangedBundleName(settings, dependencyMap, groupGuidToCacheBundleName); + + foreach (AddressableAssetEntry entry in dependencyMap.Keys) + { + //since the entry here is from our list of modified entries we know that it must be a part of a static content group. + //Since it's part of a static content update group we can go ahead and set the value to true in the dictionary without explicitly checking it. + if (!groupHasStaticContentMap.ContainsKey(entry.parentGroup)) + groupHasStaticContentMap.Add(entry.parentGroup, true); + + string[] dependencies = AssetDatabase.GetDependencies(entry.AssetPath); + foreach (string dependency in dependencies) + { + string guid = AssetDatabase.AssetPathToGUID(dependency); + var depEntry = settings.FindAssetEntry(guid, true); + if (depEntry == null) + continue; + if (groupGuidsWithUnchangedBundleName.Contains(depEntry.parentGroup.Guid)) + continue; + + if (!groupHasStaticContentMap.TryGetValue(depEntry.parentGroup, out bool groupHasStaticContentEnabled)) + { + groupHasStaticContentEnabled = depEntry.parentGroup.HasSchema() && + depEntry.parentGroup.GetSchema().StaticContent; + + groupHasStaticContentMap.Add(depEntry.parentGroup, groupHasStaticContentEnabled); + } + + if (!dependencyMap.ContainsKey(depEntry) && groupHasStaticContentEnabled) + { + if (!dependencyMap.ContainsKey(entry)) + dependencyMap.Add(entry, new List()); + dependencyMap[entry].Add(depEntry); + depEntry.FlaggedDuringContentUpdateRestriction = true; + } + } + } + } + + internal static void AddAllDependentScenesFromModifiedEntries(List modifiedEntries) + { + List entriesToAdd = new List(); + //If a scene has changed, all scenes that end up in the same bundle need to be marked as modified due to bundle dependencies + foreach (AddressableAssetEntry entry in modifiedEntries) + { + if (entry.IsScene && !entriesToAdd.Contains(entry)) + { + switch (entry.parentGroup.GetSchema().BundleMode) + { + case BundledAssetGroupSchema.BundlePackingMode.PackTogether: + //Add every scene in the group to modified entries + foreach (AddressableAssetEntry sharedGroupEntry in entry.parentGroup.entries) + { + if (sharedGroupEntry.IsScene && !modifiedEntries.Contains(sharedGroupEntry)) + { + sharedGroupEntry.FlaggedDuringContentUpdateRestriction = true; + entriesToAdd.Add(sharedGroupEntry); + } + } + + break; + + case BundledAssetGroupSchema.BundlePackingMode.PackTogetherByLabel: + foreach (AddressableAssetEntry sharedGroupEntry in entry.parentGroup.entries) + { + //Check if one entry has 0 labels while the other contains labels. The labels union check below will return true in this case. + //That is not the behavior we want. So to avoid that, we check here first. + if (sharedGroupEntry.labels.Count == 0 ^ entry.labels.Count == 0) + continue; + + //Only add if labels are shared + if (sharedGroupEntry.IsScene && !modifiedEntries.Contains(sharedGroupEntry) && sharedGroupEntry.labels.Union(entry.labels).Any()) + { + sharedGroupEntry.FlaggedDuringContentUpdateRestriction = true; + entriesToAdd.Add(sharedGroupEntry); + } + } + + break; + + case BundledAssetGroupSchema.BundlePackingMode.PackSeparately: + //Do nothing. The scene will be in a different bundle. + break; + + default: + break; + } + } + } + + modifiedEntries.AddRange(entriesToAdd); + } + + private static void AddInvalidGroupsToLogMessage(StringBuilder builder, List invalidGroupList, + string headerMessage) + { + if (invalidGroupList.Count > 0) + { + builder.AppendFormat("{0} ({1} groups):\n", headerMessage, invalidGroupList.Count); + int maxList = 15; + for (int i = 0; i < invalidGroupList.Count; i++) + { + if (i > maxList) + { + builder.AppendLine("..."); + break; + } + + builder.AppendLine("-" + invalidGroupList[i]); + } + + builder.AppendLine(""); + } + } + + /// + /// Create a new AddressableAssetGroup with the items and mark it as remote. + /// + /// The settings object. + /// The items to move. + /// The name of the new group. + public static void CreateContentUpdateGroup(AddressableAssetSettings settings, List items, string groupName) + { + var contentGroup = settings.CreateGroup(settings.FindUniqueGroupName(groupName), false, false, true, null); + var schema = contentGroup.AddSchema(); + schema.BuildPath.SetVariableByName(settings, AddressableAssetSettings.kRemoteBuildPath); + schema.LoadPath.SetVariableByName(settings, AddressableAssetSettings.kRemoteLoadPath); + schema.BundleMode = BundledAssetGroupSchema.BundlePackingMode.PackTogether; + contentGroup.AddSchema().StaticContent = false; + settings.MoveEntries(items, contentGroup); + } + + /// + /// Functor to filter AddressableAssetGroups during content update. If the functor returns false, the group is excluded from the update. + /// + public static Func GroupFilterFunc = GroupFilter; + + internal static bool GroupFilter(AddressableAssetGroup g) + { + if (g == null) + return false; + if (!g.HasSchema() || !g.GetSchema().StaticContent) + return false; + if (!g.HasSchema() || !g.GetSchema().IncludeInBuild) + return false; + return true; + } + } +} diff --git a/Editor/Build/ContentUpdateScript.cs.meta b/Editor/Build/ContentUpdateScript.cs.meta index b036c602..a0923c67 100644 --- a/Editor/Build/ContentUpdateScript.cs.meta +++ b/Editor/Build/ContentUpdateScript.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 36e2ba320a6ae3e4596bd1fe59b4fe21 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 36e2ba320a6ae3e4596bd1fe59b4fe21 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/DataBuilderInterfaces.cs b/Editor/Build/DataBuilderInterfaces.cs index fe8e508a..f24f2b97 100644 --- a/Editor/Build/DataBuilderInterfaces.cs +++ b/Editor/Build/DataBuilderInterfaces.cs @@ -1,67 +1,67 @@ -using System; -using UnityEngine; - -namespace UnityEditor.AddressableAssets.Build -{ - /// - /// The result of IDataBuilder.Build. - /// - public interface IDataBuilderResult - { - /// - /// Duration of the build in seconds. - /// - double Duration { get; set; } - - /// - /// The number of addressable assets contained in the build. - /// - int LocationCount { get; set; } - - /// - /// Error string, if any. If Succeeded is true, this may be null. - /// - string Error { get; set; } - - /// - /// Path of runtime settings file - /// - string OutputPath { get; set; } - - /// - /// Registry of files created during the build - /// - FileRegistry FileRegistry { get; set; } - } - - /// - /// Builds objects of type IDataBuilderResult. - /// - public interface IDataBuilder - { - /// - /// The name of the builder, used for GUI. - /// - string Name { get; } - - /// - /// Can this builder build the type of data requested. - /// - /// The data type. - /// True if the build can build it. - bool CanBuildData() where T : IDataBuilderResult; - - /// - /// Build the data of a specific type. - /// - /// The data type. - /// The builderInput used to build the data. - /// The built data. - TResult BuildData(AddressablesDataBuilderInput builderInput) where TResult : IDataBuilderResult; - - /// - /// Clears all cached data. - /// - void ClearCachedData(); - } -} +using System; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// The result of IDataBuilder.Build. + /// + public interface IDataBuilderResult + { + /// + /// Duration of the build in seconds. + /// + double Duration { get; set; } + + /// + /// The number of addressable assets contained in the build. + /// + int LocationCount { get; set; } + + /// + /// Error string, if any. If Succeeded is true, this may be null. + /// + string Error { get; set; } + + /// + /// Path of runtime settings file + /// + string OutputPath { get; set; } + + /// + /// Registry of files created during the build + /// + FileRegistry FileRegistry { get; set; } + } + + /// + /// Builds objects of type IDataBuilderResult. + /// + public interface IDataBuilder + { + /// + /// The name of the builder, used for GUI. + /// + string Name { get; } + + /// + /// Can this builder build the type of data requested. + /// + /// The data type. + /// True if the build can build it. + bool CanBuildData() where T : IDataBuilderResult; + + /// + /// Build the data of a specific type. + /// + /// The data type. + /// The builderInput used to build the data. + /// The built data. + TResult BuildData(AddressablesDataBuilderInput builderInput) where TResult : IDataBuilderResult; + + /// + /// Clears all cached data. + /// + void ClearCachedData(); + } +} diff --git a/Editor/Build/DataBuilderInterfaces.cs.meta b/Editor/Build/DataBuilderInterfaces.cs.meta index 6b6684bd..fb3eee7c 100644 --- a/Editor/Build/DataBuilderInterfaces.cs.meta +++ b/Editor/Build/DataBuilderInterfaces.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 732aa8bf67ed2de438b3f2f56850c43e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 732aa8bf67ed2de438b3f2f56850c43e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/DataBuilders.meta b/Editor/Build/DataBuilders.meta index f5844e8e..210106d8 100644 --- a/Editor/Build/DataBuilders.meta +++ b/Editor/Build/DataBuilders.meta @@ -1,8 +1,8 @@ -fileFormatVersion: 2 -guid: 5064f4f2812f9e741be2105c6c338f98 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 5064f4f2812f9e741be2105c6c338f98 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs b/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs index 59e32bf6..9715123c 100644 --- a/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs +++ b/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs @@ -1,167 +1,167 @@ -using System; -using System.Collections.Generic; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.Build.Pipeline.Interfaces; -using UnityEngine; -using UnityEngine.AddressableAssets.Initialization; -using UnityEngine.AddressableAssets.ResourceLocators; - -namespace UnityEditor.AddressableAssets.Build.DataBuilders -{ - /// - /// Interface for any Addressables specific context objects to be used in the Scriptable Build Pipeline context store - /// - public interface IAddressableAssetsBuildContext : IContextObject - { - } - - /// - /// Simple context object for passing data through SBP, between different sections of Addressables code. - /// - public class AddressableAssetsBuildContext : IAddressableAssetsBuildContext - { - private AddressableAssetSettings m_Settings; - - /// - /// The settings object to use. - /// - [Obsolete("Use Settings property instead.")] - public AddressableAssetSettings settings; - - /// - /// The settings object to use. - /// - public AddressableAssetSettings Settings - { - get - { - if (m_Settings == null && !string.IsNullOrEmpty(m_SettingsAssetPath)) - m_Settings = AssetDatabase.LoadAssetAtPath(m_SettingsAssetPath); - return m_Settings; - } - set - { - m_Settings = value; - string guid; - if (m_Settings != null && AssetDatabase.TryGetGUIDAndLocalFileIdentifier(m_Settings, out guid, out long localId)) - m_SettingsAssetPath = AssetDatabase.GUIDToAssetPath(guid); - else - m_SettingsAssetPath = null; - } - } - - private string m_SettingsAssetPath; - - /// - /// The time the build started - /// - public DateTime buildStartTime; - - /// - /// The current runtime data being built. - /// - public ResourceManagerRuntimeData runtimeData; - - /// - /// The list of catalog locations. - /// - public List locations; - - /// - /// Mapping of bundles to asset groups. - /// - public Dictionary bundleToAssetGroup; - - /// - /// Mapping of asset group to bundles. - /// - public Dictionary> assetGroupToBundles; - - /// - /// Set of provider types needed in this build. - /// - public HashSet providerTypes; - - /// - /// The list of all AddressableAssetEntry objects. - /// - public List assetEntries; - - /// - /// Mapping of AssetBundle to the direct dependencies. - /// - public Dictionary> bundleToImmediateBundleDependencies; - - /// - /// A mapping of AssetBundle to the full dependency tree, flattened into a single list. - /// - public Dictionary> bundleToExpandedBundleDependencies; - - /// - /// A mapping of Asset GUID's to resulting ContentCatalogDataEntry entries. - /// - internal Dictionary> GuidToCatalogLocation = null; - - private Dictionary> m_PrimaryKeyToDependers = null; - - internal Dictionary> PrimaryKeyToDependerLocations - { - get - { - if (m_PrimaryKeyToDependers != null) - return m_PrimaryKeyToDependers; - if (locations == null || locations.Count == 0) - { - Debug.LogError("Attempting to get Entries dependent on key, but currently no locations"); - return new Dictionary>(0); - } - - m_PrimaryKeyToDependers = new Dictionary>(locations.Count); - foreach (ContentCatalogDataEntry location in locations) - { - for (int i = 0; i < location.Dependencies.Count; ++i) - { - string dependencyKey = location.Dependencies[i] as string; - if (string.IsNullOrEmpty(dependencyKey)) - continue; - - if (!m_PrimaryKeyToDependers.TryGetValue(dependencyKey, out var dependers)) - { - dependers = new List(); - m_PrimaryKeyToDependers.Add(dependencyKey, dependers); - } - - dependers.Add(location); - } - } - - return m_PrimaryKeyToDependers; - } - } - - private Dictionary m_PrimaryKeyToLocation = null; - - internal Dictionary PrimaryKeyToLocation - { - get - { - if (m_PrimaryKeyToLocation != null) - return m_PrimaryKeyToLocation; - if (locations == null || locations.Count == 0) - { - Debug.LogError("Attempting to get Primary key to entries dependent on key, but currently no locations"); - return new Dictionary(); - } - - m_PrimaryKeyToLocation = new Dictionary(); - foreach (var loc in locations) - { - if (loc != null && loc.Keys[0] != null && loc.Keys[0] is string && !m_PrimaryKeyToLocation.ContainsKey((string)loc.Keys[0])) - m_PrimaryKeyToLocation[(string)loc.Keys[0]] = loc; - } - - return m_PrimaryKeyToLocation; - } - } - } -} +using System; +using System.Collections.Generic; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEngine; +using UnityEngine.AddressableAssets.Initialization; +using UnityEngine.AddressableAssets.ResourceLocators; + +namespace UnityEditor.AddressableAssets.Build.DataBuilders +{ + /// + /// Interface for any Addressables specific context objects to be used in the Scriptable Build Pipeline context store + /// + public interface IAddressableAssetsBuildContext : IContextObject + { + } + + /// + /// Simple context object for passing data through SBP, between different sections of Addressables code. + /// + public class AddressableAssetsBuildContext : IAddressableAssetsBuildContext + { + private AddressableAssetSettings m_Settings; + + /// + /// The settings object to use. + /// + [Obsolete("Use Settings property instead.")] + public AddressableAssetSettings settings; + + /// + /// The settings object to use. + /// + public AddressableAssetSettings Settings + { + get + { + if (m_Settings == null && !string.IsNullOrEmpty(m_SettingsAssetPath)) + m_Settings = AssetDatabase.LoadAssetAtPath(m_SettingsAssetPath); + return m_Settings; + } + set + { + m_Settings = value; + string guid; + if (m_Settings != null && AssetDatabase.TryGetGUIDAndLocalFileIdentifier(m_Settings, out guid, out long localId)) + m_SettingsAssetPath = AssetDatabase.GUIDToAssetPath(guid); + else + m_SettingsAssetPath = null; + } + } + + private string m_SettingsAssetPath; + + /// + /// The time the build started + /// + public DateTime buildStartTime; + + /// + /// The current runtime data being built. + /// + public ResourceManagerRuntimeData runtimeData; + + /// + /// The list of catalog locations. + /// + public List locations; + + /// + /// Mapping of bundles to asset groups. + /// + public Dictionary bundleToAssetGroup; + + /// + /// Mapping of asset group to bundles. + /// + public Dictionary> assetGroupToBundles; + + /// + /// Set of provider types needed in this build. + /// + public HashSet providerTypes; + + /// + /// The list of all AddressableAssetEntry objects. + /// + public List assetEntries; + + /// + /// Mapping of AssetBundle to the direct dependencies. + /// + public Dictionary> bundleToImmediateBundleDependencies; + + /// + /// A mapping of AssetBundle to the full dependency tree, flattened into a single list. + /// + public Dictionary> bundleToExpandedBundleDependencies; + + /// + /// A mapping of Asset GUID's to resulting ContentCatalogDataEntry entries. + /// + internal Dictionary> GuidToCatalogLocation = null; + + private Dictionary> m_PrimaryKeyToDependers = null; + + internal Dictionary> PrimaryKeyToDependerLocations + { + get + { + if (m_PrimaryKeyToDependers != null) + return m_PrimaryKeyToDependers; + if (locations == null || locations.Count == 0) + { + Debug.LogError("Attempting to get Entries dependent on key, but currently no locations"); + return new Dictionary>(0); + } + + m_PrimaryKeyToDependers = new Dictionary>(locations.Count); + foreach (ContentCatalogDataEntry location in locations) + { + for (int i = 0; i < location.Dependencies.Count; ++i) + { + string dependencyKey = location.Dependencies[i] as string; + if (string.IsNullOrEmpty(dependencyKey)) + continue; + + if (!m_PrimaryKeyToDependers.TryGetValue(dependencyKey, out var dependers)) + { + dependers = new List(); + m_PrimaryKeyToDependers.Add(dependencyKey, dependers); + } + + dependers.Add(location); + } + } + + return m_PrimaryKeyToDependers; + } + } + + private Dictionary m_PrimaryKeyToLocation = null; + + internal Dictionary PrimaryKeyToLocation + { + get + { + if (m_PrimaryKeyToLocation != null) + return m_PrimaryKeyToLocation; + if (locations == null || locations.Count == 0) + { + Debug.LogError("Attempting to get Primary key to entries dependent on key, but currently no locations"); + return new Dictionary(); + } + + m_PrimaryKeyToLocation = new Dictionary(); + foreach (var loc in locations) + { + if (loc != null && loc.Keys[0] != null && loc.Keys[0] is string && !m_PrimaryKeyToLocation.ContainsKey((string)loc.Keys[0])) + m_PrimaryKeyToLocation[(string)loc.Keys[0]] = loc; + } + + return m_PrimaryKeyToLocation; + } + } + } +} diff --git a/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs.meta b/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs.meta index 68c471d3..549d1da0 100644 --- a/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs.meta +++ b/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: bdd672a655042ae4fa4c3f8c8d8853a6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: bdd672a655042ae4fa4c3f8c8d8853a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs b/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs index c0b9feac..e412ac52 100644 --- a/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs +++ b/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs @@ -1,97 +1,97 @@ -using System.Collections.Generic; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.AddressableAssets.Settings.GroupSchemas; -using UnityEditor.Build.Pipeline; -using UnityEngine; -using UnityEditor.Build.Content; -using BuildCompression = UnityEngine.BuildCompression; - -namespace UnityEditor.AddressableAssets.Build.DataBuilders -{ - /// - /// Custom bundle parameter container that provides custom compression settings per bundle. - /// - public class AddressableAssetsBundleBuildParameters : BundleBuildParameters - { - Dictionary m_bundleToAssetGroup; - AddressableAssetSettings m_settings; - - /// - /// Create a AddressableAssetsBundleBuildParameters with data needed to determine the correct compression per bundle. - /// - /// The AddressableAssetSettings object to use for retrieving groups. - /// Mapping of bundle identifier to guid of asset groups. - /// The build target. This is used by the BundleBuildParameters base class. - /// The build target group. This is used by the BundleBuildParameters base class. - /// The path for the output folder. This is used by the BundleBuildParameters base class. - public AddressableAssetsBundleBuildParameters(AddressableAssetSettings aaSettings, Dictionary bundleToAssetGroup, BuildTarget target, BuildTargetGroup group, - string outputFolder) : base(target, group, outputFolder) - { - UseCache = true; - ContiguousBundles = aaSettings.ContiguousBundles; -#if NONRECURSIVE_DEPENDENCY_DATA - NonRecursiveDependencies = aaSettings.NonRecursiveBuilding; -#endif - DisableVisibleSubAssetRepresentations = aaSettings.DisableVisibleSubAssetRepresentations; - - m_settings = aaSettings; - m_bundleToAssetGroup = bundleToAssetGroup; - - //If default group has BundledAssetGroupSchema use the compression there otherwise check if the target is webgl or not and try set the compression accordingly - if (m_settings.DefaultGroup.HasSchema()) - BundleCompression = ConverBundleCompressiontToBuildCompression(m_settings.DefaultGroup.GetSchema().Compression); - else - BundleCompression = target == BuildTarget.WebGL ? BuildCompression.LZ4Runtime : BuildCompression.LZMA; - - if (aaSettings.StripUnityVersionFromBundleBuild) - ContentBuildFlags |= ContentBuildFlags.StripUnityVersion; - } - - private BuildCompression ConverBundleCompressiontToBuildCompression( - BundledAssetGroupSchema.BundleCompressionMode compressionMode) - { - BuildCompression compresion = BuildCompression.LZMA; - switch (compressionMode) - { - case BundledAssetGroupSchema.BundleCompressionMode.LZMA: - break; - case BundledAssetGroupSchema.BundleCompressionMode.LZ4: - compresion = BuildCompression.LZ4; - break; - case BundledAssetGroupSchema.BundleCompressionMode.Uncompressed: - compresion = BuildCompression.Uncompressed; - break; - } - - return compresion; - } - - /// - /// Get the compressions settings for the specified asset bundle. - /// - /// The identifier of the asset bundle. - /// The compression setting for the asset group. If the group is not found, the default compression is used. - public override BuildCompression GetCompressionForIdentifier(string identifier) - { - string groupGuid; - if (m_bundleToAssetGroup.TryGetValue(identifier, out groupGuid)) - { - var group = m_settings.FindGroup(g => g != null && g.Guid == groupGuid); - if (group != null) - { - var abSchema = group.GetSchema(); - if (abSchema != null) - return abSchema.GetBuildCompressionForBundle(identifier); - else - Debug.LogWarningFormat("Bundle group {0} does not have BundledAssetGroupSchema.", group.name); - } - else - { - Debug.LogWarningFormat("Unable to find group with guid {0}", groupGuid); - } - } - - return base.GetCompressionForIdentifier(identifier); - } - } -} +using System.Collections.Generic; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEditor.Build.Pipeline; +using UnityEngine; +using UnityEditor.Build.Content; +using BuildCompression = UnityEngine.BuildCompression; + +namespace UnityEditor.AddressableAssets.Build.DataBuilders +{ + /// + /// Custom bundle parameter container that provides custom compression settings per bundle. + /// + public class AddressableAssetsBundleBuildParameters : BundleBuildParameters + { + Dictionary m_bundleToAssetGroup; + AddressableAssetSettings m_settings; + + /// + /// Create a AddressableAssetsBundleBuildParameters with data needed to determine the correct compression per bundle. + /// + /// The AddressableAssetSettings object to use for retrieving groups. + /// Mapping of bundle identifier to guid of asset groups. + /// The build target. This is used by the BundleBuildParameters base class. + /// The build target group. This is used by the BundleBuildParameters base class. + /// The path for the output folder. This is used by the BundleBuildParameters base class. + public AddressableAssetsBundleBuildParameters(AddressableAssetSettings aaSettings, Dictionary bundleToAssetGroup, BuildTarget target, BuildTargetGroup group, + string outputFolder) : base(target, group, outputFolder) + { + UseCache = true; + ContiguousBundles = aaSettings.ContiguousBundles; +#if NONRECURSIVE_DEPENDENCY_DATA + NonRecursiveDependencies = aaSettings.NonRecursiveBuilding; +#endif + DisableVisibleSubAssetRepresentations = aaSettings.DisableVisibleSubAssetRepresentations; + + m_settings = aaSettings; + m_bundleToAssetGroup = bundleToAssetGroup; + + //If default group has BundledAssetGroupSchema use the compression there otherwise check if the target is webgl or not and try set the compression accordingly + if (m_settings.DefaultGroup.HasSchema()) + BundleCompression = ConverBundleCompressiontToBuildCompression(m_settings.DefaultGroup.GetSchema().Compression); + else + BundleCompression = target == BuildTarget.WebGL ? BuildCompression.LZ4Runtime : BuildCompression.LZMA; + + if (aaSettings.StripUnityVersionFromBundleBuild) + ContentBuildFlags |= ContentBuildFlags.StripUnityVersion; + } + + private BuildCompression ConverBundleCompressiontToBuildCompression( + BundledAssetGroupSchema.BundleCompressionMode compressionMode) + { + BuildCompression compresion = BuildCompression.LZMA; + switch (compressionMode) + { + case BundledAssetGroupSchema.BundleCompressionMode.LZMA: + break; + case BundledAssetGroupSchema.BundleCompressionMode.LZ4: + compresion = BuildCompression.LZ4; + break; + case BundledAssetGroupSchema.BundleCompressionMode.Uncompressed: + compresion = BuildCompression.Uncompressed; + break; + } + + return compresion; + } + + /// + /// Get the compressions settings for the specified asset bundle. + /// + /// The identifier of the asset bundle. + /// The compression setting for the asset group. If the group is not found, the default compression is used. + public override BuildCompression GetCompressionForIdentifier(string identifier) + { + string groupGuid; + if (m_bundleToAssetGroup.TryGetValue(identifier, out groupGuid)) + { + var group = m_settings.FindGroup(g => g != null && g.Guid == groupGuid); + if (group != null) + { + var abSchema = group.GetSchema(); + if (abSchema != null) + return abSchema.GetBuildCompressionForBundle(identifier); + else + Debug.LogWarningFormat("Bundle group {0} does not have BundledAssetGroupSchema.", group.name); + } + else + { + Debug.LogWarningFormat("Unable to find group with guid {0}", groupGuid); + } + } + + return base.GetCompressionForIdentifier(identifier); + } + } +} diff --git a/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs.meta b/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs.meta index 544d071b..769373ff 100644 --- a/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs.meta +++ b/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: e4e9f0f7eaff4094990720ec2b944faf -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: e4e9f0f7eaff4094990720ec2b944faf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/DataBuilders/BuildScriptBase.cs b/Editor/Build/DataBuilders/BuildScriptBase.cs index 2208126f..09e5a5a6 100644 --- a/Editor/Build/DataBuilders/BuildScriptBase.cs +++ b/Editor/Build/DataBuilders/BuildScriptBase.cs @@ -1,313 +1,313 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.AddressableAssets.Settings.GroupSchemas; -using UnityEditor.Build.Pipeline.Interfaces; -using UnityEditor.Build.Pipeline.Utilities; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.AddressableAssets.Initialization; -using UnityEngine.AddressableAssets.ResourceLocators; -using UnityEngine.ResourceManagement.ResourceProviders; -using UnityEngine.ResourceManagement.Util; -using UnityEngine.Serialization; - -namespace UnityEditor.AddressableAssets.Build.DataBuilders -{ - /// - /// Base class for build script assets - /// - public class BuildScriptBase : ScriptableObject, IDataBuilder - { - /// - /// The type of instance provider to create for the Addressables system. - /// - [FormerlySerializedAs("m_InstanceProviderType")] - [SerializedTypeRestrictionAttribute(type = typeof(IInstanceProvider))] - public SerializedType instanceProviderType = new SerializedType() {Value = typeof(InstanceProvider)}; - - /// - /// The type of scene provider to create for the addressables system. - /// - [FormerlySerializedAs("m_SceneProviderType")] - [SerializedTypeRestrictionAttribute(type = typeof(ISceneProvider))] - public SerializedType sceneProviderType = new SerializedType() {Value = typeof(SceneProvider)}; - - /// - /// Stores the logged information of all the build tasks. - /// - public IBuildLogger Log - { - get { return m_Log; } - } - - [NonSerialized] - internal IBuildLogger m_Log; - - /// - /// The descriptive name used in the UI. - /// - public virtual string Name - { - get { return "Undefined"; } - } - - internal static void WriteBuildLog(BuildLog log, string directory) - { - Directory.CreateDirectory(directory); - PackageManager.PackageInfo info = PackageManager.PackageInfo.FindForAssembly(typeof(BuildScriptBase).Assembly); - log.AddMetaData(info.name, info.version); - File.WriteAllText(Path.Combine(directory, "AddressablesBuildTEP.json"), log.FormatForTraceEventProfiler()); - } - - /// - /// Build the specified data with the provided builderInput. This is the public entry point. - /// Child class overrides should use - /// - /// The type of data to build. - /// The builderInput object used in the build. - /// The build data result. - public TResult BuildData(AddressablesDataBuilderInput builderInput) where TResult : IDataBuilderResult - { - if (!CanBuildData()) - { - var message = "Data builder " + Name + " cannot build requested type: " + typeof(TResult); - Debug.LogError(message); - return AddressableAssetBuildResult.CreateResult(null, 0, message); - } - - AddressableAnalytics.BuildType buildType = AddressableAnalytics.DetermineBuildType(); - m_Log = (builderInput.Logger != null) ? builderInput.Logger : new BuildLog(); - - AddressablesRuntimeProperties.ClearCachedPropertyValues(); - - TResult result = default; - // Append the file registry to the results - using (m_Log.ScopedStep(LogLevel.Info, $"Building {this.Name}")) - { - try - { - result = BuildDataImplementation(builderInput); - } - catch (Exception e) - { - string errMessage; - if (e.Message == "path") - errMessage = "Invalid path detected during build. Check for unmatched brackets in your active profile's variables."; - else - errMessage = e.Message; - - Debug.LogError(errMessage); - return AddressableAssetBuildResult.CreateResult(null, 0, errMessage); - } - - if (result != null) - result.FileRegistry = builderInput.Registry; - } - - if (builderInput.Logger == null && m_Log != null) - WriteBuildLog((BuildLog)m_Log, Path.GetDirectoryName(Application.dataPath) + "/" + Addressables.LibraryPath); - - if (result is AddressableAssetBuildResult) - { - AddressableAnalytics.ReportBuildEvent(builderInput, result as AddressableAssetBuildResult, buildType); - } - - return result; - } - - /// - /// The implementation of . That is the public entry point, - /// this is the home for child class overrides. - /// - /// The builderInput object used in the build - /// The type of data to build - /// The build data result - protected virtual TResult BuildDataImplementation(AddressablesDataBuilderInput builderInput) where TResult : IDataBuilderResult - { - return default(TResult); - } - - /// - /// Loops over each group, after doing some data checking. - /// - /// The Addressables builderInput object to base the group processing on - /// An error string if there were any problems processing the groups - protected virtual string ProcessAllGroups(AddressableAssetsBuildContext aaContext) - { - try - { - if (aaContext == null || - aaContext.Settings == null || - aaContext.Settings.groups == null) - { - return "No groups found to process in build script " + Name; - } - - //intentionally for not foreach so groups can be added mid-loop. - for (int index = 0; index < aaContext.Settings.groups.Count; index++) - { - AddressableAssetGroup assetGroup = aaContext.Settings.groups[index]; - if (assetGroup == null) - continue; - - if (assetGroup.Schemas.Find((x) => x.GetType() == typeof(PlayerDataGroupSchema)) && - assetGroup.Schemas.Find((x) => x.GetType() == typeof(BundledAssetGroupSchema))) - { - return $"Addressable group {assetGroup.Name} cannot have both a {typeof(PlayerDataGroupSchema).Name} and a {typeof(BundledAssetGroupSchema).Name}"; - } - - EditorUtility.DisplayProgressBar($"Processing Addressable Group", assetGroup.Name, (float)index / aaContext.Settings.groups.Count); - var errorString = ProcessGroup(assetGroup, aaContext); - if (!string.IsNullOrEmpty(errorString)) - { - return errorString; - } - } - } finally - { - EditorUtility.ClearProgressBar(); - } - - return string.Empty; - } - - /// - /// Build processing of an individual group. - /// - /// The group to process - /// The Addressables builderInput object to base the group processing on - /// An error string if there were any problems processing the groups - protected virtual string ProcessGroup(AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext) - { - return string.Empty; - } - - /// - /// Used to determine if this builder is capable of building a specific type of data. - /// - /// The type of data needed to be built. - /// True if this builder can build this data. - public virtual bool CanBuildData() where T : IDataBuilderResult - { - return false; - } - - /// - /// Utility method for creating locations from player data. - /// - /// The schema for the group. - /// The group to extract the locations from. - /// The list of created locations to fill in. - /// Any unknown provider types are added to this set in order to ensure they are not stripped. - /// True if any legacy locations were created. This is used by the build scripts to determine if a legacy provider is needed. - protected bool CreateLocationsForPlayerData(PlayerDataGroupSchema playerDataSchema, AddressableAssetGroup assetGroup, List locations, HashSet providerTypes) - { - bool needsLegacyProvider = false; - if (playerDataSchema != null && (playerDataSchema.IncludeBuildSettingsScenes || playerDataSchema.IncludeResourcesFolders)) - { - var entries = new List(); - assetGroup.GatherAllAssets(entries, true, true, false); - foreach (var a in entries.Where(e => e.IsInSceneList || e.IsInResources)) - { - if (!playerDataSchema.IncludeBuildSettingsScenes && a.IsInSceneList) - continue; - if (!playerDataSchema.IncludeResourcesFolders && a.IsInResources) - continue; - a.CreateCatalogEntries(locations, false, a.IsScene ? "" : typeof(LegacyResourcesProvider).FullName, null, null, providerTypes); - if (!a.IsScene) - needsLegacyProvider = true; - } - } - - return needsLegacyProvider; - } - - /// - /// Utility method for deleting files. - /// - /// The file path to delete. - protected static void DeleteFile(string path) - { - try - { - if (File.Exists(path)) - File.Delete(path); - } - catch (Exception ex) - { - Debug.LogException(ex); - } - } - - /// - /// Utility method to write a file. The directory will be created if it does not exist. - /// - /// The path of the file to write. - /// The content of the file. - /// The file registry used to track all produced artifacts. - /// True if the file was written. - protected internal static bool WriteFile(string path, byte[] content, FileRegistry registry) - { - try - { - registry.AddFile(path); - var dir = Path.GetDirectoryName(path); - if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) - Directory.CreateDirectory(dir); - File.WriteAllBytes(path, content); - return true; - } - catch (Exception ex) - { - Debug.LogException(ex); - registry.RemoveFile(path); - return false; - } - } - - /// - /// Utility method to write a file. The directory will be created if it does not exist. - /// - /// The path of the file to write. - /// The content of the file. - /// The file registry used to track all produced artifacts. - /// True if the file was written. - protected static bool WriteFile(string path, string content, FileRegistry registry) - { - try - { - registry.AddFile(path); - var dir = Path.GetDirectoryName(path); - if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) - Directory.CreateDirectory(dir); - File.WriteAllText(path, content); - return true; - } - catch (Exception ex) - { - Debug.LogException(ex); - registry.RemoveFile(path); - return false; - } - } - - /// - /// Used to clean up any cached data created by this builder. - /// - public virtual void ClearCachedData() - { - } - - /// - /// Checks to see if the data is built for the given builder. - /// - /// Returns true if the data is built. Returns false otherwise. - public virtual bool IsDataBuilt() - { - return false; - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEditor.Build.Pipeline.Utilities; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.AddressableAssets.Initialization; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.ResourceManagement.Util; +using UnityEngine.Serialization; + +namespace UnityEditor.AddressableAssets.Build.DataBuilders +{ + /// + /// Base class for build script assets + /// + public class BuildScriptBase : ScriptableObject, IDataBuilder + { + /// + /// The type of instance provider to create for the Addressables system. + /// + [FormerlySerializedAs("m_InstanceProviderType")] + [SerializedTypeRestrictionAttribute(type = typeof(IInstanceProvider))] + public SerializedType instanceProviderType = new SerializedType() {Value = typeof(InstanceProvider)}; + + /// + /// The type of scene provider to create for the addressables system. + /// + [FormerlySerializedAs("m_SceneProviderType")] + [SerializedTypeRestrictionAttribute(type = typeof(ISceneProvider))] + public SerializedType sceneProviderType = new SerializedType() {Value = typeof(SceneProvider)}; + + /// + /// Stores the logged information of all the build tasks. + /// + public IBuildLogger Log + { + get { return m_Log; } + } + + [NonSerialized] + internal IBuildLogger m_Log; + + /// + /// The descriptive name used in the UI. + /// + public virtual string Name + { + get { return "Undefined"; } + } + + internal static void WriteBuildLog(BuildLog log, string directory) + { + Directory.CreateDirectory(directory); + PackageManager.PackageInfo info = PackageManager.PackageInfo.FindForAssembly(typeof(BuildScriptBase).Assembly); + log.AddMetaData(info.name, info.version); + File.WriteAllText(Path.Combine(directory, "AddressablesBuildTEP.json"), log.FormatForTraceEventProfiler()); + } + + /// + /// Build the specified data with the provided builderInput. This is the public entry point. + /// Child class overrides should use + /// + /// The type of data to build. + /// The builderInput object used in the build. + /// The build data result. + public TResult BuildData(AddressablesDataBuilderInput builderInput) where TResult : IDataBuilderResult + { + if (!CanBuildData()) + { + var message = "Data builder " + Name + " cannot build requested type: " + typeof(TResult); + Debug.LogError(message); + return AddressableAssetBuildResult.CreateResult(null, 0, message); + } + + AddressableAnalytics.BuildType buildType = AddressableAnalytics.DetermineBuildType(); + m_Log = (builderInput.Logger != null) ? builderInput.Logger : new BuildLog(); + + AddressablesRuntimeProperties.ClearCachedPropertyValues(); + + TResult result = default; + // Append the file registry to the results + using (m_Log.ScopedStep(LogLevel.Info, $"Building {this.Name}")) + { + try + { + result = BuildDataImplementation(builderInput); + } + catch (Exception e) + { + string errMessage; + if (e.Message == "path") + errMessage = "Invalid path detected during build. Check for unmatched brackets in your active profile's variables."; + else + errMessage = e.Message; + + Debug.LogError(errMessage); + return AddressableAssetBuildResult.CreateResult(null, 0, errMessage); + } + + if (result != null) + result.FileRegistry = builderInput.Registry; + } + + if (builderInput.Logger == null && m_Log != null) + WriteBuildLog((BuildLog)m_Log, Path.GetDirectoryName(Application.dataPath) + "/" + Addressables.LibraryPath); + + if (result is AddressableAssetBuildResult) + { + AddressableAnalytics.ReportBuildEvent(builderInput, result as AddressableAssetBuildResult, buildType); + } + + return result; + } + + /// + /// The implementation of . That is the public entry point, + /// this is the home for child class overrides. + /// + /// The builderInput object used in the build + /// The type of data to build + /// The build data result + protected virtual TResult BuildDataImplementation(AddressablesDataBuilderInput builderInput) where TResult : IDataBuilderResult + { + return default(TResult); + } + + /// + /// Loops over each group, after doing some data checking. + /// + /// The Addressables builderInput object to base the group processing on + /// An error string if there were any problems processing the groups + protected virtual string ProcessAllGroups(AddressableAssetsBuildContext aaContext) + { + try + { + if (aaContext == null || + aaContext.Settings == null || + aaContext.Settings.groups == null) + { + return "No groups found to process in build script " + Name; + } + + //intentionally for not foreach so groups can be added mid-loop. + for (int index = 0; index < aaContext.Settings.groups.Count; index++) + { + AddressableAssetGroup assetGroup = aaContext.Settings.groups[index]; + if (assetGroup == null) + continue; + + if (assetGroup.Schemas.Find((x) => x.GetType() == typeof(PlayerDataGroupSchema)) && + assetGroup.Schemas.Find((x) => x.GetType() == typeof(BundledAssetGroupSchema))) + { + return $"Addressable group {assetGroup.Name} cannot have both a {typeof(PlayerDataGroupSchema).Name} and a {typeof(BundledAssetGroupSchema).Name}"; + } + + EditorUtility.DisplayProgressBar($"Processing Addressable Group", assetGroup.Name, (float)index / aaContext.Settings.groups.Count); + var errorString = ProcessGroup(assetGroup, aaContext); + if (!string.IsNullOrEmpty(errorString)) + { + return errorString; + } + } + } finally + { + EditorUtility.ClearProgressBar(); + } + + return string.Empty; + } + + /// + /// Build processing of an individual group. + /// + /// The group to process + /// The Addressables builderInput object to base the group processing on + /// An error string if there were any problems processing the groups + protected virtual string ProcessGroup(AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext) + { + return string.Empty; + } + + /// + /// Used to determine if this builder is capable of building a specific type of data. + /// + /// The type of data needed to be built. + /// True if this builder can build this data. + public virtual bool CanBuildData() where T : IDataBuilderResult + { + return false; + } + + /// + /// Utility method for creating locations from player data. + /// + /// The schema for the group. + /// The group to extract the locations from. + /// The list of created locations to fill in. + /// Any unknown provider types are added to this set in order to ensure they are not stripped. + /// True if any legacy locations were created. This is used by the build scripts to determine if a legacy provider is needed. + protected bool CreateLocationsForPlayerData(PlayerDataGroupSchema playerDataSchema, AddressableAssetGroup assetGroup, List locations, HashSet providerTypes) + { + bool needsLegacyProvider = false; + if (playerDataSchema != null && (playerDataSchema.IncludeBuildSettingsScenes || playerDataSchema.IncludeResourcesFolders)) + { + var entries = new List(); + assetGroup.GatherAllAssets(entries, true, true, false); + foreach (var a in entries.Where(e => e.IsInSceneList || e.IsInResources)) + { + if (!playerDataSchema.IncludeBuildSettingsScenes && a.IsInSceneList) + continue; + if (!playerDataSchema.IncludeResourcesFolders && a.IsInResources) + continue; + a.CreateCatalogEntries(locations, false, a.IsScene ? "" : typeof(LegacyResourcesProvider).FullName, null, null, providerTypes); + if (!a.IsScene) + needsLegacyProvider = true; + } + } + + return needsLegacyProvider; + } + + /// + /// Utility method for deleting files. + /// + /// The file path to delete. + protected static void DeleteFile(string path) + { + try + { + if (File.Exists(path)) + File.Delete(path); + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + + /// + /// Utility method to write a file. The directory will be created if it does not exist. + /// + /// The path of the file to write. + /// The content of the file. + /// The file registry used to track all produced artifacts. + /// True if the file was written. + protected internal static bool WriteFile(string path, byte[] content, FileRegistry registry) + { + try + { + registry.AddFile(path); + var dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) + Directory.CreateDirectory(dir); + File.WriteAllBytes(path, content); + return true; + } + catch (Exception ex) + { + Debug.LogException(ex); + registry.RemoveFile(path); + return false; + } + } + + /// + /// Utility method to write a file. The directory will be created if it does not exist. + /// + /// The path of the file to write. + /// The content of the file. + /// The file registry used to track all produced artifacts. + /// True if the file was written. + protected static bool WriteFile(string path, string content, FileRegistry registry) + { + try + { + registry.AddFile(path); + var dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) + Directory.CreateDirectory(dir); + File.WriteAllText(path, content); + return true; + } + catch (Exception ex) + { + Debug.LogException(ex); + registry.RemoveFile(path); + return false; + } + } + + /// + /// Used to clean up any cached data created by this builder. + /// + public virtual void ClearCachedData() + { + } + + /// + /// Checks to see if the data is built for the given builder. + /// + /// Returns true if the data is built. Returns false otherwise. + public virtual bool IsDataBuilt() + { + return false; + } + } +} diff --git a/Editor/Build/DataBuilders/BuildScriptBase.cs.meta b/Editor/Build/DataBuilders/BuildScriptBase.cs.meta index 941616d0..09e133b8 100644 --- a/Editor/Build/DataBuilders/BuildScriptBase.cs.meta +++ b/Editor/Build/DataBuilders/BuildScriptBase.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 8559dec58f92398448ea2ea83fd63c3e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 8559dec58f92398448ea2ea83fd63c3e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/DataBuilders/BuildScriptFastMode.cs b/Editor/Build/DataBuilders/BuildScriptFastMode.cs index 71789c8f..17cc7995 100644 --- a/Editor/Build/DataBuilders/BuildScriptFastMode.cs +++ b/Editor/Build/DataBuilders/BuildScriptFastMode.cs @@ -1,65 +1,65 @@ -using System; -using System.IO; -using UnityEditor.AddressableAssets.Settings; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.AddressableAssets.Initialization; - -namespace UnityEditor.AddressableAssets.Build.DataBuilders -{ - /// - /// Only saves the guid of the settings asset to PlayerPrefs. All catalog data is generated directly from the settings as needed. - /// - [CreateAssetMenu(fileName = nameof(BuildScriptFastMode) + ".asset", menuName = "Addressables/Content Builders/Use Asset Database (fastest)")] - public class BuildScriptFastMode : BuildScriptBase - { - /// - public override string Name - { - get { return "Use Asset Database (fastest)"; } - } - - private bool m_DataBuilt; - - /// - public override void ClearCachedData() - { - m_DataBuilt = false; - } - - /// - public override bool IsDataBuilt() - { - return m_DataBuilt; - } - - /// - protected override string ProcessGroup(AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext) - { - return string.Empty; - } - - /// - public override bool CanBuildData() - { - return typeof(T).IsAssignableFrom(typeof(AddressablesPlayModeBuildResult)); - } - - /// - protected override TResult BuildDataImplementation(AddressablesDataBuilderInput builderInput) - { - if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(builderInput.AddressableSettings, out var guid, out long _)) - { - IDataBuilderResult res = new AddressablesPlayModeBuildResult() {Error = "Invalid Settings asset."}; - return (TResult)res; - } - else - { - PlayerPrefs.SetString(Addressables.kAddressablesRuntimeDataPath, $"GUID:{guid}"); - IDataBuilderResult res = new AddressablesPlayModeBuildResult() {OutputPath = "", Duration = 0}; - m_DataBuilt = true; - return (TResult)res; - } - } - } -} +using System; +using System.IO; +using UnityEditor.AddressableAssets.Settings; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.AddressableAssets.Initialization; + +namespace UnityEditor.AddressableAssets.Build.DataBuilders +{ + /// + /// Only saves the guid of the settings asset to PlayerPrefs. All catalog data is generated directly from the settings as needed. + /// + [CreateAssetMenu(fileName = nameof(BuildScriptFastMode) + ".asset", menuName = "Addressables/Content Builders/Use Asset Database (fastest)")] + public class BuildScriptFastMode : BuildScriptBase + { + /// + public override string Name + { + get { return "Use Asset Database (fastest)"; } + } + + private bool m_DataBuilt; + + /// + public override void ClearCachedData() + { + m_DataBuilt = false; + } + + /// + public override bool IsDataBuilt() + { + return m_DataBuilt; + } + + /// + protected override string ProcessGroup(AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext) + { + return string.Empty; + } + + /// + public override bool CanBuildData() + { + return typeof(T).IsAssignableFrom(typeof(AddressablesPlayModeBuildResult)); + } + + /// + protected override TResult BuildDataImplementation(AddressablesDataBuilderInput builderInput) + { + if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(builderInput.AddressableSettings, out var guid, out long _)) + { + IDataBuilderResult res = new AddressablesPlayModeBuildResult() {Error = "Invalid Settings asset."}; + return (TResult)res; + } + else + { + PlayerPrefs.SetString(Addressables.kAddressablesRuntimeDataPath, $"GUID:{guid}"); + IDataBuilderResult res = new AddressablesPlayModeBuildResult() {OutputPath = "", Duration = 0}; + m_DataBuilt = true; + return (TResult)res; + } + } + } +} diff --git a/Editor/Build/DataBuilders/BuildScriptFastMode.cs.meta b/Editor/Build/DataBuilders/BuildScriptFastMode.cs.meta index 9a01ed53..99c976b9 100644 --- a/Editor/Build/DataBuilders/BuildScriptFastMode.cs.meta +++ b/Editor/Build/DataBuilders/BuildScriptFastMode.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 88d21199f5d473f4db36845f2318f180 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 88d21199f5d473f4db36845f2318f180 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/DataBuilders/BuildScriptPackedMode.cs b/Editor/Build/DataBuilders/BuildScriptPackedMode.cs index 8021f220..7eb62872 100644 --- a/Editor/Build/DataBuilders/BuildScriptPackedMode.cs +++ b/Editor/Build/DataBuilders/BuildScriptPackedMode.cs @@ -1,1649 +1,1661 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using UnityEditor.AddressableAssets.Build.BuildPipelineTasks; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.AddressableAssets.Settings.GroupSchemas; -using UnityEditor.Build.Pipeline; -using UnityEditor.Build.Pipeline.Interfaces; -using UnityEditor.Build.Pipeline.Tasks; -using UnityEditor.Build.Pipeline.Utilities; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.AddressableAssets.Initialization; -using UnityEngine.AddressableAssets.ResourceLocators; -using UnityEngine.AddressableAssets.ResourceProviders; -using UnityEngine.Build.Pipeline; -using UnityEngine.ResourceManagement.ResourceProviders; -using UnityEngine.ResourceManagement.Util; -using static UnityEditor.AddressableAssets.Build.ContentUpdateScript; - -#if UNITY_2022_2_OR_NEWER -using UnityEditor.AddressableAssets.BuildReportVisualizer; -#endif - -namespace UnityEditor.AddressableAssets.Build.DataBuilders -{ - using Debug = UnityEngine.Debug; - - /// - /// Build scripts used for player builds and running with bundles in the editor. - /// - [CreateAssetMenu(fileName = "BuildScriptPacked.asset", menuName = "Addressables/Content Builders/Default Build Script")] - public class BuildScriptPackedMode : BuildScriptBase - { - /// - public override string Name - { - get { return "Default Build Script"; } - } - - internal List m_ResourceProviderData; - List m_AllBundleInputDefs; - Dictionary m_GroupToBundleNames; - HashSet m_CreatedProviderIds; - UnityEditor.Build.Pipeline.Utilities.LinkXmlGenerator m_Linker; - Dictionary m_BundleToInternalId = new Dictionary(); - private string m_CatalogBuildPath; - - internal List ResourceProviderData => m_ResourceProviderData.ToList(); - - /// - public override bool CanBuildData() - { - return typeof(T).IsAssignableFrom(typeof(AddressablesPlayerBuildResult)); - } - - /// - protected override TResult BuildDataImplementation(AddressablesDataBuilderInput builderInput) - { - -#if UNITY_2022_2_OR_NEWER - bool buildReportSettingCheck = ProjectConfigData.UserHasBeenInformedAboutBuildReportSettingPreBuild; - if (!buildReportSettingCheck && !Application.isBatchMode && !ProjectConfigData.GenerateBuildLayout) - { - bool turnOnBuildLayout = EditorUtility.DisplayDialog("Addressables Build Report", "There's a new Addressables Build Report you can check out after your content build. " + - "However, this requires that 'Debug Build Layout' is turned on. The setting can be found in Edit > Preferences > Addressables. Would you like to turn it on?", "Yes", "No"); - if (turnOnBuildLayout) - ProjectConfigData.GenerateBuildLayout = true; - ProjectConfigData.UserHasBeenInformedAboutBuildReportSettingPreBuild = true; - } -#endif - - - TResult result = default(TResult); - m_IncludedGroupsInBuild?.Clear(); - - InitializeBuildContext(builderInput, out AddressableAssetsBuildContext aaContext); - - using (m_Log.ScopedStep(LogLevel.Info, "ProcessAllGroups")) - { - var errorString = ProcessAllGroups(aaContext); - if (!string.IsNullOrEmpty(errorString)) - result = CreateErrorResult(errorString, builderInput, aaContext); - } - - if (result == null) - { - result = DoBuild(builderInput, aaContext); - } - - if (result != null) - { - var span = DateTime.Now - aaContext.buildStartTime; - result.Duration = span.TotalSeconds; - } - - if (result != null && string.IsNullOrEmpty(result.Error)) - { - foreach (var group in m_IncludedGroupsInBuild) - ContentUpdateScript.ClearContentUpdateNotifications(group); - } - - if (result != null && string.IsNullOrEmpty(result.Error)) - { - foreach (var group in m_IncludedGroupsInBuild) - ContentUpdateScript.ClearContentUpdateNotifications(group); - } - -#if UNITY_2022_2_OR_NEWER - if (result != null && !Application.isBatchMode && ProjectConfigData.AutoOpenAddressablesReport && ProjectConfigData.GenerateBuildLayout) - { - BuildReportWindow.ShowWindowAfterBuild(); - } -#endif - return result; - } - - internal const string UserHasBeenInformedAboutBuildReportSettingPreBuild = nameof(UserHasBeenInformedAboutBuildReportSettingPreBuild); - - private TResult CreateErrorResult(string errorString, AddressablesDataBuilderInput builderInput, AddressableAssetsBuildContext aaContext) where TResult : IDataBuilderResult - { - BuildLayoutGenerationTask.GenerateErrorReport(errorString, aaContext, builderInput.PreviousContentState); - return AddressableAssetBuildResult.CreateResult(null, 0, errorString); - } - - internal void InitializeBuildContext(AddressablesDataBuilderInput builderInput, out AddressableAssetsBuildContext aaContext) - { - var now = DateTime.Now; - var aaSettings = builderInput.AddressableSettings; - - m_AllBundleInputDefs = new List(); - m_GroupToBundleNames = new Dictionary(); - var bundleToAssetGroup = new Dictionary(); - var runtimeData = new ResourceManagerRuntimeData - { - SettingsHash = aaSettings.currentHash.ToString(), - CertificateHandlerType = aaSettings.CertificateHandlerType, - BuildTarget = builderInput.Target.ToString(), -#if ENABLE_CCD - CcdManagedData = aaSettings.m_CcdManagedData, -#endif - ProfileEvents = builderInput.ProfilerEventsEnabled, - LogResourceManagerExceptions = aaSettings.buildSettings.LogResourceManagerExceptions, - DisableCatalogUpdateOnStartup = aaSettings.DisableCatalogUpdateOnStartup, - IsLocalCatalogInBundle = aaSettings.BundleLocalCatalog, -#if UNITY_2019_3_OR_NEWER - AddressablesVersion = PackageManager.PackageInfo.FindForAssembly(typeof(Addressables).Assembly)?.version, -#endif - MaxConcurrentWebRequests = aaSettings.MaxConcurrentWebRequests, - CatalogRequestsTimeout = aaSettings.CatalogRequestsTimeout - }; - m_Linker = UnityEditor.Build.Pipeline.Utilities.LinkXmlGenerator.CreateDefault(); - m_Linker.AddAssemblies(new[] {typeof(Addressables).Assembly, typeof(UnityEngine.ResourceManagement.ResourceManager).Assembly}); - m_Linker.AddTypes(runtimeData.CertificateHandlerType); - - m_ResourceProviderData = new List(); - aaContext = new AddressableAssetsBuildContext - { - Settings = aaSettings, - runtimeData = runtimeData, - bundleToAssetGroup = bundleToAssetGroup, - locations = new List(), - providerTypes = new HashSet(), - assetEntries = new List(), - buildStartTime = now - }; - - m_CreatedProviderIds = new HashSet(); - } - - struct SBPSettingsOverwriterScope : IDisposable - { - bool m_PrevSlimResults; - - public SBPSettingsOverwriterScope(bool forceFullWriteResults) - { - m_PrevSlimResults = ScriptableBuildPipeline.slimWriteResults; - if (forceFullWriteResults) - ScriptableBuildPipeline.slimWriteResults = false; - } - - public void Dispose() - { - ScriptableBuildPipeline.slimWriteResults = m_PrevSlimResults; - } - } - - internal static string GetBuiltInShaderBundleNamePrefix(AddressableAssetsBuildContext aaContext) - { - return GetBuiltInShaderBundleNamePrefix(aaContext.Settings); - } - - internal static string GetBuiltInShaderBundleNamePrefix(AddressableAssetSettings settings) - { - string value = ""; - switch (settings.ShaderBundleNaming) - { - case ShaderBundleNaming.DefaultGroupGuid: - value = settings.DefaultGroup.Guid; - break; - case ShaderBundleNaming.ProjectName: - value = Hash128.Compute(GetProjectName()).ToString(); - break; - case ShaderBundleNaming.Custom: - value = settings.ShaderBundleCustomNaming; - break; - } - - return value; - } - - void AddBundleProvider(BundledAssetGroupSchema schema) - { - var bundleProviderId = schema.GetBundleCachedProviderId(); - - if (!m_CreatedProviderIds.Contains(bundleProviderId)) - { - m_CreatedProviderIds.Add(bundleProviderId); - var bundleProviderType = schema.AssetBundleProviderType.Value; - var bundleProviderData = ObjectInitializationData.CreateSerializedInitializationData(bundleProviderType, bundleProviderId); - m_ResourceProviderData.Add(bundleProviderData); - } - } - - internal static string GetMonoScriptBundleNamePrefix(AddressableAssetsBuildContext aaContext) - { - return GetMonoScriptBundleNamePrefix(aaContext.Settings); - } - - internal static string GetMonoScriptBundleNamePrefix(AddressableAssetSettings settings) - { - string value = null; - switch (settings.MonoScriptBundleNaming) - { - case MonoScriptBundleNaming.ProjectName: - value = Hash128.Compute(GetProjectName()).ToString(); - break; - case MonoScriptBundleNaming.DefaultGroupGuid: - value = settings.DefaultGroup.Guid; - break; - case MonoScriptBundleNaming.Custom: - value = settings.MonoScriptBundleCustomNaming; - break; - } - - return value; - } - - /// - /// The method that does the actual building after all the groups have been processed. - /// - /// The generic builderInput of the - /// - /// - /// - protected virtual TResult DoBuild(AddressablesDataBuilderInput builderInput, AddressableAssetsBuildContext aaContext) where TResult : IDataBuilderResult - { - var genericResult = AddressableAssetBuildResult.CreateResult(); - AddressablesPlayerBuildResult addrResult = genericResult as AddressablesPlayerBuildResult; - - ExtractDataTask extractData = new ExtractDataTask(); - ContentUpdateContext contentUpdateContext = default; - List carryOverCachedState = new List(); - var tempPath = Path.GetDirectoryName(Application.dataPath) + "/" + Addressables.LibraryPath + PlatformMappingService.GetPlatformPathSubFolder() + "/addressables_content_state.bin"; - - var bundleRenameMap = new Dictionary(); - var playerBuildVersion = builderInput.PlayerVersion; - if (m_AllBundleInputDefs.Count > 0) - { - if (!BuildUtility.CheckModifiedScenesAndAskToSave()) - return CreateErrorResult("Unsaved scenes", builderInput, aaContext); - - var buildTarget = builderInput.Target; - var buildTargetGroup = builderInput.TargetGroup; - - var buildParams = new AddressableAssetsBundleBuildParameters( - aaContext.Settings, - aaContext.bundleToAssetGroup, - buildTarget, - buildTargetGroup, - aaContext.Settings.buildSettings.bundleBuildPath); - - var builtinShaderBundleName = GetBuiltInShaderBundleNamePrefix(aaContext) + "_unitybuiltinshaders.bundle"; - - var schema = aaContext.Settings.DefaultGroup.GetSchema(); - AddBundleProvider(schema); - - string monoScriptBundleName = GetMonoScriptBundleNamePrefix(aaContext); - if (!string.IsNullOrEmpty(monoScriptBundleName)) - monoScriptBundleName += "_monoscripts.bundle"; - var buildTasks = RuntimeDataBuildTasks(builtinShaderBundleName, monoScriptBundleName); - buildTasks.Add(extractData); - - IBundleBuildResults results; - using (m_Log.ScopedStep(LogLevel.Info, "ContentPipeline.BuildAssetBundles")) - using (new SBPSettingsOverwriterScope(ProjectConfigData.GenerateBuildLayout)) // build layout generation requires full SBP write results - { - var buildContent = new BundleBuildContent(m_AllBundleInputDefs); - var exitCode = ContentPipeline.BuildAssetBundles(buildParams, buildContent, out results, buildTasks, aaContext, m_Log); - - if (exitCode < ReturnCode.Success) - return CreateErrorResult("SBP Error" + exitCode, builderInput, aaContext); - } - - var groups = aaContext.Settings.groups.Where(g => g != null); - - var postCatalogUpdateCallbacks = new List(); - using (m_Log.ScopedStep(LogLevel.Info, "PostProcessBundles")) - using (var progressTracker = new UnityEditor.Build.Pipeline.Utilities.ProgressTracker()) - { - progressTracker.UpdateTask("Post Processing AssetBundles"); - - foreach (var assetGroup in groups) - { - if (!aaContext.assetGroupToBundles.ContainsKey(assetGroup)) - continue; - - using (m_Log.ScopedStep(LogLevel.Info, assetGroup.name)) - { - PostProcessBundles(assetGroup, results, addrResult, - builderInput.Registry, aaContext, - bundleRenameMap, postCatalogUpdateCallbacks); - } - } - } - - using (m_Log.ScopedStep(LogLevel.Info, "Process Catalog Entries")) - { - Dictionary locationIdToCatalogEntryMap = BuildLocationIdToCatalogEntryMap(aaContext.locations); - if (builderInput.PreviousContentState != null) - { - contentUpdateContext = new ContentUpdateContext() - { - BundleToInternalBundleIdMap = m_BundleToInternalId, - GuidToPreviousAssetStateMap = BuildGuidToCachedAssetStateMap(builderInput.PreviousContentState, aaContext.Settings), - IdToCatalogDataEntryMap = locationIdToCatalogEntryMap, - WriteData = extractData.WriteData, - ContentState = builderInput.PreviousContentState, - Registry = builderInput.Registry, - PreviousAssetStateCarryOver = carryOverCachedState - }; - } - ProcessCatalogEntriesForBuild(aaContext, groups, builderInput, extractData.WriteData, - contentUpdateContext, m_BundleToInternalId, locationIdToCatalogEntryMap); - foreach (var postUpdateCatalogCallback in postCatalogUpdateCallbacks) - postUpdateCatalogCallback.Invoke(); - - foreach (var r in results.WriteResults) - { - var resultValue = r.Value; - m_Linker.AddTypes(resultValue.includedTypes); -#if UNITY_2021_1_OR_NEWER - m_Linker.AddSerializedClass(resultValue.includedSerializeReferenceFQN); -#else - if (resultValue.GetType().GetProperty("includedSerializeReferenceFQN") != null) - m_Linker.AddSerializedClass(resultValue.GetType().GetProperty("includedSerializeReferenceFQN").GetValue(resultValue) as System.Collections.Generic.IEnumerable); -#endif - } - } - } - - ContentCatalogData contentCatalog = null; -#if ENABLE_BINARY_CATALOG - using (m_Log.ScopedStep(LogLevel.Info, "Generate Binary Catalog")) - { - contentCatalog = new ContentCatalogData(ResourceManagerRuntimeData.kCatalogAddress); - - if (addrResult != null) - { - object[] hashingObjects = new object[addrResult.AssetBundleBuildResults.Count]; - for (int i = 0; i < addrResult.AssetBundleBuildResults.Count; ++i) - hashingObjects[i] = addrResult.AssetBundleBuildResults[i].Hash; - string buildResultHash = HashingMethods.Calculate(hashingObjects).ToString(); - contentCatalog.m_BuildResultHash = buildResultHash; - } - - contentCatalog.ResourceProviderData.AddRange(m_ResourceProviderData); - foreach (var t in aaContext.providerTypes) - contentCatalog.ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(t)); - - contentCatalog.InstanceProviderData = ObjectInitializationData.CreateSerializedInitializationData(instanceProviderType.Value); - contentCatalog.SceneProviderData = ObjectInitializationData.CreateSerializedInitializationData(sceneProviderType.Value); - - contentCatalog.SetData(aaContext.locations.OrderBy(f => f.InternalId).ToList());//, aaContext.Settings.OptimizeCatalogSize); - var bytes = contentCatalog.SerializeToByteArray(); - var contentHash = HashingMethods.Calculate(bytes); - - if (aaContext.Settings.BuildRemoteCatalog || ProjectConfigData.GenerateBuildLayout) - contentCatalog.localHash = contentHash.ToString(); - - CreateCatalogFiles(bytes, builderInput, aaContext, contentHash.ToString()); - } -#else - using (m_Log.ScopedStep(LogLevel.Info, "Generate JSON Catalog")) - { - contentCatalog = new ContentCatalogData(ResourceManagerRuntimeData.kCatalogAddress); - - if (addrResult != null) - { - object[] hashingObjects = new object[addrResult.AssetBundleBuildResults.Count]; - for (int i = 0; i < addrResult.AssetBundleBuildResults.Count; ++i) - hashingObjects[i] = addrResult.AssetBundleBuildResults[i].Hash; - string buildResultHash = HashingMethods.Calculate(hashingObjects).ToString(); - contentCatalog.m_BuildResultHash = buildResultHash; - } - - contentCatalog.SetData(aaContext.locations.OrderBy(f => f.InternalId).ToList()); - - contentCatalog.ResourceProviderData.AddRange(m_ResourceProviderData); - foreach (var t in aaContext.providerTypes) - contentCatalog.ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(t)); - - contentCatalog.InstanceProviderData = ObjectInitializationData.CreateSerializedInitializationData(instanceProviderType.Value); - contentCatalog.SceneProviderData = ObjectInitializationData.CreateSerializedInitializationData(sceneProviderType.Value); - - //save catalog - string contentHash = null; - string jsonText = null; - using (m_Log.ScopedStep(LogLevel.Info, "Generating Json")) - jsonText = JsonUtility.ToJson(contentCatalog); - if (aaContext.Settings.BuildRemoteCatalog || ProjectConfigData.GenerateBuildLayout) - { - using (m_Log.ScopedStep(LogLevel.Info, "Hashing Catalog")) - contentHash = HashingMethods.Calculate(jsonText).ToString(); - contentCatalog.localHash = contentHash; - } - - CreateCatalogFiles(jsonText, builderInput, aaContext, contentHash); - } -#endif - - - using (m_Log.ScopedStep(LogLevel.Info, "Generate link")) - { - foreach (var pd in contentCatalog.ResourceProviderData) - { - m_Linker.AddTypes(pd.ObjectType.Value); - m_Linker.AddTypes(pd.GetRuntimeTypes()); - } - - m_Linker.AddTypes(contentCatalog.InstanceProviderData.ObjectType.Value); - m_Linker.AddTypes(contentCatalog.InstanceProviderData.GetRuntimeTypes()); - m_Linker.AddTypes(contentCatalog.SceneProviderData.ObjectType.Value); - m_Linker.AddTypes(contentCatalog.SceneProviderData.GetRuntimeTypes()); - - foreach (var io in aaContext.Settings.InitializationObjects) - { - var provider = io as IObjectInitializationDataProvider; - if (provider != null) - { - var id = provider.CreateObjectInitializationData(); - aaContext.runtimeData.InitializationObjects.Add(id); - m_Linker.AddTypes(id.ObjectType.Value); - m_Linker.AddTypes(id.GetRuntimeTypes()); - } - } - - m_Linker.AddTypes(typeof(Addressables)); - Directory.CreateDirectory(Addressables.BuildPath + "/AddressablesLink/"); - m_Linker.Save(Addressables.BuildPath + "/AddressablesLink/link.xml"); - } - - var settingsPath = Addressables.BuildPath + "/" + builderInput.RuntimeSettingsFilename; - - using (m_Log.ScopedStep(LogLevel.Info, "Generate Settings")) - WriteFile(settingsPath, JsonUtility.ToJson(aaContext.runtimeData), builderInput.Registry); - - if (extractData.BuildCache != null && builderInput.PreviousContentState == null) - { - using (m_Log.ScopedStep(LogLevel.Info, "Generate Content Update State")) - { - var remoteCatalogLoadPath = aaContext.Settings.BuildRemoteCatalog - ? aaContext.Settings.RemoteCatalogLoadPath.GetValue(aaContext.Settings) - : string.Empty; - - var allEntries = new List(); - using (m_Log.ScopedStep(LogLevel.Info, "Get Assets")) - aaContext.Settings.GetAllAssets(allEntries, false, ContentUpdateScript.GroupFilter); - - if (ContentUpdateScript.SaveContentState(aaContext.locations, aaContext.GuidToCatalogLocation, tempPath, allEntries, - extractData.DependencyData, playerBuildVersion, remoteCatalogLoadPath, - carryOverCachedState)) - { - string contentStatePath = ContentUpdateScript.GetContentStateDataPath(false, aaContext.Settings); - if (ResourceManagerConfig.ShouldPathUseWebRequest(contentStatePath)) - { -#if ENABLE_CCD - contentStatePath = Path.Combine(aaContext.Settings.RemoteCatalogBuildPath.GetValue(aaContext.Settings), Path.GetFileName(tempPath)); -#else - contentStatePath = ContentUpdateScript.PreviousContentStateFileCachePath; -#endif - } - - try - { - string directory = Path.GetDirectoryName(contentStatePath); - if (!Directory.Exists(directory)) - Directory.CreateDirectory(directory); - if (File.Exists(contentStatePath)) - File.Delete(contentStatePath); - - File.Copy(tempPath, contentStatePath, true); - if (addrResult != null) - addrResult.ContentStateFilePath = contentStatePath; - builderInput.Registry.AddFile(contentStatePath); - } - catch (UnauthorizedAccessException uae) - { - if (!AddressableAssetUtility.IsVCAssetOpenForEdit(contentStatePath)) - Debug.LogErrorFormat("Cannot access the file {0}. It may be locked by version control.", - contentStatePath); - else - Debug.LogException(uae); - } - catch (Exception e) - { - Debug.LogException(e); - } - } - } - } - - if (addrResult != null) - addrResult.IsUpdateContentBuild = builderInput.PreviousContentState != null; - - genericResult.LocationCount = aaContext.locations.Count; - genericResult.OutputPath = settingsPath; - - if (ProjectConfigData.GenerateBuildLayout && extractData.BuildContext != null) - { - using (var progressTracker = new UnityEditor.Build.Pipeline.Utilities.ProgressTracker()) - { - progressTracker.UpdateTask("Generating Build Layout"); - using (m_Log.ScopedStep(LogLevel.Info, "Generate Build Layout")) - { - List tasks = new List(); - var buildLayoutTask = new BuildLayoutGenerationTask(); - buildLayoutTask.m_BundleNameRemap = bundleRenameMap; - buildLayoutTask.m_ContentCatalogData = contentCatalog; - if (contentUpdateContext.ContentState != null) - buildLayoutTask.m_AddressablesInput = builderInput; - tasks.Add(buildLayoutTask); - BuildTasksRunner.Run(tasks, extractData.m_BuildContext); - } - } - } - - return genericResult; - } - - private static void ProcessCatalogEntriesForBuild(AddressableAssetsBuildContext aaContext, - IEnumerable validGroups, AddressablesDataBuilderInput builderInput, IBundleWriteData writeData, - ContentUpdateContext contentUpdateContext, Dictionary bundleToInternalId, Dictionary locationIdToCatalogEntryMap) - { - using (var progressTracker = new UnityEditor.Build.Pipeline.Utilities.ProgressTracker()) - { - progressTracker.UpdateTask("Post Processing Catalog Entries"); - if (builderInput.PreviousContentState != null) - { - RevertUnchangedAssetsToPreviousAssetState.Run(aaContext, contentUpdateContext); - } - else - { - foreach (var assetGroup in validGroups) - SetAssetEntriesBundleFileIdToCatalogEntryBundleFileId(assetGroup.entries, bundleToInternalId, writeData, locationIdToCatalogEntryMap); - } - } - - bundleToInternalId.Clear(); - } - - private static Dictionary BuildLocationIdToCatalogEntryMap(List locations) - { - Dictionary locationIdToCatalogEntryMap = new Dictionary(); - foreach (var location in locations) - locationIdToCatalogEntryMap[location.InternalId] = location; - - return locationIdToCatalogEntryMap; - } - - private static Dictionary BuildGuidToCachedAssetStateMap(AddressablesContentState contentState, AddressableAssetSettings settings) - { - Dictionary addressableEntryToCachedStateMap = new Dictionary(); - foreach (var cachedInfo in contentState.cachedInfos) - addressableEntryToCachedStateMap[cachedInfo.asset.guid.ToString()] = cachedInfo; - - return addressableEntryToCachedStateMap; - } -#if ENABLE_BINARY_CATALOG - internal bool CreateCatalogFiles(byte[] data, AddressablesDataBuilderInput builderInput, AddressableAssetsBuildContext aaContext, string catalogHash = null) - { - if (data == null || data.Length == 0 || builderInput == null || aaContext == null) - { - Addressables.LogError("Unable to create content catalog (Null arguments)."); - return false; - } - - // Path needs to be resolved at runtime. - string localLoadPath = "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/" + builderInput.RuntimeCatalogFilename; - m_CatalogBuildPath = Path.Combine(Addressables.BuildPath, builderInput.RuntimeCatalogFilename); - - if (aaContext.Settings.BundleLocalCatalog) - { - localLoadPath = localLoadPath.Replace(".bin", ".bundle"); - m_CatalogBuildPath = m_CatalogBuildPath.Replace(".bin", ".bundle"); - var returnCode = CreateCatalogBundle(m_CatalogBuildPath, data, builderInput); - if (returnCode != ReturnCode.Success || !File.Exists(m_CatalogBuildPath)) - { - Addressables.LogError($"An error occured during the creation of the content catalog bundle (return code {returnCode})."); - return false; - } - } - else - { - WriteFile(m_CatalogBuildPath, data, builderInput.Registry); - } - - string[] dependencyHashes = null; - if (aaContext.Settings.BuildRemoteCatalog) - { - dependencyHashes = CreateRemoteCatalog(data, aaContext.runtimeData.CatalogLocations, aaContext.Settings, builderInput, new ProviderLoadRequestOptions() { IgnoreFailures = true }, catalogHash); - } - - aaContext.runtimeData.CatalogLocations.Add(new ResourceLocationData( - new[] { ResourceManagerRuntimeData.kCatalogAddress }, - localLoadPath, - typeof(ContentCatalogProvider), - typeof(ContentCatalogData), - dependencyHashes)); - - return true; - } - static string[] CreateRemoteCatalog(byte[] data, List locations, AddressableAssetSettings aaSettings, AddressablesDataBuilderInput builderInput, - ProviderLoadRequestOptions catalogLoadOptions, string contentHash) - { - string[] dependencyHashes = null; - - var versionedFileName = aaSettings.profileSettings.EvaluateString(aaSettings.activeProfileId, "/catalog_" + builderInput.PlayerVersion); - var remoteBuildFolder = aaSettings.RemoteCatalogBuildPath.GetValue(aaSettings); - var remoteLoadFolder = aaSettings.RemoteCatalogLoadPath.GetValue(aaSettings); - - if (string.IsNullOrEmpty(remoteBuildFolder) || - string.IsNullOrEmpty(remoteLoadFolder) || - remoteBuildFolder == AddressableAssetProfileSettings.undefinedEntryValue || - remoteLoadFolder == AddressableAssetProfileSettings.undefinedEntryValue) - { - Addressables.LogWarning( - "Remote Build and/or Load paths are not set on the main AddressableAssetSettings asset, but 'Build Remote Catalog' is true. Cannot create remote catalog. In the inspector for any group, double click the 'Addressable Asset Settings' object to begin inspecting it. '" + - remoteBuildFolder + "', '" + remoteLoadFolder + "'"); - } - else - { - var remoteJsonBuildPath = remoteBuildFolder + versionedFileName + ".bin"; - var remoteHashBuildPath = remoteBuildFolder + versionedFileName + ".hash"; - - WriteFile(remoteJsonBuildPath, data, builderInput.Registry); - WriteFile(remoteHashBuildPath, contentHash, builderInput.Registry); - - dependencyHashes = new string[((int)ContentCatalogProvider.DependencyHashIndex.Count)]; - dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Remote] = ResourceManagerRuntimeData.kCatalogAddress + "RemoteHash"; - dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Cache] = ResourceManagerRuntimeData.kCatalogAddress + "CacheHash"; - - var remoteHashLoadPath = remoteLoadFolder + versionedFileName + ".hash"; - var remoteHashLoadLocation = new ResourceLocationData( - new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Remote] }, - remoteHashLoadPath, - typeof(TextDataProvider), typeof(string)); - remoteHashLoadLocation.Data = catalogLoadOptions.Copy(); - locations.Add(remoteHashLoadLocation); - -#if UNITY_SWITCH - var cacheLoadPath = remoteHashLoadPath; // ResourceLocationBase does not allow empty string id -#else - var cacheLoadPath = "{UnityEngine.Application.persistentDataPath}/com.unity.addressables" + versionedFileName + ".hash"; -#endif - var cacheLoadLocation = new ResourceLocationData( - new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Cache] }, - cacheLoadPath, - typeof(TextDataProvider), typeof(string)); - cacheLoadLocation.Data = catalogLoadOptions.Copy(); - locations.Add(cacheLoadLocation); - } - - return dependencyHashes; - } - - internal ReturnCode CreateCatalogBundle(string filepath, byte[] data, AddressablesDataBuilderInput builderInput) - { - if (string.IsNullOrEmpty(filepath) || data == null || data.Length == 0 || builderInput == null) - { - throw new ArgumentException("Unable to create catalog bundle (null arguments)."); - } - - // A bundle requires an actual asset - var tempFolderName = "TempCatalogFolder"; - - var configFolder = AddressableAssetSettingsDefaultObject.kDefaultConfigFolder; - if (builderInput.AddressableSettings != null && builderInput.AddressableSettings.IsPersisted) - configFolder = builderInput.AddressableSettings.ConfigFolder; - - var tempFolderPath = Path.Combine(configFolder, tempFolderName); - var tempFilePath = Path.Combine(tempFolderPath, Path.GetFileName(filepath).Replace(".bundle", ".bin")); - if (!WriteFile(tempFilePath, data, builderInput.Registry)) - { - throw new Exception("An error occured during the creation of temporary files needed to bundle the content catalog."); - } - - AssetDatabase.Refresh(); - - var bundleBuildContent = new BundleBuildContent(new[] - { - new AssetBundleBuild() - { - assetBundleName = Path.GetFileName(filepath), - assetNames = new[] {tempFilePath}, - addressableNames = new string[0] - } - }); - - var buildTasks = new List - { - new CalculateAssetDependencyData(), - new GenerateBundlePacking(), - new GenerateBundleCommands(), - new WriteSerializedFiles(), - new ArchiveAndCompressBundles() - }; - - var buildParams = new BundleBuildParameters(builderInput.Target, builderInput.TargetGroup, Path.GetDirectoryName(filepath)); - if (builderInput.Target == BuildTarget.WebGL) - buildParams.BundleCompression = BuildCompression.LZ4Runtime; - var retCode = ContentPipeline.BuildAssetBundles(buildParams, bundleBuildContent, out IBundleBuildResults result, buildTasks, m_Log); - - if (Directory.Exists(tempFolderPath)) - { - Directory.Delete(tempFolderPath, true); - builderInput.Registry.RemoveFile(tempFilePath); - } - - var tempFolderMetaFile = tempFolderPath + ".meta"; - if (File.Exists(tempFolderMetaFile)) - { - File.Delete(tempFolderMetaFile); - builderInput.Registry.RemoveFile(tempFolderMetaFile); - } - - if (File.Exists(filepath)) - { - builderInput.Registry.AddFile(filepath); - } - - return retCode; - } - -#else - internal bool CreateCatalogFiles(string jsonText, AddressablesDataBuilderInput builderInput, AddressableAssetsBuildContext aaContext, string catalogHash = null) - { - if (string.IsNullOrEmpty(jsonText) || builderInput == null || aaContext == null) - { - Addressables.LogError("Unable to create content catalog (Null arguments)."); - return false; - } - - // Path needs to be resolved at runtime. - string localLoadPath = "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/" + builderInput.RuntimeCatalogFilename; - m_CatalogBuildPath = Path.Combine(Addressables.BuildPath, builderInput.RuntimeCatalogFilename); - - if (aaContext.Settings.BundleLocalCatalog) - { - localLoadPath = localLoadPath.Replace(".json", ".bundle"); - m_CatalogBuildPath = m_CatalogBuildPath.Replace(".json", ".bundle"); - var returnCode = CreateCatalogBundle(m_CatalogBuildPath, jsonText, builderInput); - if (returnCode != ReturnCode.Success || !File.Exists(m_CatalogBuildPath)) - { - Addressables.LogError($"An error occured during the creation of the content catalog bundle (return code {returnCode})."); - return false; - } - } - else - { - WriteFile(m_CatalogBuildPath, jsonText, builderInput.Registry); - } - - string[] dependencyHashes = null; - if (aaContext.Settings.BuildRemoteCatalog) - { - dependencyHashes = CreateRemoteCatalog(jsonText, aaContext.runtimeData.CatalogLocations, aaContext.Settings, builderInput, new ProviderLoadRequestOptions() {IgnoreFailures = true}, catalogHash); - } - - ResourceLocationData localCatalog = new ResourceLocationData( - new[] {ResourceManagerRuntimeData.kCatalogAddress}, - localLoadPath, - typeof(ContentCatalogProvider), - typeof(ContentCatalogData), - dependencyHashes); - //We need to set the data here because this location data gets used later if we decide to load the remote/cached catalog instead. See DetermineIdToLoad(...) - localCatalog.Data = new ProviderLoadRequestOptions() { IgnoreFailures = true }; - - aaContext.runtimeData.CatalogLocations.Add(localCatalog); - - return true; - } - - internal ReturnCode CreateCatalogBundle(string filepath, string jsonText, AddressablesDataBuilderInput builderInput) - { - if (string.IsNullOrEmpty(filepath) || string.IsNullOrEmpty(jsonText) || builderInput == null) - { - throw new ArgumentException("Unable to create catalog bundle (null arguments)."); - } - - // A bundle requires an actual asset - var tempFolderName = "TempCatalogFolder"; - - var configFolder = AddressableAssetSettingsDefaultObject.kDefaultConfigFolder; - if (builderInput.AddressableSettings != null && builderInput.AddressableSettings.IsPersisted) - configFolder = builderInput.AddressableSettings.ConfigFolder; - - var tempFolderPath = Path.Combine(configFolder, tempFolderName); - var tempFilePath = Path.Combine(tempFolderPath, Path.GetFileName(filepath).Replace(".bundle", ".json")); - if (!WriteFile(tempFilePath, jsonText, builderInput.Registry)) - { - throw new Exception("An error occured during the creation of temporary files needed to bundle the content catalog."); - } - - AssetDatabase.Refresh(); - - var bundleBuildContent = new BundleBuildContent(new[] - { - new AssetBundleBuild() - { - assetBundleName = Path.GetFileName(filepath), - assetNames = new[] {tempFilePath}, - addressableNames = new string[0] - } - }); - - var buildTasks = new List - { - new CalculateAssetDependencyData(), - new GenerateBundlePacking(), - new GenerateBundleCommands(), - new WriteSerializedFiles(), - new ArchiveAndCompressBundles() - }; - - var buildParams = new BundleBuildParameters(builderInput.Target, builderInput.TargetGroup, Path.GetDirectoryName(filepath)); - if (builderInput.Target == BuildTarget.WebGL) - buildParams.BundleCompression = BuildCompression.LZ4Runtime; - var retCode = ContentPipeline.BuildAssetBundles(buildParams, bundleBuildContent, out IBundleBuildResults result, buildTasks, m_Log); - - if (Directory.Exists(tempFolderPath)) - { - Directory.Delete(tempFolderPath, true); - builderInput.Registry.RemoveFile(tempFilePath); - } - - var tempFolderMetaFile = tempFolderPath + ".meta"; - if (File.Exists(tempFolderMetaFile)) - { - File.Delete(tempFolderMetaFile); - builderInput.Registry.RemoveFile(tempFolderMetaFile); - } - - if (File.Exists(filepath)) - { - builderInput.Registry.AddFile(filepath); - } - - return retCode; - } - - - static string[] CreateRemoteCatalog(string jsonText, List locations, AddressableAssetSettings aaSettings, AddressablesDataBuilderInput builderInput, - ProviderLoadRequestOptions catalogLoadOptions, string contentHash) - { - string[] dependencyHashes = null; - - if (string.IsNullOrEmpty(contentHash)) - contentHash = HashingMethods.Calculate(jsonText).ToString(); - - var versionedFileName = aaSettings.profileSettings.EvaluateString(aaSettings.activeProfileId, "/catalog_" + builderInput.PlayerVersion); - var remoteBuildFolder = aaSettings.RemoteCatalogBuildPath.GetValue(aaSettings); - var remoteLoadFolder = aaSettings.RemoteCatalogLoadPath.GetValue(aaSettings); - - if (string.IsNullOrEmpty(remoteBuildFolder) || - string.IsNullOrEmpty(remoteLoadFolder) || - remoteBuildFolder == AddressableAssetProfileSettings.undefinedEntryValue || - remoteLoadFolder == AddressableAssetProfileSettings.undefinedEntryValue) - { - Addressables.LogWarning( - "Remote Build and/or Load paths are not set on the main AddressableAssetSettings asset, but 'Build Remote Catalog' is true. Cannot create remote catalog. In the inspector for any group, double click the 'Addressable Asset Settings' object to begin inspecting it. '" + - remoteBuildFolder + "', '" + remoteLoadFolder + "'"); - } - else - { - var remoteJsonBuildPath = remoteBuildFolder + versionedFileName + ".json"; - var remoteHashBuildPath = remoteBuildFolder + versionedFileName + ".hash"; - - WriteFile(remoteJsonBuildPath, jsonText, builderInput.Registry); - WriteFile(remoteHashBuildPath, contentHash, builderInput.Registry); - - dependencyHashes = new string[((int)ContentCatalogProvider.DependencyHashIndex.Count)]; - dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Remote] = ResourceManagerRuntimeData.kCatalogAddress + "RemoteHash"; - dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Cache] = ResourceManagerRuntimeData.kCatalogAddress + "CacheHash"; - - var remoteHashLoadPath = remoteLoadFolder + versionedFileName + ".hash"; - var remoteHashLoadLocation = new ResourceLocationData( - new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Remote] }, - remoteHashLoadPath, - typeof(TextDataProvider), typeof(string)); - remoteHashLoadLocation.Data = catalogLoadOptions.Copy(); - locations.Add(remoteHashLoadLocation); - -#if UNITY_SWITCH - var cacheLoadPath = remoteHashLoadPath; // ResourceLocationBase does not allow empty string id -#else - var cacheLoadPath = "{UnityEngine.Application.persistentDataPath}/com.unity.addressables" + versionedFileName + ".hash"; -#endif - var cacheLoadLocation = new ResourceLocationData( - new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Cache] }, - cacheLoadPath, - typeof(TextDataProvider), typeof(string)); - cacheLoadLocation.Data = catalogLoadOptions.Copy(); - locations.Add(cacheLoadLocation); - } - - return dependencyHashes; - } - -#endif - internal static string GetProjectName() - { - return new DirectoryInfo(Path.GetDirectoryName(Application.dataPath)).Name; - } - - internal static void SetAssetEntriesBundleFileIdToCatalogEntryBundleFileId(ICollection assetEntries, Dictionary bundleNameToInternalBundleIdMap, - IBundleWriteData writeData, Dictionary locationIdToCatalogEntryMap) - { - foreach (var loc in assetEntries) - { - AddressableAssetEntry processedEntry = loc; - if (loc.IsFolder && loc.SubAssets.Count > 0) - processedEntry = loc.SubAssets[0]; - GUID guid = new GUID(processedEntry.guid); - //For every entry in the write data we need to ensure the BundleFileId is set so we can save it correctly in the cached state - if (writeData.AssetToFiles.TryGetValue(guid, out List files)) - { - string file = files[0]; - string fullBundleName = writeData.FileToBundle[file]; - string convertedLocation; - - if (!bundleNameToInternalBundleIdMap.TryGetValue(fullBundleName, out convertedLocation)) - { - Debug.LogException(new Exception($"Unable to find bundleId for key: {fullBundleName}.")); - } - - if (locationIdToCatalogEntryMap.TryGetValue(convertedLocation, - out ContentCatalogDataEntry catalogEntry)) - { - loc.BundleFileId = catalogEntry.InternalId; - - //This is where we strip out the temporary hash added to the bundle name for Content Update for the AssetEntry - if (loc.parentGroup?.GetSchema()?.BundleNaming == - BundledAssetGroupSchema.BundleNamingStyle.NoHash) - { - loc.BundleFileId = StripHashFromBundleLocation(loc.BundleFileId); - } - } - } - } - } - - static string StripHashFromBundleLocation(string hashedBundleLocation) - { - return hashedBundleLocation.Remove(hashedBundleLocation.LastIndexOf('_')) + ".bundle"; - } - - /// - protected override string ProcessGroup(AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext) - { - if (assetGroup == null) - return string.Empty; - - if (assetGroup.Schemas.Count == 0) - { - Addressables.LogWarning($"{assetGroup.Name} does not have any associated AddressableAssetGroupSchemas. " + - $"Data from this group will not be included in the build. " + - $"If this is unexpected the AddressableGroup may have become corrupted."); - return string.Empty; - } - - foreach (var schema in assetGroup.Schemas) - { - var errorString = ProcessGroupSchema(schema, assetGroup, aaContext); - if (!string.IsNullOrEmpty(errorString)) - return errorString; - } - - return string.Empty; - } - - /// - /// Called per group per schema to evaluate that schema. This can be an easy entry point for implementing the - /// build aspects surrounding a custom schema. Note, you should not rely on schemas getting called in a specific - /// order. - /// - /// The schema to process - /// The group this schema was pulled from - /// The general Addressables build builderInput - /// - protected virtual string ProcessGroupSchema(AddressableAssetGroupSchema schema, AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext) - { - var playerDataSchema = schema as PlayerDataGroupSchema; - if (playerDataSchema != null) - return ProcessPlayerDataSchema(playerDataSchema, assetGroup, aaContext); - var bundledAssetSchema = schema as BundledAssetGroupSchema; - if (bundledAssetSchema != null) - return ProcessBundledAssetSchema(bundledAssetSchema, assetGroup, aaContext); - return string.Empty; - } - - internal string ProcessPlayerDataSchema( - PlayerDataGroupSchema schema, - AddressableAssetGroup assetGroup, - AddressableAssetsBuildContext aaContext) - { - if (CreateLocationsForPlayerData(schema, assetGroup, aaContext.locations, aaContext.providerTypes)) - { - if (!m_CreatedProviderIds.Contains(typeof(LegacyResourcesProvider).Name)) - { - m_CreatedProviderIds.Add(typeof(LegacyResourcesProvider).Name); - m_ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(typeof(LegacyResourcesProvider))); - } - } - - return string.Empty; - } - - /// - /// A temporary list of the groups that get processed during a build. - /// - List m_IncludedGroupsInBuild = new List(); - - /// - /// The processing of the bundled asset schema. This is where the bundle(s) for a given group are actually setup. - /// - /// The BundledAssetGroupSchema to process - /// The group this schema was pulled from - /// The general Addressables build builderInput - /// The error string, if any. - protected virtual string ProcessBundledAssetSchema( - BundledAssetGroupSchema schema, - AddressableAssetGroup assetGroup, - AddressableAssetsBuildContext aaContext) - { - if (schema == null || !schema.IncludeInBuild || !assetGroup.entries.Any()) - return string.Empty; - - var errorStr = ErrorCheckBundleSettings(schema, assetGroup, aaContext.Settings); - if (!string.IsNullOrEmpty(errorStr)) - return errorStr; - - m_IncludedGroupsInBuild?.Add(assetGroup); - - AddBundleProvider(schema); - - var assetProviderId = schema.GetAssetCachedProviderId(); - if (!m_CreatedProviderIds.Contains(assetProviderId)) - { - m_CreatedProviderIds.Add(assetProviderId); - var assetProviderType = schema.BundledAssetProviderType.Value; - var assetProviderData = ObjectInitializationData.CreateSerializedInitializationData(assetProviderType, assetProviderId); - m_ResourceProviderData.Add(assetProviderData); - } - -#if UNITY_2022_1_OR_NEWER - string loadPath = schema.LoadPath.GetValue(aaContext.Settings); - if (loadPath.StartsWith("http://", StringComparison.Ordinal) && PlayerSettings.insecureHttpOption == InsecureHttpOption.NotAllowed) - Addressables.LogWarning($"Addressable group {assetGroup.Name} uses insecure http for its load path. To allow http connections for UnityWebRequests, change your settings in Edit > Project Settings > Player > Other Settings > Configuration > Allow downloads over HTTP."); -#endif - if (schema.Compression == BundledAssetGroupSchema.BundleCompressionMode.LZMA && aaContext.runtimeData.BuildTarget == BuildTarget.WebGL.ToString()) - Addressables.LogWarning($"Addressable group {assetGroup.Name} uses LZMA compression, which cannot be decompressed on WebGL. Use LZ4 compression instead."); - - var bundleInputDefs = new List(); - var list = PrepGroupBundlePacking(assetGroup, bundleInputDefs, schema); - aaContext.assetEntries.AddRange(list); - List uniqueNames = HandleBundleNames(bundleInputDefs, aaContext.bundleToAssetGroup, assetGroup.Guid); - (string, string)[] groupBundles = new (string, string)[uniqueNames.Count]; - for (int i = 0; i < uniqueNames.Count; ++i) - groupBundles[i] = (bundleInputDefs[i].assetBundleName, uniqueNames[i]); - m_GroupToBundleNames.Add(assetGroup, groupBundles); - m_AllBundleInputDefs.AddRange(bundleInputDefs); - return string.Empty; - } - - internal static List HandleBundleNames(List bundleInputDefs, Dictionary bundleToAssetGroup = null, string assetGroupGuid = null) - { - var generatedUniqueNames = new List(); - var handledNames = new HashSet(); - - for (int i = 0; i < bundleInputDefs.Count; i++) - { - AssetBundleBuild bundleBuild = bundleInputDefs[i]; - string assetBundleName = bundleBuild.assetBundleName; - if (handledNames.Contains(assetBundleName)) - { - int count = 1; - var newName = assetBundleName; - while (handledNames.Contains(newName) && count < 1000) - newName = assetBundleName.Replace(".bundle", string.Format("{0}.bundle", count++)); - assetBundleName = newName; - } - - string hashedAssetBundleName = HashingMethods.Calculate(assetBundleName) + ".bundle"; - generatedUniqueNames.Add(assetBundleName); - handledNames.Add(assetBundleName); - - bundleBuild.assetBundleName = hashedAssetBundleName; - bundleInputDefs[i] = bundleBuild; - - if (bundleToAssetGroup != null) - bundleToAssetGroup.Add(hashedAssetBundleName, assetGroupGuid); - } - - return generatedUniqueNames; - } - - internal static string ErrorCheckBundleSettings(BundledAssetGroupSchema schema, AddressableAssetGroup assetGroup, AddressableAssetSettings settings) - { - var message = string.Empty; - - string buildPath = settings.profileSettings.GetValueById(settings.activeProfileId, schema.BuildPath.Id); - string loadPath = settings.profileSettings.GetValueById(settings.activeProfileId, schema.LoadPath.Id); - - bool buildLocal = AddressableAssetUtility.StringContains(buildPath, "[UnityEngine.AddressableAssets.Addressables.BuildPath]", StringComparison.Ordinal); - bool loadLocal = AddressableAssetUtility.StringContains(loadPath, "{UnityEngine.AddressableAssets.Addressables.RuntimePath}", StringComparison.Ordinal); - - if (buildLocal && !loadLocal) - { - message = "BuildPath for group '" + assetGroup.Name + "' is set to the dynamic-lookup version of StreamingAssets, but LoadPath is not. \n"; - } - else if (!buildLocal && loadLocal) - { - message = "LoadPath for group " + assetGroup.Name + - " is set to the dynamic-lookup version of StreamingAssets, but BuildPath is not. These paths must both use the dynamic-lookup, or both not use it. \n"; - } - - if (!string.IsNullOrEmpty(message)) - { - message += "BuildPath: '" + buildPath + "'\n"; - message += "LoadPath: '" + loadPath + "'"; - } - - if (schema.Compression == BundledAssetGroupSchema.BundleCompressionMode.LZMA && (buildLocal || loadLocal)) - { - Debug.LogWarningFormat("Bundle compression is set to LZMA, but group {0} uses local content.", assetGroup.Name); - } - - return message; - } - - internal static string CalculateGroupHash(BundledAssetGroupSchema.BundleInternalIdMode mode, AddressableAssetGroup assetGroup, IEnumerable entries) - { - switch (mode) - { - case BundledAssetGroupSchema.BundleInternalIdMode.GroupGuid: return assetGroup.Guid; - case BundledAssetGroupSchema.BundleInternalIdMode.GroupGuidProjectIdHash: return HashingMethods.Calculate(assetGroup.Guid, Application.cloudProjectId).ToString(); - case BundledAssetGroupSchema.BundleInternalIdMode.GroupGuidProjectIdEntriesHash: - return HashingMethods.Calculate(assetGroup.Guid, Application.cloudProjectId, new HashSet(entries.Select(e => e.guid))).ToString(); - } - - throw new Exception("Invalid naming mode."); - } - - /// - /// Processes an AddressableAssetGroup and generates AssetBundle input definitions based on the BundlePackingMode. - /// - /// The AddressableAssetGroup to be processed. - /// The list of bundle definitions fed into the build pipeline AssetBundleBuild - /// The BundledAssetGroupSchema of used to process the assetGroup. - /// A filter to remove AddressableAssetEntries from being processed in the build. - /// The total list of AddressableAssetEntries that were processed. - public static List PrepGroupBundlePacking(AddressableAssetGroup assetGroup, List bundleInputDefs, BundledAssetGroupSchema schema, - Func entryFilter = null) - { - var combinedEntries = new List(); - var packingMode = schema.BundleMode; - var namingMode = schema.InternalBundleIdMode; - bool ignoreUnsupportedFilesInBuild = assetGroup.Settings.IgnoreUnsupportedFilesInBuild; - - switch (packingMode) - { - case BundledAssetGroupSchema.BundlePackingMode.PackTogether: - { - var allEntries = new List(); - foreach (AddressableAssetEntry a in assetGroup.entries) - { - if (entryFilter != null && !entryFilter(a)) - continue; - a.GatherAllAssets(allEntries, true, true, false, entryFilter); - } - - combinedEntries.AddRange(allEntries); - GenerateBuildInputDefinitions(allEntries, bundleInputDefs, CalculateGroupHash(namingMode, assetGroup, allEntries), "all", ignoreUnsupportedFilesInBuild); - } - break; - case BundledAssetGroupSchema.BundlePackingMode.PackSeparately: - { - foreach (AddressableAssetEntry a in assetGroup.entries) - { - if (entryFilter != null && !entryFilter(a)) - continue; - var allEntries = new List(); - a.GatherAllAssets(allEntries, true, true, false, entryFilter); - combinedEntries.AddRange(allEntries); - GenerateBuildInputDefinitions(allEntries, bundleInputDefs, CalculateGroupHash(namingMode, assetGroup, allEntries), a.address, ignoreUnsupportedFilesInBuild); - } - } - break; - case BundledAssetGroupSchema.BundlePackingMode.PackTogetherByLabel: - { - var labelTable = new Dictionary>(); - foreach (AddressableAssetEntry a in assetGroup.entries) - { - if (entryFilter != null && !entryFilter(a)) - continue; - var sb = new StringBuilder(); - foreach (var l in a.labels) - sb.Append(l); - var key = sb.ToString(); - List entries; - if (!labelTable.TryGetValue(key, out entries)) - labelTable.Add(key, entries = new List()); - entries.Add(a); - } - - foreach (var entryGroup in labelTable) - { - var allEntries = new List(); - foreach (var a in entryGroup.Value) - { - if (entryFilter != null && !entryFilter(a)) - continue; - a.GatherAllAssets(allEntries, true, true, false, entryFilter); - } - - combinedEntries.AddRange(allEntries); - GenerateBuildInputDefinitions(allEntries, bundleInputDefs, CalculateGroupHash(namingMode, assetGroup, allEntries), entryGroup.Key, ignoreUnsupportedFilesInBuild); - } - } - break; - default: - throw new Exception("Unknown Packing Mode"); - } - - return combinedEntries; - } - - internal static void GenerateBuildInputDefinitions(List allEntries, List buildInputDefs, string groupGuid, string address, - bool ignoreUnsupportedFilesInBuild) - { - var scenes = new List(); - var assets = new List(); - foreach (var e in allEntries) - { - ThrowExceptionIfInvalidFiletypeOrAddress(e, ignoreUnsupportedFilesInBuild); - if (string.IsNullOrEmpty(e.AssetPath)) - continue; - if (e.IsScene) - scenes.Add(e); - else - assets.Add(e); - } - - if (assets.Count > 0) - buildInputDefs.Add(GenerateBuildInputDefinition(assets, groupGuid + "_assets_" + address + ".bundle")); - if (scenes.Count > 0) - buildInputDefs.Add(GenerateBuildInputDefinition(scenes, groupGuid + "_scenes_" + address + ".bundle")); - } - - private static void ThrowExceptionIfInvalidFiletypeOrAddress(AddressableAssetEntry entry, bool ignoreUnsupportedFilesInBuild) - { - if (entry.guid.Length > 0 && entry.address.Contains('[') && entry.address.Contains(']')) - throw new Exception($"Address '{entry.address}' cannot contain '[ ]'."); - if (entry.MainAssetType == typeof(DefaultAsset) && !AssetDatabase.IsValidFolder(entry.AssetPath)) - { - if (ignoreUnsupportedFilesInBuild) - Debug.LogWarning($"Cannot recognize file type for entry located at '{entry.AssetPath}'. Asset location will be ignored."); - else - throw new Exception($"Cannot recognize file type for entry located at '{entry.AssetPath}'. Asset import failed for using an unsupported file type."); - } - } - - internal static AssetBundleBuild GenerateBuildInputDefinition(List assets, string name) - { - var assetInternalIds = new HashSet(); - var assetsInputDef = new AssetBundleBuild(); - assetsInputDef.assetBundleName = name.ToLower().Replace(" ", "").Replace('\\', '/').Replace("//", "/"); - assetsInputDef.assetNames = assets.Select(s => s.AssetPath).ToArray(); - assetsInputDef.addressableNames = assets.Select(s => s.GetAssetLoadPath(true, assetInternalIds)).ToArray(); - return assetsInputDef; - } - - - // Tests can set this flag to prevent player script compilation. This is the most expensive part of small builds - // and isn't needed for most tests. - internal static bool s_SkipCompilePlayerScripts = false; - - static IList RuntimeDataBuildTasks(string builtinShaderBundleName, string monoScriptBundleName) - { - var buildTasks = new List(); - - // Setup - buildTasks.Add(new SwitchToBuildPlatform()); - buildTasks.Add(new RebuildSpriteAtlasCache()); - - // Player Scripts - if (!s_SkipCompilePlayerScripts) - buildTasks.Add(new BuildPlayerScripts()); - buildTasks.Add(new PostScriptsCallback()); - - // Dependency - buildTasks.Add(new CalculateSceneDependencyData()); - buildTasks.Add(new CalculateAssetDependencyData()); - buildTasks.Add(new AddHashToBundleNameTask()); - buildTasks.Add(new StripUnusedSpriteSources()); - buildTasks.Add(new CreateBuiltInShadersBundle(builtinShaderBundleName)); - if (!string.IsNullOrEmpty(monoScriptBundleName)) - buildTasks.Add(new CreateMonoScriptBundle(monoScriptBundleName)); - buildTasks.Add(new PostDependencyCallback()); - - // Packing - buildTasks.Add(new GenerateBundlePacking()); - buildTasks.Add(new UpdateBundleObjectLayout()); - buildTasks.Add(new GenerateBundleCommands()); - buildTasks.Add(new GenerateSubAssetPathMaps()); - buildTasks.Add(new GenerateBundleMaps()); - buildTasks.Add(new PostPackingCallback()); - - // Writing - buildTasks.Add(new WriteSerializedFiles()); - buildTasks.Add(new ArchiveAndCompressBundles()); - buildTasks.Add(new GenerateLocationListsTask()); - buildTasks.Add(new PostWritingCallback()); - - return buildTasks; - } - - static void MoveFileToDestinationWithTimestampIfDifferent(string srcPath, string destPath, IBuildLogger log) - { - if (srcPath == destPath) - return; - - DateTime time = File.GetLastWriteTime(srcPath); - DateTime destTime = File.Exists(destPath) ? File.GetLastWriteTime(destPath) : new DateTime(); - - if (destTime == time) - return; - - using (log.ScopedStep(LogLevel.Verbose, "Move File", $"{srcPath} -> {destPath}")) - { - var directory = Path.GetDirectoryName(destPath); - if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) - Directory.CreateDirectory(directory); - else if (File.Exists(destPath)) - File.Delete(destPath); - File.Move(srcPath, destPath); - } - } - - void PostProcessBundles(AddressableAssetGroup assetGroup, IBundleBuildResults buildResult, AddressablesPlayerBuildResult addrResult, FileRegistry registry, - AddressableAssetsBuildContext aaContext, Dictionary bundleRenameMap, List postCatalogUpdateCallbacks) - { - var schema = assetGroup.GetSchema(); - if (schema == null) - return; - - var path = schema.BuildPath.GetValue(assetGroup.Settings); - if (string.IsNullOrEmpty(path)) - return; - - List builtBundleNames = aaContext.assetGroupToBundles[assetGroup]; - List outputBundleNames = null; - - if (m_GroupToBundleNames.TryGetValue(assetGroup, out (string,string)[] bundleValues)) - { - outputBundleNames = new List(builtBundleNames.Count); - for (int i = 0; i < builtBundleNames.Count; ++i) - { - string outputName = null; - foreach ((string, string) bundleValue in bundleValues) - { - if (schema.BundleMode == BundledAssetGroupSchema.BundlePackingMode.PackSeparately) - { - if (builtBundleNames[i].StartsWith(bundleValue.Item1, StringComparison.Ordinal)) - outputName = bundleValue.Item2; - } - else if (builtBundleNames[i].Equals(bundleValue.Item1, StringComparison.Ordinal)) - outputName = bundleValue.Item2; - - if (outputName != null) - break; - } - outputBundleNames.Add(string.IsNullOrEmpty(outputName) ? builtBundleNames[i] : outputName); - } - } - else - { - outputBundleNames = new List(builtBundleNames); - } - - for (int i = 0; i < builtBundleNames.Count; ++i) - { - AddressablesPlayerBuildResult.BundleBuildResult bundleResultInfo = new AddressablesPlayerBuildResult.BundleBuildResult(); - bundleResultInfo.SourceAssetGroup = assetGroup; - - if (aaContext.PrimaryKeyToLocation.TryGetValue(builtBundleNames[i], out ContentCatalogDataEntry dataEntry)) - { - var info = buildResult.BundleInfos[builtBundleNames[i]]; - bundleResultInfo.Crc = info.Crc; - bundleResultInfo.Hash = info.Hash.ToString(); - var requestOptions = new AssetBundleRequestOptions - { - Crc = schema.UseAssetBundleCrc ? info.Crc : 0, - UseCrcForCachedBundle = schema.UseAssetBundleCrcForCachedBundles, - UseUnityWebRequestForLocalBundles = schema.UseUnityWebRequestForLocalBundles, - Hash = schema.UseAssetBundleCache ? info.Hash.ToString() : "", - ChunkedTransfer = schema.ChunkedTransfer, - RedirectLimit = schema.RedirectLimit, - RetryCount = schema.RetryCount, - Timeout = schema.Timeout, - BundleName = Path.GetFileNameWithoutExtension(info.FileName), - AssetLoadMode = schema.AssetLoadMode, - BundleSize = GetFileSize(info.FileName), - ClearOtherCachedVersionsWhenLoaded = schema.AssetBundledCacheClearBehavior == BundledAssetGroupSchema.CacheClearBehavior.ClearWhenWhenNewVersionLoaded - }; - dataEntry.Data = requestOptions; - bundleResultInfo.InternalBundleName = requestOptions.BundleName; - - if (assetGroup == assetGroup.Settings.DefaultGroup && info.Dependencies.Length == 0 && !string.IsNullOrEmpty(info.FileName) && - (info.FileName.EndsWith("_unitybuiltinshaders.bundle", StringComparison.Ordinal) || info.FileName.EndsWith("_monoscripts.bundle", StringComparison.Ordinal))) - { - outputBundleNames[i] = ConstructAssetBundleName(null, schema, info, outputBundleNames[i]); - } - else - { - int extensionLength = Path.GetExtension(outputBundleNames[i]).Length; - string[] deconstructedBundleName = outputBundleNames[i].Substring(0, outputBundleNames[i].Length - extensionLength).Split('_'); - string reconstructedBundleName = string.Join("_", deconstructedBundleName, 1, deconstructedBundleName.Length - 1) + ".bundle"; - outputBundleNames[i] = ConstructAssetBundleName(assetGroup, schema, info, reconstructedBundleName); - } - - dataEntry.InternalId = dataEntry.InternalId.Remove(dataEntry.InternalId.Length - builtBundleNames[i].Length) + outputBundleNames[i]; - SetPrimaryKey(dataEntry, outputBundleNames[i], aaContext); - - if (!m_BundleToInternalId.ContainsKey(builtBundleNames[i])) - m_BundleToInternalId.Add(builtBundleNames[i], dataEntry.InternalId); - - if (dataEntry.InternalId.StartsWith("http:\\", StringComparison.Ordinal)) - dataEntry.InternalId = dataEntry.InternalId.Replace("http:\\", "http://").Replace("\\", "/"); - else if (dataEntry.InternalId.StartsWith("https:\\", StringComparison.Ordinal)) - dataEntry.InternalId = dataEntry.InternalId.Replace("https:\\", "https://").Replace("\\", "/"); - } - else - { - Debug.LogWarningFormat("Unable to find ContentCatalogDataEntry for bundle {0}.", outputBundleNames[i]); - } - - var targetPath = Path.Combine(path, outputBundleNames[i]); - bundleResultInfo.FilePath = targetPath; - var srcPath = Path.Combine(assetGroup.Settings.buildSettings.bundleBuildPath, builtBundleNames[i]); - - if (assetGroup.GetSchema()?.BundleNaming == BundledAssetGroupSchema.BundleNamingStyle.NoHash) - outputBundleNames[i] = StripHashFromBundleLocation(outputBundleNames[i]); - - bundleRenameMap.Add(builtBundleNames[i], outputBundleNames[i]); - MoveFileToDestinationWithTimestampIfDifferent(srcPath, targetPath, m_Log); - AddPostCatalogUpdatesInternal(assetGroup, postCatalogUpdateCallbacks, dataEntry, targetPath, registry); - - if (addrResult != null) - addrResult.AssetBundleBuildResults.Add(bundleResultInfo); - - registry.AddFile(targetPath); - } - } - - internal void AddPostCatalogUpdatesInternal(AddressableAssetGroup assetGroup, List postCatalogUpdates, ContentCatalogDataEntry dataEntry, string targetBundlePath, - FileRegistry registry) - { - if (assetGroup.GetSchema()?.BundleNaming == - BundledAssetGroupSchema.BundleNamingStyle.NoHash) - { - postCatalogUpdates.Add(() => - { - //This is where we strip out the temporary hash for the final bundle location and filename - string bundlePathWithoutHash = StripHashFromBundleLocation(targetBundlePath); - if (File.Exists(targetBundlePath)) - { - if (File.Exists(bundlePathWithoutHash)) - File.Delete(bundlePathWithoutHash); - string destFolder = Path.GetDirectoryName(bundlePathWithoutHash); - if (!string.IsNullOrEmpty(destFolder) && !Directory.Exists(destFolder)) - Directory.CreateDirectory(destFolder); - - File.Move(targetBundlePath, bundlePathWithoutHash); - } - - if (registry != null) - { - if (!registry.ReplaceBundleEntry(targetBundlePath, bundlePathWithoutHash)) - Debug.LogErrorFormat("Unable to find registered file for bundle {0}.", targetBundlePath); - } - - if (dataEntry != null) - if (DataEntryDiffersFromBundleFilename(dataEntry, bundlePathWithoutHash)) - dataEntry.InternalId = StripHashFromBundleLocation(dataEntry.InternalId); - }); - } - } - - // if false, there is no need to remove the hash from dataEntry.InternalId - bool DataEntryDiffersFromBundleFilename(ContentCatalogDataEntry dataEntry, string bundlePathWithoutHash) - { - string dataEntryId = dataEntry.InternalId; - string dataEntryFilename = Path.GetFileName(dataEntryId); - string bundleFileName = Path.GetFileName(bundlePathWithoutHash); - - return dataEntryFilename != bundleFileName; - } - - /// - /// Creates a name for an asset bundle using the provided information. - /// - /// The asset group. - /// The schema of the group. - /// The bundle information. - /// The base name of the asset bundle. - /// Returns the asset bundle name with the provided information. - protected virtual string ConstructAssetBundleName(AddressableAssetGroup assetGroup, BundledAssetGroupSchema schema, BundleDetails info, string assetBundleName) - { - if (assetGroup != null) - { - string groupName = assetGroup.Name.Replace(" ", "").Replace('\\', '/').Replace("//", "/").ToLower(); - assetBundleName = groupName + "_" + assetBundleName; - } - - string bundleNameWithHashing = BuildUtility.GetNameWithHashNaming(schema.BundleNaming, info.Hash.ToString(), assetBundleName); - //For no hash, we need the hash temporarily for content update purposes. This will be stripped later on. - if (schema.BundleNaming == BundledAssetGroupSchema.BundleNamingStyle.NoHash) - { - bundleNameWithHashing = bundleNameWithHashing.Replace(".bundle", "_" + info.Hash.ToString() + ".bundle"); - } - - return bundleNameWithHashing; - } - - /// - /// Sets the primary key of the given location. Syncing with other locations that have a dependency on this location - /// - /// CatalogEntry to set the primary key for - /// New Primary key to set on location - /// Addressables build context to collect and assign other location data - /// - private void SetPrimaryKey(ContentCatalogDataEntry forLocation, string newPrimaryKey, AddressableAssetsBuildContext aaContext) - { - if (forLocation == null || forLocation.Keys == null || forLocation.Keys.Count == 0) - throw new ArgumentException("Cannot change primary key. Invalid catalog entry"); - - string originalKey = forLocation.Keys[0] as string; - if (string.IsNullOrEmpty(originalKey)) - throw new ArgumentException("Invalid primary key for catalog entry " + forLocation.ToString()); - - forLocation.Keys[0] = newPrimaryKey; - aaContext.PrimaryKeyToLocation.Remove(originalKey); - aaContext.PrimaryKeyToLocation.Add(newPrimaryKey, forLocation); - - if (!aaContext.PrimaryKeyToDependerLocations.TryGetValue(originalKey, out var dependers)) - return; // nothing depends on it - - foreach (ContentCatalogDataEntry location in dependers) - { - for (int i = 0; i < location.Dependencies.Count; ++i) - { - string keyString = location.Dependencies[i] as string; - if (string.IsNullOrEmpty(keyString)) - continue; - if (keyString == originalKey) - { - location.Dependencies[i] = newPrimaryKey; - break; - } - } - } - - aaContext.PrimaryKeyToDependerLocations.Remove(originalKey); - aaContext.PrimaryKeyToDependerLocations.Add(newPrimaryKey, dependers); - } - - private static long GetFileSize(string fileName) - { - try - { - return new FileInfo(fileName).Length; - } - catch (Exception e) - { - Debug.LogException(e); - return 0; - } - } - - /// - public override void ClearCachedData() - { - if (Directory.Exists(Addressables.BuildPath)) - { - try - { -#if ENABLE_BINARY_CATALOG - var catalogPath = Addressables.BuildPath + "/catalog.bin"; - DeleteFile(catalogPath); -#else - var catalogPath = Addressables.BuildPath + "/catalog.json"; - DeleteFile(catalogPath); -#endif - var settingsPath = Addressables.BuildPath + "/settings.json"; - DeleteFile(settingsPath); - Directory.Delete(Addressables.BuildPath, true); - } - catch (Exception e) - { - Debug.LogException(e); - } - } - } - - /// - public override bool IsDataBuilt() - { - var settingsPath = Addressables.BuildPath + "/settings.json"; - return !String.IsNullOrEmpty(m_CatalogBuildPath) && - File.Exists(m_CatalogBuildPath) && - File.Exists(settingsPath); - } - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using UnityEditor.AddressableAssets.Build.BuildPipelineTasks; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEditor.Build.Pipeline; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEditor.Build.Pipeline.Tasks; +using UnityEditor.Build.Pipeline.Utilities; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.AddressableAssets.Initialization; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.AddressableAssets.ResourceProviders; +using UnityEngine.Build.Pipeline; +using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.ResourceManagement.Util; +using static UnityEditor.AddressableAssets.Build.ContentUpdateScript; + +#if UNITY_2022_2_OR_NEWER +using UnityEditor.AddressableAssets.BuildReportVisualizer; +#endif + +namespace UnityEditor.AddressableAssets.Build.DataBuilders +{ + using Debug = UnityEngine.Debug; + + /// + /// Build scripts used for player builds and running with bundles in the editor. + /// + [CreateAssetMenu(fileName = "BuildScriptPacked.asset", menuName = "Addressables/Content Builders/Default Build Script")] + public class BuildScriptPackedMode : BuildScriptBase + { + /// + public override string Name + { + get { return "Default Build Script"; } + } + + internal List m_ResourceProviderData; + List m_AllBundleInputDefs; + Dictionary m_GroupToBundleNames; + HashSet m_CreatedProviderIds; + UnityEditor.Build.Pipeline.Utilities.LinkXmlGenerator m_Linker; + Dictionary m_BundleToInternalId = new Dictionary(); + private string m_CatalogBuildPath; + + internal List ResourceProviderData => m_ResourceProviderData.ToList(); + + /// + public override bool CanBuildData() + { + return typeof(T).IsAssignableFrom(typeof(AddressablesPlayerBuildResult)); + } + + /// + protected override TResult BuildDataImplementation(AddressablesDataBuilderInput builderInput) + { + +#if UNITY_2022_2_OR_NEWER + bool buildReportSettingCheck = ProjectConfigData.UserHasBeenInformedAboutBuildReportSettingPreBuild; + if (!buildReportSettingCheck && !Application.isBatchMode && !ProjectConfigData.GenerateBuildLayout) + { + bool turnOnBuildLayout = EditorUtility.DisplayDialog("Addressables Build Report", "There's a new Addressables Build Report you can check out after your content build. " + + "However, this requires that 'Debug Build Layout' is turned on. The setting can be found in Edit > Preferences > Addressables. Would you like to turn it on?", "Yes", "No"); + if (turnOnBuildLayout) + ProjectConfigData.GenerateBuildLayout = true; + ProjectConfigData.UserHasBeenInformedAboutBuildReportSettingPreBuild = true; + } +#endif + + + TResult result = default(TResult); + m_IncludedGroupsInBuild?.Clear(); + + InitializeBuildContext(builderInput, out AddressableAssetsBuildContext aaContext); + + using (m_Log.ScopedStep(LogLevel.Info, "ProcessAllGroups")) + { + var errorString = ProcessAllGroups(aaContext); + if (!string.IsNullOrEmpty(errorString)) + result = CreateErrorResult(errorString, builderInput, aaContext); + } + + if (result == null) + { + result = DoBuild(builderInput, aaContext); + } + + if (result != null) + { + var span = DateTime.Now - aaContext.buildStartTime; + result.Duration = span.TotalSeconds; + } + + if (result != null && string.IsNullOrEmpty(result.Error)) + { + foreach (var group in m_IncludedGroupsInBuild) + ContentUpdateScript.ClearContentUpdateNotifications(group); + } + + if (result != null && string.IsNullOrEmpty(result.Error)) + { + foreach (var group in m_IncludedGroupsInBuild) + ContentUpdateScript.ClearContentUpdateNotifications(group); + } + +#if UNITY_2022_2_OR_NEWER + if (result != null && !Application.isBatchMode && ProjectConfigData.AutoOpenAddressablesReport && ProjectConfigData.GenerateBuildLayout) + { + BuildReportWindow.ShowWindowAfterBuild(); + } +#endif + return result; + } + + internal const string UserHasBeenInformedAboutBuildReportSettingPreBuild = nameof(UserHasBeenInformedAboutBuildReportSettingPreBuild); + + private TResult CreateErrorResult(string errorString, AddressablesDataBuilderInput builderInput, AddressableAssetsBuildContext aaContext) where TResult : IDataBuilderResult + { + BuildLayoutGenerationTask.GenerateErrorReport(errorString, aaContext, builderInput.PreviousContentState); + return AddressableAssetBuildResult.CreateResult(null, 0, errorString); + } + + internal void InitializeBuildContext(AddressablesDataBuilderInput builderInput, out AddressableAssetsBuildContext aaContext) + { + var now = DateTime.Now; + var aaSettings = builderInput.AddressableSettings; +#if ENABLE_CCD + // we have to populate the ccd managed data every time we build. + try + { + CcdBuildEvents.Instance.PopulateCcdManagedData(aaSettings, aaSettings.activeProfileId); + } + catch (Exception e) + { + Addressables.LogError("Unable to populated CCD Managed Data. You may need to refresh remote data in the profile window."); + throw; + } +#endif + + m_AllBundleInputDefs = new List(); + m_GroupToBundleNames = new Dictionary(); + var bundleToAssetGroup = new Dictionary(); + var runtimeData = new ResourceManagerRuntimeData + { + SettingsHash = aaSettings.currentHash.ToString(), + CertificateHandlerType = aaSettings.CertificateHandlerType, + BuildTarget = builderInput.Target.ToString(), +#if ENABLE_CCD + CcdManagedData = aaSettings.m_CcdManagedData, +#endif + ProfileEvents = builderInput.ProfilerEventsEnabled, + LogResourceManagerExceptions = aaSettings.buildSettings.LogResourceManagerExceptions, + DisableCatalogUpdateOnStartup = aaSettings.DisableCatalogUpdateOnStartup, + IsLocalCatalogInBundle = aaSettings.BundleLocalCatalog, +#if UNITY_2019_3_OR_NEWER + AddressablesVersion = PackageManager.PackageInfo.FindForAssembly(typeof(Addressables).Assembly)?.version, +#endif + MaxConcurrentWebRequests = aaSettings.MaxConcurrentWebRequests, + CatalogRequestsTimeout = aaSettings.CatalogRequestsTimeout + }; + m_Linker = UnityEditor.Build.Pipeline.Utilities.LinkXmlGenerator.CreateDefault(); + m_Linker.AddAssemblies(new[] {typeof(Addressables).Assembly, typeof(UnityEngine.ResourceManagement.ResourceManager).Assembly}); + m_Linker.AddTypes(runtimeData.CertificateHandlerType); + + m_ResourceProviderData = new List(); + aaContext = new AddressableAssetsBuildContext + { + Settings = aaSettings, + runtimeData = runtimeData, + bundleToAssetGroup = bundleToAssetGroup, + locations = new List(), + providerTypes = new HashSet(), + assetEntries = new List(), + buildStartTime = now + }; + + m_CreatedProviderIds = new HashSet(); + } + + struct SBPSettingsOverwriterScope : IDisposable + { + bool m_PrevSlimResults; + + public SBPSettingsOverwriterScope(bool forceFullWriteResults) + { + m_PrevSlimResults = ScriptableBuildPipeline.slimWriteResults; + if (forceFullWriteResults) + ScriptableBuildPipeline.slimWriteResults = false; + } + + public void Dispose() + { + ScriptableBuildPipeline.slimWriteResults = m_PrevSlimResults; + } + } + + internal static string GetBuiltInShaderBundleNamePrefix(AddressableAssetsBuildContext aaContext) + { + return GetBuiltInShaderBundleNamePrefix(aaContext.Settings); + } + + internal static string GetBuiltInShaderBundleNamePrefix(AddressableAssetSettings settings) + { + string value = ""; + switch (settings.ShaderBundleNaming) + { + case ShaderBundleNaming.DefaultGroupGuid: + value = settings.DefaultGroup.Guid; + break; + case ShaderBundleNaming.ProjectName: + value = Hash128.Compute(GetProjectName()).ToString(); + break; + case ShaderBundleNaming.Custom: + value = settings.ShaderBundleCustomNaming; + break; + } + + return value; + } + + void AddBundleProvider(BundledAssetGroupSchema schema) + { + var bundleProviderId = schema.GetBundleCachedProviderId(); + + if (!m_CreatedProviderIds.Contains(bundleProviderId)) + { + m_CreatedProviderIds.Add(bundleProviderId); + var bundleProviderType = schema.AssetBundleProviderType.Value; + var bundleProviderData = ObjectInitializationData.CreateSerializedInitializationData(bundleProviderType, bundleProviderId); + m_ResourceProviderData.Add(bundleProviderData); + } + } + + internal static string GetMonoScriptBundleNamePrefix(AddressableAssetsBuildContext aaContext) + { + return GetMonoScriptBundleNamePrefix(aaContext.Settings); + } + + internal static string GetMonoScriptBundleNamePrefix(AddressableAssetSettings settings) + { + string value = null; + switch (settings.MonoScriptBundleNaming) + { + case MonoScriptBundleNaming.ProjectName: + value = Hash128.Compute(GetProjectName()).ToString(); + break; + case MonoScriptBundleNaming.DefaultGroupGuid: + value = settings.DefaultGroup.Guid; + break; + case MonoScriptBundleNaming.Custom: + value = settings.MonoScriptBundleCustomNaming; + break; + } + + return value; + } + + /// + /// The method that does the actual building after all the groups have been processed. + /// + /// The generic builderInput of the + /// + /// + /// + protected virtual TResult DoBuild(AddressablesDataBuilderInput builderInput, AddressableAssetsBuildContext aaContext) where TResult : IDataBuilderResult + { + var genericResult = AddressableAssetBuildResult.CreateResult(); + AddressablesPlayerBuildResult addrResult = genericResult as AddressablesPlayerBuildResult; + + ExtractDataTask extractData = new ExtractDataTask(); + ContentUpdateContext contentUpdateContext = default; + List carryOverCachedState = new List(); + var tempPath = Path.GetDirectoryName(Application.dataPath) + "/" + Addressables.LibraryPath + PlatformMappingService.GetPlatformPathSubFolder() + "/addressables_content_state.bin"; + + var bundleRenameMap = new Dictionary(); + var playerBuildVersion = builderInput.PlayerVersion; + if (m_AllBundleInputDefs.Count > 0) + { + if (!BuildUtility.CheckModifiedScenesAndAskToSave()) + return CreateErrorResult("Unsaved scenes", builderInput, aaContext); + + var buildTarget = builderInput.Target; + var buildTargetGroup = builderInput.TargetGroup; + + var buildParams = new AddressableAssetsBundleBuildParameters( + aaContext.Settings, + aaContext.bundleToAssetGroup, + buildTarget, + buildTargetGroup, + aaContext.Settings.buildSettings.bundleBuildPath); + + var builtinShaderBundleName = GetBuiltInShaderBundleNamePrefix(aaContext) + "_unitybuiltinshaders.bundle"; + + var schema = aaContext.Settings.DefaultGroup.GetSchema(); + AddBundleProvider(schema); + + string monoScriptBundleName = GetMonoScriptBundleNamePrefix(aaContext); + if (!string.IsNullOrEmpty(monoScriptBundleName)) + monoScriptBundleName += "_monoscripts.bundle"; + var buildTasks = RuntimeDataBuildTasks(builtinShaderBundleName, monoScriptBundleName); + buildTasks.Add(extractData); + + IBundleBuildResults results; + using (m_Log.ScopedStep(LogLevel.Info, "ContentPipeline.BuildAssetBundles")) + using (new SBPSettingsOverwriterScope(ProjectConfigData.GenerateBuildLayout)) // build layout generation requires full SBP write results + { + var buildContent = new BundleBuildContent(m_AllBundleInputDefs); + var exitCode = ContentPipeline.BuildAssetBundles(buildParams, buildContent, out results, buildTasks, aaContext, m_Log); + + if (exitCode < ReturnCode.Success) + return CreateErrorResult("SBP Error" + exitCode, builderInput, aaContext); + } + + var groups = aaContext.Settings.groups.Where(g => g != null); + + var postCatalogUpdateCallbacks = new List(); + using (m_Log.ScopedStep(LogLevel.Info, "PostProcessBundles")) + using (var progressTracker = new UnityEditor.Build.Pipeline.Utilities.ProgressTracker()) + { + progressTracker.UpdateTask("Post Processing AssetBundles"); + + foreach (var assetGroup in groups) + { + if (!aaContext.assetGroupToBundles.ContainsKey(assetGroup)) + continue; + + using (m_Log.ScopedStep(LogLevel.Info, assetGroup.name)) + { + PostProcessBundles(assetGroup, results, addrResult, + builderInput.Registry, aaContext, + bundleRenameMap, postCatalogUpdateCallbacks); + } + } + } + + using (m_Log.ScopedStep(LogLevel.Info, "Process Catalog Entries")) + { + Dictionary locationIdToCatalogEntryMap = BuildLocationIdToCatalogEntryMap(aaContext.locations); + if (builderInput.PreviousContentState != null) + { + contentUpdateContext = new ContentUpdateContext() + { + BundleToInternalBundleIdMap = m_BundleToInternalId, + GuidToPreviousAssetStateMap = BuildGuidToCachedAssetStateMap(builderInput.PreviousContentState, aaContext.Settings), + IdToCatalogDataEntryMap = locationIdToCatalogEntryMap, + WriteData = extractData.WriteData, + ContentState = builderInput.PreviousContentState, + Registry = builderInput.Registry, + PreviousAssetStateCarryOver = carryOverCachedState + }; + } + ProcessCatalogEntriesForBuild(aaContext, groups, builderInput, extractData.WriteData, + contentUpdateContext, m_BundleToInternalId, locationIdToCatalogEntryMap); + foreach (var postUpdateCatalogCallback in postCatalogUpdateCallbacks) + postUpdateCatalogCallback.Invoke(); + + foreach (var r in results.WriteResults) + { + var resultValue = r.Value; + m_Linker.AddTypes(resultValue.includedTypes); +#if UNITY_2021_1_OR_NEWER + m_Linker.AddSerializedClass(resultValue.includedSerializeReferenceFQN); +#else + if (resultValue.GetType().GetProperty("includedSerializeReferenceFQN") != null) + m_Linker.AddSerializedClass(resultValue.GetType().GetProperty("includedSerializeReferenceFQN").GetValue(resultValue) as System.Collections.Generic.IEnumerable); +#endif + } + } + } + + ContentCatalogData contentCatalog = null; +#if ENABLE_BINARY_CATALOG + using (m_Log.ScopedStep(LogLevel.Info, "Generate Binary Catalog")) + { + contentCatalog = new ContentCatalogData(ResourceManagerRuntimeData.kCatalogAddress); + + if (addrResult != null) + { + object[] hashingObjects = new object[addrResult.AssetBundleBuildResults.Count]; + for (int i = 0; i < addrResult.AssetBundleBuildResults.Count; ++i) + hashingObjects[i] = addrResult.AssetBundleBuildResults[i].Hash; + string buildResultHash = HashingMethods.Calculate(hashingObjects).ToString(); + contentCatalog.m_BuildResultHash = buildResultHash; + } + + contentCatalog.ResourceProviderData.AddRange(m_ResourceProviderData); + foreach (var t in aaContext.providerTypes) + contentCatalog.ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(t)); + + contentCatalog.InstanceProviderData = ObjectInitializationData.CreateSerializedInitializationData(instanceProviderType.Value); + contentCatalog.SceneProviderData = ObjectInitializationData.CreateSerializedInitializationData(sceneProviderType.Value); + + contentCatalog.SetData(aaContext.locations.OrderBy(f => f.InternalId).ToList());//, aaContext.Settings.OptimizeCatalogSize); + var bytes = contentCatalog.SerializeToByteArray(); + var contentHash = HashingMethods.Calculate(bytes); + + if (aaContext.Settings.BuildRemoteCatalog || ProjectConfigData.GenerateBuildLayout) + contentCatalog.localHash = contentHash.ToString(); + + CreateCatalogFiles(bytes, builderInput, aaContext, contentHash.ToString()); + } +#else + using (m_Log.ScopedStep(LogLevel.Info, "Generate JSON Catalog")) + { + contentCatalog = new ContentCatalogData(ResourceManagerRuntimeData.kCatalogAddress); + + if (addrResult != null) + { + object[] hashingObjects = new object[addrResult.AssetBundleBuildResults.Count]; + for (int i = 0; i < addrResult.AssetBundleBuildResults.Count; ++i) + hashingObjects[i] = addrResult.AssetBundleBuildResults[i].Hash; + string buildResultHash = HashingMethods.Calculate(hashingObjects).ToString(); + contentCatalog.m_BuildResultHash = buildResultHash; + } + + contentCatalog.SetData(aaContext.locations.OrderBy(f => f.InternalId).ToList()); + + contentCatalog.ResourceProviderData.AddRange(m_ResourceProviderData); + foreach (var t in aaContext.providerTypes) + contentCatalog.ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(t)); + + contentCatalog.InstanceProviderData = ObjectInitializationData.CreateSerializedInitializationData(instanceProviderType.Value); + contentCatalog.SceneProviderData = ObjectInitializationData.CreateSerializedInitializationData(sceneProviderType.Value); + + //save catalog + string contentHash = null; + string jsonText = null; + using (m_Log.ScopedStep(LogLevel.Info, "Generating Json")) + jsonText = JsonUtility.ToJson(contentCatalog); + if (aaContext.Settings.BuildRemoteCatalog || ProjectConfigData.GenerateBuildLayout) + { + using (m_Log.ScopedStep(LogLevel.Info, "Hashing Catalog")) + contentHash = HashingMethods.Calculate(jsonText).ToString(); + contentCatalog.localHash = contentHash; + } + + CreateCatalogFiles(jsonText, builderInput, aaContext, contentHash); + } +#endif + + + using (m_Log.ScopedStep(LogLevel.Info, "Generate link")) + { + foreach (var pd in contentCatalog.ResourceProviderData) + { + m_Linker.AddTypes(pd.ObjectType.Value); + m_Linker.AddTypes(pd.GetRuntimeTypes()); + } + + m_Linker.AddTypes(contentCatalog.InstanceProviderData.ObjectType.Value); + m_Linker.AddTypes(contentCatalog.InstanceProviderData.GetRuntimeTypes()); + m_Linker.AddTypes(contentCatalog.SceneProviderData.ObjectType.Value); + m_Linker.AddTypes(contentCatalog.SceneProviderData.GetRuntimeTypes()); + + foreach (var io in aaContext.Settings.InitializationObjects) + { + var provider = io as IObjectInitializationDataProvider; + if (provider != null) + { + var id = provider.CreateObjectInitializationData(); + aaContext.runtimeData.InitializationObjects.Add(id); + m_Linker.AddTypes(id.ObjectType.Value); + m_Linker.AddTypes(id.GetRuntimeTypes()); + } + } + + m_Linker.AddTypes(typeof(Addressables)); + Directory.CreateDirectory(Addressables.BuildPath + "/AddressablesLink/"); + m_Linker.Save(Addressables.BuildPath + "/AddressablesLink/link.xml"); + } + + var settingsPath = Addressables.BuildPath + "/" + builderInput.RuntimeSettingsFilename; + + using (m_Log.ScopedStep(LogLevel.Info, "Generate Settings")) + WriteFile(settingsPath, JsonUtility.ToJson(aaContext.runtimeData), builderInput.Registry); + + if (extractData.BuildCache != null && builderInput.PreviousContentState == null) + { + using (m_Log.ScopedStep(LogLevel.Info, "Generate Content Update State")) + { + var remoteCatalogLoadPath = aaContext.Settings.BuildRemoteCatalog + ? aaContext.Settings.RemoteCatalogLoadPath.GetValue(aaContext.Settings) + : string.Empty; + + var allEntries = new List(); + using (m_Log.ScopedStep(LogLevel.Info, "Get Assets")) + aaContext.Settings.GetAllAssets(allEntries, false, ContentUpdateScript.GroupFilter); + + if (ContentUpdateScript.SaveContentState(aaContext.locations, aaContext.GuidToCatalogLocation, tempPath, allEntries, + extractData.DependencyData, playerBuildVersion, remoteCatalogLoadPath, + carryOverCachedState)) + { + string contentStatePath = ContentUpdateScript.GetContentStateDataPath(false, aaContext.Settings); + if (ResourceManagerConfig.ShouldPathUseWebRequest(contentStatePath)) + { +#if ENABLE_CCD + contentStatePath = Path.Combine(aaContext.Settings.RemoteCatalogBuildPath.GetValue(aaContext.Settings), Path.GetFileName(tempPath)); +#else + contentStatePath = ContentUpdateScript.PreviousContentStateFileCachePath; +#endif + } + + try + { + string directory = Path.GetDirectoryName(contentStatePath); + if (!Directory.Exists(directory)) + Directory.CreateDirectory(directory); + if (File.Exists(contentStatePath)) + File.Delete(contentStatePath); + + File.Copy(tempPath, contentStatePath, true); + if (addrResult != null) + addrResult.ContentStateFilePath = contentStatePath; + builderInput.Registry.AddFile(contentStatePath); + } + catch (UnauthorizedAccessException uae) + { + if (!AddressableAssetUtility.IsVCAssetOpenForEdit(contentStatePath)) + Debug.LogErrorFormat("Cannot access the file {0}. It may be locked by version control.", + contentStatePath); + else + Debug.LogException(uae); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + } + } + + if (addrResult != null) + addrResult.IsUpdateContentBuild = builderInput.PreviousContentState != null; + + genericResult.LocationCount = aaContext.locations.Count; + genericResult.OutputPath = settingsPath; + + if (ProjectConfigData.GenerateBuildLayout && extractData.BuildContext != null) + { + using (var progressTracker = new UnityEditor.Build.Pipeline.Utilities.ProgressTracker()) + { + progressTracker.UpdateTask("Generating Build Layout"); + using (m_Log.ScopedStep(LogLevel.Info, "Generate Build Layout")) + { + List tasks = new List(); + var buildLayoutTask = new BuildLayoutGenerationTask(); + buildLayoutTask.m_BundleNameRemap = bundleRenameMap; + buildLayoutTask.m_ContentCatalogData = contentCatalog; + if (contentUpdateContext.ContentState != null) + buildLayoutTask.m_AddressablesInput = builderInput; + tasks.Add(buildLayoutTask); + BuildTasksRunner.Run(tasks, extractData.m_BuildContext); + } + } + } + + return genericResult; + } + + private static void ProcessCatalogEntriesForBuild(AddressableAssetsBuildContext aaContext, + IEnumerable validGroups, AddressablesDataBuilderInput builderInput, IBundleWriteData writeData, + ContentUpdateContext contentUpdateContext, Dictionary bundleToInternalId, Dictionary locationIdToCatalogEntryMap) + { + using (var progressTracker = new UnityEditor.Build.Pipeline.Utilities.ProgressTracker()) + { + progressTracker.UpdateTask("Post Processing Catalog Entries"); + if (builderInput.PreviousContentState != null) + { + RevertUnchangedAssetsToPreviousAssetState.Run(aaContext, contentUpdateContext); + } + else + { + foreach (var assetGroup in validGroups) + SetAssetEntriesBundleFileIdToCatalogEntryBundleFileId(assetGroup.entries, bundleToInternalId, writeData, locationIdToCatalogEntryMap); + } + } + + bundleToInternalId.Clear(); + } + + private static Dictionary BuildLocationIdToCatalogEntryMap(List locations) + { + Dictionary locationIdToCatalogEntryMap = new Dictionary(); + foreach (var location in locations) + locationIdToCatalogEntryMap[location.InternalId] = location; + + return locationIdToCatalogEntryMap; + } + + private static Dictionary BuildGuidToCachedAssetStateMap(AddressablesContentState contentState, AddressableAssetSettings settings) + { + Dictionary addressableEntryToCachedStateMap = new Dictionary(); + foreach (var cachedInfo in contentState.cachedInfos) + addressableEntryToCachedStateMap[cachedInfo.asset.guid.ToString()] = cachedInfo; + + return addressableEntryToCachedStateMap; + } +#if ENABLE_BINARY_CATALOG + internal bool CreateCatalogFiles(byte[] data, AddressablesDataBuilderInput builderInput, AddressableAssetsBuildContext aaContext, string catalogHash = null) + { + if (data == null || data.Length == 0 || builderInput == null || aaContext == null) + { + Addressables.LogError("Unable to create content catalog (Null arguments)."); + return false; + } + + // Path needs to be resolved at runtime. + string localLoadPath = "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/" + builderInput.RuntimeCatalogFilename; + m_CatalogBuildPath = Path.Combine(Addressables.BuildPath, builderInput.RuntimeCatalogFilename); + + if (aaContext.Settings.BundleLocalCatalog) + { + localLoadPath = localLoadPath.Replace(".bin", ".bundle"); + m_CatalogBuildPath = m_CatalogBuildPath.Replace(".bin", ".bundle"); + var returnCode = CreateCatalogBundle(m_CatalogBuildPath, data, builderInput); + if (returnCode != ReturnCode.Success || !File.Exists(m_CatalogBuildPath)) + { + Addressables.LogError($"An error occured during the creation of the content catalog bundle (return code {returnCode})."); + return false; + } + } + else + { + WriteFile(m_CatalogBuildPath, data, builderInput.Registry); + } + + string[] dependencyHashes = null; + if (aaContext.Settings.BuildRemoteCatalog) + { + dependencyHashes = CreateRemoteCatalog(data, aaContext.runtimeData.CatalogLocations, aaContext.Settings, builderInput, new ProviderLoadRequestOptions() { IgnoreFailures = true }, catalogHash); + } + + aaContext.runtimeData.CatalogLocations.Add(new ResourceLocationData( + new[] { ResourceManagerRuntimeData.kCatalogAddress }, + localLoadPath, + typeof(ContentCatalogProvider), + typeof(ContentCatalogData), + dependencyHashes)); + + return true; + } + static string[] CreateRemoteCatalog(byte[] data, List locations, AddressableAssetSettings aaSettings, AddressablesDataBuilderInput builderInput, + ProviderLoadRequestOptions catalogLoadOptions, string contentHash) + { + string[] dependencyHashes = null; + + var versionedFileName = aaSettings.profileSettings.EvaluateString(aaSettings.activeProfileId, "/catalog_" + builderInput.PlayerVersion); + var remoteBuildFolder = aaSettings.RemoteCatalogBuildPath.GetValue(aaSettings); + var remoteLoadFolder = aaSettings.RemoteCatalogLoadPath.GetValue(aaSettings); + + if (string.IsNullOrEmpty(remoteBuildFolder) || + string.IsNullOrEmpty(remoteLoadFolder) || + remoteBuildFolder == AddressableAssetProfileSettings.undefinedEntryValue || + remoteLoadFolder == AddressableAssetProfileSettings.undefinedEntryValue) + { + Addressables.LogWarning( + "Remote Build and/or Load paths are not set on the main AddressableAssetSettings asset, but 'Build Remote Catalog' is true. Cannot create remote catalog. In the inspector for any group, double click the 'Addressable Asset Settings' object to begin inspecting it. '" + + remoteBuildFolder + "', '" + remoteLoadFolder + "'"); + } + else + { + var remoteJsonBuildPath = remoteBuildFolder + versionedFileName + ".bin"; + var remoteHashBuildPath = remoteBuildFolder + versionedFileName + ".hash"; + + WriteFile(remoteJsonBuildPath, data, builderInput.Registry); + WriteFile(remoteHashBuildPath, contentHash, builderInput.Registry); + + dependencyHashes = new string[((int)ContentCatalogProvider.DependencyHashIndex.Count)]; + dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Remote] = ResourceManagerRuntimeData.kCatalogAddress + "RemoteHash"; + dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Cache] = ResourceManagerRuntimeData.kCatalogAddress + "CacheHash"; + + var remoteHashLoadPath = remoteLoadFolder + versionedFileName + ".hash"; + var remoteHashLoadLocation = new ResourceLocationData( + new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Remote] }, + remoteHashLoadPath, + typeof(TextDataProvider), typeof(string)); + remoteHashLoadLocation.Data = catalogLoadOptions.Copy(); + locations.Add(remoteHashLoadLocation); + +#if UNITY_SWITCH + var cacheLoadPath = remoteHashLoadPath; // ResourceLocationBase does not allow empty string id +#else + var cacheLoadPath = "{UnityEngine.Application.persistentDataPath}/com.unity.addressables" + versionedFileName + ".hash"; +#endif + var cacheLoadLocation = new ResourceLocationData( + new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Cache] }, + cacheLoadPath, + typeof(TextDataProvider), typeof(string)); + cacheLoadLocation.Data = catalogLoadOptions.Copy(); + locations.Add(cacheLoadLocation); + } + + return dependencyHashes; + } + + internal ReturnCode CreateCatalogBundle(string filepath, byte[] data, AddressablesDataBuilderInput builderInput) + { + if (string.IsNullOrEmpty(filepath) || data == null || data.Length == 0 || builderInput == null) + { + throw new ArgumentException("Unable to create catalog bundle (null arguments)."); + } + + // A bundle requires an actual asset + var tempFolderName = "TempCatalogFolder"; + + var configFolder = AddressableAssetSettingsDefaultObject.kDefaultConfigFolder; + if (builderInput.AddressableSettings != null && builderInput.AddressableSettings.IsPersisted) + configFolder = builderInput.AddressableSettings.ConfigFolder; + + var tempFolderPath = Path.Combine(configFolder, tempFolderName); + var tempFilePath = Path.Combine(tempFolderPath, Path.GetFileName(filepath).Replace(".bundle", ".bin")); + if (!WriteFile(tempFilePath, data, builderInput.Registry)) + { + throw new Exception("An error occured during the creation of temporary files needed to bundle the content catalog."); + } + + AssetDatabase.Refresh(); + + var bundleBuildContent = new BundleBuildContent(new[] + { + new AssetBundleBuild() + { + assetBundleName = Path.GetFileName(filepath), + assetNames = new[] {tempFilePath}, + addressableNames = new string[0] + } + }); + + var buildTasks = new List + { + new CalculateAssetDependencyData(), + new GenerateBundlePacking(), + new GenerateBundleCommands(), + new WriteSerializedFiles(), + new ArchiveAndCompressBundles() + }; + + var buildParams = new BundleBuildParameters(builderInput.Target, builderInput.TargetGroup, Path.GetDirectoryName(filepath)); + if (builderInput.Target == BuildTarget.WebGL) + buildParams.BundleCompression = BuildCompression.LZ4Runtime; + var retCode = ContentPipeline.BuildAssetBundles(buildParams, bundleBuildContent, out IBundleBuildResults result, buildTasks, m_Log); + + if (Directory.Exists(tempFolderPath)) + { + Directory.Delete(tempFolderPath, true); + builderInput.Registry.RemoveFile(tempFilePath); + } + + var tempFolderMetaFile = tempFolderPath + ".meta"; + if (File.Exists(tempFolderMetaFile)) + { + File.Delete(tempFolderMetaFile); + builderInput.Registry.RemoveFile(tempFolderMetaFile); + } + + if (File.Exists(filepath)) + { + builderInput.Registry.AddFile(filepath); + } + + return retCode; + } + +#else + internal bool CreateCatalogFiles(string jsonText, AddressablesDataBuilderInput builderInput, AddressableAssetsBuildContext aaContext, string catalogHash = null) + { + if (string.IsNullOrEmpty(jsonText) || builderInput == null || aaContext == null) + { + Addressables.LogError("Unable to create content catalog (Null arguments)."); + return false; + } + + // Path needs to be resolved at runtime. + string localLoadPath = "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/" + builderInput.RuntimeCatalogFilename; + m_CatalogBuildPath = Path.Combine(Addressables.BuildPath, builderInput.RuntimeCatalogFilename); + + if (aaContext.Settings.BundleLocalCatalog) + { + localLoadPath = localLoadPath.Replace(".json", ".bundle"); + m_CatalogBuildPath = m_CatalogBuildPath.Replace(".json", ".bundle"); + var returnCode = CreateCatalogBundle(m_CatalogBuildPath, jsonText, builderInput); + if (returnCode != ReturnCode.Success || !File.Exists(m_CatalogBuildPath)) + { + Addressables.LogError($"An error occured during the creation of the content catalog bundle (return code {returnCode})."); + return false; + } + } + else + { + WriteFile(m_CatalogBuildPath, jsonText, builderInput.Registry); + } + + string[] dependencyHashes = null; + if (aaContext.Settings.BuildRemoteCatalog) + { + dependencyHashes = CreateRemoteCatalog(jsonText, aaContext.runtimeData.CatalogLocations, aaContext.Settings, builderInput, new ProviderLoadRequestOptions() {IgnoreFailures = true}, catalogHash); + } + + ResourceLocationData localCatalog = new ResourceLocationData( + new[] {ResourceManagerRuntimeData.kCatalogAddress}, + localLoadPath, + typeof(ContentCatalogProvider), + typeof(ContentCatalogData), + dependencyHashes); + //We need to set the data here because this location data gets used later if we decide to load the remote/cached catalog instead. See DetermineIdToLoad(...) + localCatalog.Data = new ProviderLoadRequestOptions() { IgnoreFailures = true }; + + aaContext.runtimeData.CatalogLocations.Add(localCatalog); + + return true; + } + + internal ReturnCode CreateCatalogBundle(string filepath, string jsonText, AddressablesDataBuilderInput builderInput) + { + if (string.IsNullOrEmpty(filepath) || string.IsNullOrEmpty(jsonText) || builderInput == null) + { + throw new ArgumentException("Unable to create catalog bundle (null arguments)."); + } + + // A bundle requires an actual asset + var tempFolderName = "TempCatalogFolder"; + + var configFolder = AddressableAssetSettingsDefaultObject.kDefaultConfigFolder; + if (builderInput.AddressableSettings != null && builderInput.AddressableSettings.IsPersisted) + configFolder = builderInput.AddressableSettings.ConfigFolder; + + var tempFolderPath = Path.Combine(configFolder, tempFolderName); + var tempFilePath = Path.Combine(tempFolderPath, Path.GetFileName(filepath).Replace(".bundle", ".json")); + if (!WriteFile(tempFilePath, jsonText, builderInput.Registry)) + { + throw new Exception("An error occured during the creation of temporary files needed to bundle the content catalog."); + } + + AssetDatabase.Refresh(); + + var bundleBuildContent = new BundleBuildContent(new[] + { + new AssetBundleBuild() + { + assetBundleName = Path.GetFileName(filepath), + assetNames = new[] {tempFilePath}, + addressableNames = new string[0] + } + }); + + var buildTasks = new List + { + new CalculateAssetDependencyData(), + new GenerateBundlePacking(), + new GenerateBundleCommands(), + new WriteSerializedFiles(), + new ArchiveAndCompressBundles() + }; + + var buildParams = new BundleBuildParameters(builderInput.Target, builderInput.TargetGroup, Path.GetDirectoryName(filepath)); + if (builderInput.Target == BuildTarget.WebGL) + buildParams.BundleCompression = BuildCompression.LZ4Runtime; + var retCode = ContentPipeline.BuildAssetBundles(buildParams, bundleBuildContent, out IBundleBuildResults result, buildTasks, m_Log); + + if (Directory.Exists(tempFolderPath)) + { + Directory.Delete(tempFolderPath, true); + builderInput.Registry.RemoveFile(tempFilePath); + } + + var tempFolderMetaFile = tempFolderPath + ".meta"; + if (File.Exists(tempFolderMetaFile)) + { + File.Delete(tempFolderMetaFile); + builderInput.Registry.RemoveFile(tempFolderMetaFile); + } + + if (File.Exists(filepath)) + { + builderInput.Registry.AddFile(filepath); + } + + return retCode; + } + + + static string[] CreateRemoteCatalog(string jsonText, List locations, AddressableAssetSettings aaSettings, AddressablesDataBuilderInput builderInput, + ProviderLoadRequestOptions catalogLoadOptions, string contentHash) + { + string[] dependencyHashes = null; + + if (string.IsNullOrEmpty(contentHash)) + contentHash = HashingMethods.Calculate(jsonText).ToString(); + + var versionedFileName = aaSettings.profileSettings.EvaluateString(aaSettings.activeProfileId, "/catalog_" + builderInput.PlayerVersion); + var remoteBuildFolder = aaSettings.RemoteCatalogBuildPath.GetValue(aaSettings); + var remoteLoadFolder = aaSettings.RemoteCatalogLoadPath.GetValue(aaSettings); + + if (string.IsNullOrEmpty(remoteBuildFolder) || + string.IsNullOrEmpty(remoteLoadFolder) || + remoteBuildFolder == AddressableAssetProfileSettings.undefinedEntryValue || + remoteLoadFolder == AddressableAssetProfileSettings.undefinedEntryValue) + { + Addressables.LogWarning( + "Remote Build and/or Load paths are not set on the main AddressableAssetSettings asset, but 'Build Remote Catalog' is true. Cannot create remote catalog. In the inspector for any group, double click the 'Addressable Asset Settings' object to begin inspecting it. '" + + remoteBuildFolder + "', '" + remoteLoadFolder + "'"); + } + else + { + var remoteJsonBuildPath = remoteBuildFolder + versionedFileName + ".json"; + var remoteHashBuildPath = remoteBuildFolder + versionedFileName + ".hash"; + + WriteFile(remoteJsonBuildPath, jsonText, builderInput.Registry); + WriteFile(remoteHashBuildPath, contentHash, builderInput.Registry); + + dependencyHashes = new string[((int)ContentCatalogProvider.DependencyHashIndex.Count)]; + dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Remote] = ResourceManagerRuntimeData.kCatalogAddress + "RemoteHash"; + dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Cache] = ResourceManagerRuntimeData.kCatalogAddress + "CacheHash"; + + var remoteHashLoadPath = remoteLoadFolder + versionedFileName + ".hash"; + var remoteHashLoadLocation = new ResourceLocationData( + new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Remote] }, + remoteHashLoadPath, + typeof(TextDataProvider), typeof(string)); + remoteHashLoadLocation.Data = catalogLoadOptions.Copy(); + locations.Add(remoteHashLoadLocation); + +#if UNITY_SWITCH + var cacheLoadPath = remoteHashLoadPath; // ResourceLocationBase does not allow empty string id +#else + var cacheLoadPath = "{UnityEngine.Application.persistentDataPath}/com.unity.addressables" + versionedFileName + ".hash"; +#endif + var cacheLoadLocation = new ResourceLocationData( + new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Cache] }, + cacheLoadPath, + typeof(TextDataProvider), typeof(string)); + cacheLoadLocation.Data = catalogLoadOptions.Copy(); + locations.Add(cacheLoadLocation); + } + + return dependencyHashes; + } + +#endif + internal static string GetProjectName() + { + return new DirectoryInfo(Path.GetDirectoryName(Application.dataPath)).Name; + } + + internal static void SetAssetEntriesBundleFileIdToCatalogEntryBundleFileId(ICollection assetEntries, Dictionary bundleNameToInternalBundleIdMap, + IBundleWriteData writeData, Dictionary locationIdToCatalogEntryMap) + { + foreach (var loc in assetEntries) + { + AddressableAssetEntry processedEntry = loc; + if (loc.IsFolder && loc.SubAssets.Count > 0) + processedEntry = loc.SubAssets[0]; + GUID guid = new GUID(processedEntry.guid); + //For every entry in the write data we need to ensure the BundleFileId is set so we can save it correctly in the cached state + if (writeData.AssetToFiles.TryGetValue(guid, out List files)) + { + string file = files[0]; + string fullBundleName = writeData.FileToBundle[file]; + string convertedLocation; + + if (!bundleNameToInternalBundleIdMap.TryGetValue(fullBundleName, out convertedLocation)) + { + Debug.LogException(new Exception($"Unable to find bundleId for key: {fullBundleName}.")); + } + + if (locationIdToCatalogEntryMap.TryGetValue(convertedLocation, + out ContentCatalogDataEntry catalogEntry)) + { + loc.BundleFileId = catalogEntry.InternalId; + + //This is where we strip out the temporary hash added to the bundle name for Content Update for the AssetEntry + if (loc.parentGroup?.GetSchema()?.BundleNaming == + BundledAssetGroupSchema.BundleNamingStyle.NoHash) + { + loc.BundleFileId = StripHashFromBundleLocation(loc.BundleFileId); + } + } + } + } + } + + static string StripHashFromBundleLocation(string hashedBundleLocation) + { + return hashedBundleLocation.Remove(hashedBundleLocation.LastIndexOf('_')) + ".bundle"; + } + + /// + protected override string ProcessGroup(AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext) + { + if (assetGroup == null) + return string.Empty; + + if (assetGroup.Schemas.Count == 0) + { + Addressables.LogWarning($"{assetGroup.Name} does not have any associated AddressableAssetGroupSchemas. " + + $"Data from this group will not be included in the build. " + + $"If this is unexpected the AddressableGroup may have become corrupted."); + return string.Empty; + } + + foreach (var schema in assetGroup.Schemas) + { + var errorString = ProcessGroupSchema(schema, assetGroup, aaContext); + if (!string.IsNullOrEmpty(errorString)) + return errorString; + } + + return string.Empty; + } + + /// + /// Called per group per schema to evaluate that schema. This can be an easy entry point for implementing the + /// build aspects surrounding a custom schema. Note, you should not rely on schemas getting called in a specific + /// order. + /// + /// The schema to process + /// The group this schema was pulled from + /// The general Addressables build builderInput + /// + protected virtual string ProcessGroupSchema(AddressableAssetGroupSchema schema, AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext) + { + var playerDataSchema = schema as PlayerDataGroupSchema; + if (playerDataSchema != null) + return ProcessPlayerDataSchema(playerDataSchema, assetGroup, aaContext); + var bundledAssetSchema = schema as BundledAssetGroupSchema; + if (bundledAssetSchema != null) + return ProcessBundledAssetSchema(bundledAssetSchema, assetGroup, aaContext); + return string.Empty; + } + + internal string ProcessPlayerDataSchema( + PlayerDataGroupSchema schema, + AddressableAssetGroup assetGroup, + AddressableAssetsBuildContext aaContext) + { + if (CreateLocationsForPlayerData(schema, assetGroup, aaContext.locations, aaContext.providerTypes)) + { + if (!m_CreatedProviderIds.Contains(typeof(LegacyResourcesProvider).Name)) + { + m_CreatedProviderIds.Add(typeof(LegacyResourcesProvider).Name); + m_ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(typeof(LegacyResourcesProvider))); + } + } + + return string.Empty; + } + + /// + /// A temporary list of the groups that get processed during a build. + /// + List m_IncludedGroupsInBuild = new List(); + + /// + /// The processing of the bundled asset schema. This is where the bundle(s) for a given group are actually setup. + /// + /// The BundledAssetGroupSchema to process + /// The group this schema was pulled from + /// The general Addressables build builderInput + /// The error string, if any. + protected virtual string ProcessBundledAssetSchema( + BundledAssetGroupSchema schema, + AddressableAssetGroup assetGroup, + AddressableAssetsBuildContext aaContext) + { + if (schema == null || !schema.IncludeInBuild || !assetGroup.entries.Any()) + return string.Empty; + + var errorStr = ErrorCheckBundleSettings(schema, assetGroup, aaContext.Settings); + if (!string.IsNullOrEmpty(errorStr)) + return errorStr; + + m_IncludedGroupsInBuild?.Add(assetGroup); + + AddBundleProvider(schema); + + var assetProviderId = schema.GetAssetCachedProviderId(); + if (!m_CreatedProviderIds.Contains(assetProviderId)) + { + m_CreatedProviderIds.Add(assetProviderId); + var assetProviderType = schema.BundledAssetProviderType.Value; + var assetProviderData = ObjectInitializationData.CreateSerializedInitializationData(assetProviderType, assetProviderId); + m_ResourceProviderData.Add(assetProviderData); + } + +#if UNITY_2022_1_OR_NEWER + string loadPath = schema.LoadPath.GetValue(aaContext.Settings); + if (loadPath.StartsWith("http://", StringComparison.Ordinal) && PlayerSettings.insecureHttpOption == InsecureHttpOption.NotAllowed) + Addressables.LogWarning($"Addressable group {assetGroup.Name} uses insecure http for its load path. To allow http connections for UnityWebRequests, change your settings in Edit > Project Settings > Player > Other Settings > Configuration > Allow downloads over HTTP."); +#endif + if (schema.Compression == BundledAssetGroupSchema.BundleCompressionMode.LZMA && aaContext.runtimeData.BuildTarget == BuildTarget.WebGL.ToString()) + Addressables.LogWarning($"Addressable group {assetGroup.Name} uses LZMA compression, which cannot be decompressed on WebGL. Use LZ4 compression instead."); + + var bundleInputDefs = new List(); + var list = PrepGroupBundlePacking(assetGroup, bundleInputDefs, schema); + aaContext.assetEntries.AddRange(list); + List uniqueNames = HandleBundleNames(bundleInputDefs, aaContext.bundleToAssetGroup, assetGroup.Guid); + (string, string)[] groupBundles = new (string, string)[uniqueNames.Count]; + for (int i = 0; i < uniqueNames.Count; ++i) + groupBundles[i] = (bundleInputDefs[i].assetBundleName, uniqueNames[i]); + m_GroupToBundleNames.Add(assetGroup, groupBundles); + m_AllBundleInputDefs.AddRange(bundleInputDefs); + return string.Empty; + } + + internal static List HandleBundleNames(List bundleInputDefs, Dictionary bundleToAssetGroup = null, string assetGroupGuid = null) + { + var generatedUniqueNames = new List(); + var handledNames = new HashSet(); + + for (int i = 0; i < bundleInputDefs.Count; i++) + { + AssetBundleBuild bundleBuild = bundleInputDefs[i]; + string assetBundleName = bundleBuild.assetBundleName; + if (handledNames.Contains(assetBundleName)) + { + int count = 1; + var newName = assetBundleName; + while (handledNames.Contains(newName) && count < 1000) + newName = assetBundleName.Replace(".bundle", string.Format("{0}.bundle", count++)); + assetBundleName = newName; + } + + string hashedAssetBundleName = HashingMethods.Calculate(assetBundleName) + ".bundle"; + generatedUniqueNames.Add(assetBundleName); + handledNames.Add(assetBundleName); + + bundleBuild.assetBundleName = hashedAssetBundleName; + bundleInputDefs[i] = bundleBuild; + + if (bundleToAssetGroup != null) + bundleToAssetGroup.Add(hashedAssetBundleName, assetGroupGuid); + } + + return generatedUniqueNames; + } + + internal static string ErrorCheckBundleSettings(BundledAssetGroupSchema schema, AddressableAssetGroup assetGroup, AddressableAssetSettings settings) + { + var message = string.Empty; + + string buildPath = settings.profileSettings.GetValueById(settings.activeProfileId, schema.BuildPath.Id); + string loadPath = settings.profileSettings.GetValueById(settings.activeProfileId, schema.LoadPath.Id); + + bool buildLocal = AddressableAssetUtility.StringContains(buildPath, "[UnityEngine.AddressableAssets.Addressables.BuildPath]", StringComparison.Ordinal); + bool loadLocal = AddressableAssetUtility.StringContains(loadPath, "{UnityEngine.AddressableAssets.Addressables.RuntimePath}", StringComparison.Ordinal); + + if (buildLocal && !loadLocal) + { + message = "BuildPath for group '" + assetGroup.Name + "' is set to the dynamic-lookup version of StreamingAssets, but LoadPath is not. \n"; + } + else if (!buildLocal && loadLocal) + { + message = "LoadPath for group " + assetGroup.Name + + " is set to the dynamic-lookup version of StreamingAssets, but BuildPath is not. These paths must both use the dynamic-lookup, or both not use it. \n"; + } + + if (!string.IsNullOrEmpty(message)) + { + message += "BuildPath: '" + buildPath + "'\n"; + message += "LoadPath: '" + loadPath + "'"; + } + + if (schema.Compression == BundledAssetGroupSchema.BundleCompressionMode.LZMA && (buildLocal || loadLocal)) + { + Debug.LogWarningFormat("Bundle compression is set to LZMA, but group {0} uses local content.", assetGroup.Name); + } + + return message; + } + + internal static string CalculateGroupHash(BundledAssetGroupSchema.BundleInternalIdMode mode, AddressableAssetGroup assetGroup, IEnumerable entries) + { + switch (mode) + { + case BundledAssetGroupSchema.BundleInternalIdMode.GroupGuid: return assetGroup.Guid; + case BundledAssetGroupSchema.BundleInternalIdMode.GroupGuidProjectIdHash: return HashingMethods.Calculate(assetGroup.Guid, Application.cloudProjectId).ToString(); + case BundledAssetGroupSchema.BundleInternalIdMode.GroupGuidProjectIdEntriesHash: + return HashingMethods.Calculate(assetGroup.Guid, Application.cloudProjectId, new HashSet(entries.Select(e => e.guid))).ToString(); + } + + throw new Exception("Invalid naming mode."); + } + + /// + /// Processes an AddressableAssetGroup and generates AssetBundle input definitions based on the BundlePackingMode. + /// + /// The AddressableAssetGroup to be processed. + /// The list of bundle definitions fed into the build pipeline AssetBundleBuild + /// The BundledAssetGroupSchema of used to process the assetGroup. + /// A filter to remove AddressableAssetEntries from being processed in the build. + /// The total list of AddressableAssetEntries that were processed. + public static List PrepGroupBundlePacking(AddressableAssetGroup assetGroup, List bundleInputDefs, BundledAssetGroupSchema schema, + Func entryFilter = null) + { + var combinedEntries = new List(); + var packingMode = schema.BundleMode; + var namingMode = schema.InternalBundleIdMode; + bool ignoreUnsupportedFilesInBuild = assetGroup.Settings.IgnoreUnsupportedFilesInBuild; + + switch (packingMode) + { + case BundledAssetGroupSchema.BundlePackingMode.PackTogether: + { + var allEntries = new List(); + foreach (AddressableAssetEntry a in assetGroup.entries) + { + if (entryFilter != null && !entryFilter(a)) + continue; + a.GatherAllAssets(allEntries, true, true, false, entryFilter); + } + + combinedEntries.AddRange(allEntries); + GenerateBuildInputDefinitions(allEntries, bundleInputDefs, CalculateGroupHash(namingMode, assetGroup, allEntries), "all", ignoreUnsupportedFilesInBuild); + } + break; + case BundledAssetGroupSchema.BundlePackingMode.PackSeparately: + { + foreach (AddressableAssetEntry a in assetGroup.entries) + { + if (entryFilter != null && !entryFilter(a)) + continue; + var allEntries = new List(); + a.GatherAllAssets(allEntries, true, true, false, entryFilter); + combinedEntries.AddRange(allEntries); + GenerateBuildInputDefinitions(allEntries, bundleInputDefs, CalculateGroupHash(namingMode, assetGroup, allEntries), a.address, ignoreUnsupportedFilesInBuild); + } + } + break; + case BundledAssetGroupSchema.BundlePackingMode.PackTogetherByLabel: + { + var labelTable = new Dictionary>(); + foreach (AddressableAssetEntry a in assetGroup.entries) + { + if (entryFilter != null && !entryFilter(a)) + continue; + var sb = new StringBuilder(); + foreach (var l in a.labels) + sb.Append(l); + var key = sb.ToString(); + List entries; + if (!labelTable.TryGetValue(key, out entries)) + labelTable.Add(key, entries = new List()); + entries.Add(a); + } + + foreach (var entryGroup in labelTable) + { + var allEntries = new List(); + foreach (var a in entryGroup.Value) + { + if (entryFilter != null && !entryFilter(a)) + continue; + a.GatherAllAssets(allEntries, true, true, false, entryFilter); + } + + combinedEntries.AddRange(allEntries); + GenerateBuildInputDefinitions(allEntries, bundleInputDefs, CalculateGroupHash(namingMode, assetGroup, allEntries), entryGroup.Key, ignoreUnsupportedFilesInBuild); + } + } + break; + default: + throw new Exception("Unknown Packing Mode"); + } + + return combinedEntries; + } + + internal static void GenerateBuildInputDefinitions(List allEntries, List buildInputDefs, string groupGuid, string address, + bool ignoreUnsupportedFilesInBuild) + { + var scenes = new List(); + var assets = new List(); + foreach (var e in allEntries) + { + ThrowExceptionIfInvalidFiletypeOrAddress(e, ignoreUnsupportedFilesInBuild); + if (string.IsNullOrEmpty(e.AssetPath)) + continue; + if (e.IsScene) + scenes.Add(e); + else + assets.Add(e); + } + + if (assets.Count > 0) + buildInputDefs.Add(GenerateBuildInputDefinition(assets, groupGuid + "_assets_" + address + ".bundle")); + if (scenes.Count > 0) + buildInputDefs.Add(GenerateBuildInputDefinition(scenes, groupGuid + "_scenes_" + address + ".bundle")); + } + + private static void ThrowExceptionIfInvalidFiletypeOrAddress(AddressableAssetEntry entry, bool ignoreUnsupportedFilesInBuild) + { + if (entry.guid.Length > 0 && entry.address.Contains('[') && entry.address.Contains(']')) + throw new Exception($"Address '{entry.address}' cannot contain '[ ]'."); + if (entry.MainAssetType == typeof(DefaultAsset) && !AssetDatabase.IsValidFolder(entry.AssetPath)) + { + if (ignoreUnsupportedFilesInBuild) + Debug.LogWarning($"Cannot recognize file type for entry located at '{entry.AssetPath}'. Asset location will be ignored."); + else + throw new Exception($"Cannot recognize file type for entry located at '{entry.AssetPath}'. Asset import failed for using an unsupported file type."); + } + } + + internal static AssetBundleBuild GenerateBuildInputDefinition(List assets, string name) + { + var assetInternalIds = new HashSet(); + var assetsInputDef = new AssetBundleBuild(); + assetsInputDef.assetBundleName = name.ToLower().Replace(" ", "").Replace('\\', '/').Replace("//", "/"); + assetsInputDef.assetNames = assets.Select(s => s.AssetPath).ToArray(); + assetsInputDef.addressableNames = assets.Select(s => s.GetAssetLoadPath(true, assetInternalIds)).ToArray(); + return assetsInputDef; + } + + + // Tests can set this flag to prevent player script compilation. This is the most expensive part of small builds + // and isn't needed for most tests. + internal static bool s_SkipCompilePlayerScripts = false; + + static IList RuntimeDataBuildTasks(string builtinShaderBundleName, string monoScriptBundleName) + { + var buildTasks = new List(); + + // Setup + buildTasks.Add(new SwitchToBuildPlatform()); + buildTasks.Add(new RebuildSpriteAtlasCache()); + + // Player Scripts + if (!s_SkipCompilePlayerScripts) + buildTasks.Add(new BuildPlayerScripts()); + buildTasks.Add(new PostScriptsCallback()); + + // Dependency + buildTasks.Add(new CalculateSceneDependencyData()); + buildTasks.Add(new CalculateAssetDependencyData()); + buildTasks.Add(new AddHashToBundleNameTask()); + buildTasks.Add(new StripUnusedSpriteSources()); + buildTasks.Add(new CreateBuiltInShadersBundle(builtinShaderBundleName)); + if (!string.IsNullOrEmpty(monoScriptBundleName)) + buildTasks.Add(new CreateMonoScriptBundle(monoScriptBundleName)); + buildTasks.Add(new PostDependencyCallback()); + + // Packing + buildTasks.Add(new GenerateBundlePacking()); + buildTasks.Add(new UpdateBundleObjectLayout()); + buildTasks.Add(new GenerateBundleCommands()); + buildTasks.Add(new GenerateSubAssetPathMaps()); + buildTasks.Add(new GenerateBundleMaps()); + buildTasks.Add(new PostPackingCallback()); + + // Writing + buildTasks.Add(new WriteSerializedFiles()); + buildTasks.Add(new ArchiveAndCompressBundles()); + buildTasks.Add(new GenerateLocationListsTask()); + buildTasks.Add(new PostWritingCallback()); + + return buildTasks; + } + + static void MoveFileToDestinationWithTimestampIfDifferent(string srcPath, string destPath, IBuildLogger log) + { + if (srcPath == destPath) + return; + + DateTime time = File.GetLastWriteTime(srcPath); + DateTime destTime = File.Exists(destPath) ? File.GetLastWriteTime(destPath) : new DateTime(); + + if (destTime == time) + return; + + using (log.ScopedStep(LogLevel.Verbose, "Move File", $"{srcPath} -> {destPath}")) + { + var directory = Path.GetDirectoryName(destPath); + if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) + Directory.CreateDirectory(directory); + else if (File.Exists(destPath)) + File.Delete(destPath); + File.Move(srcPath, destPath); + } + } + + void PostProcessBundles(AddressableAssetGroup assetGroup, IBundleBuildResults buildResult, AddressablesPlayerBuildResult addrResult, FileRegistry registry, + AddressableAssetsBuildContext aaContext, Dictionary bundleRenameMap, List postCatalogUpdateCallbacks) + { + var schema = assetGroup.GetSchema(); + if (schema == null) + return; + + var path = schema.BuildPath.GetValue(assetGroup.Settings); + if (string.IsNullOrEmpty(path)) + return; + + List builtBundleNames = aaContext.assetGroupToBundles[assetGroup]; + List outputBundleNames = null; + + if (m_GroupToBundleNames.TryGetValue(assetGroup, out (string,string)[] bundleValues)) + { + outputBundleNames = new List(builtBundleNames.Count); + for (int i = 0; i < builtBundleNames.Count; ++i) + { + string outputName = null; + foreach ((string, string) bundleValue in bundleValues) + { + if (schema.BundleMode == BundledAssetGroupSchema.BundlePackingMode.PackSeparately) + { + if (builtBundleNames[i].StartsWith(bundleValue.Item1, StringComparison.Ordinal)) + outputName = bundleValue.Item2; + } + else if (builtBundleNames[i].Equals(bundleValue.Item1, StringComparison.Ordinal)) + outputName = bundleValue.Item2; + + if (outputName != null) + break; + } + outputBundleNames.Add(string.IsNullOrEmpty(outputName) ? builtBundleNames[i] : outputName); + } + } + else + { + outputBundleNames = new List(builtBundleNames); + } + + for (int i = 0; i < builtBundleNames.Count; ++i) + { + AddressablesPlayerBuildResult.BundleBuildResult bundleResultInfo = new AddressablesPlayerBuildResult.BundleBuildResult(); + bundleResultInfo.SourceAssetGroup = assetGroup; + + if (aaContext.PrimaryKeyToLocation.TryGetValue(builtBundleNames[i], out ContentCatalogDataEntry dataEntry)) + { + var info = buildResult.BundleInfos[builtBundleNames[i]]; + bundleResultInfo.Crc = info.Crc; + bundleResultInfo.Hash = info.Hash.ToString(); + var requestOptions = new AssetBundleRequestOptions + { + Crc = schema.UseAssetBundleCrc ? info.Crc : 0, + UseCrcForCachedBundle = schema.UseAssetBundleCrcForCachedBundles, + UseUnityWebRequestForLocalBundles = schema.UseUnityWebRequestForLocalBundles, + Hash = schema.UseAssetBundleCache ? info.Hash.ToString() : "", + ChunkedTransfer = schema.ChunkedTransfer, + RedirectLimit = schema.RedirectLimit, + RetryCount = schema.RetryCount, + Timeout = schema.Timeout, + BundleName = Path.GetFileNameWithoutExtension(info.FileName), + AssetLoadMode = schema.AssetLoadMode, + BundleSize = GetFileSize(info.FileName), + ClearOtherCachedVersionsWhenLoaded = schema.AssetBundledCacheClearBehavior == BundledAssetGroupSchema.CacheClearBehavior.ClearWhenWhenNewVersionLoaded + }; + dataEntry.Data = requestOptions; + bundleResultInfo.InternalBundleName = requestOptions.BundleName; + + if (assetGroup == assetGroup.Settings.DefaultGroup && info.Dependencies.Length == 0 && !string.IsNullOrEmpty(info.FileName) && + (info.FileName.EndsWith("_unitybuiltinshaders.bundle", StringComparison.Ordinal) || info.FileName.EndsWith("_monoscripts.bundle", StringComparison.Ordinal))) + { + outputBundleNames[i] = ConstructAssetBundleName(null, schema, info, outputBundleNames[i]); + } + else + { + int extensionLength = Path.GetExtension(outputBundleNames[i]).Length; + string[] deconstructedBundleName = outputBundleNames[i].Substring(0, outputBundleNames[i].Length - extensionLength).Split('_'); + string reconstructedBundleName = string.Join("_", deconstructedBundleName, 1, deconstructedBundleName.Length - 1) + ".bundle"; + outputBundleNames[i] = ConstructAssetBundleName(assetGroup, schema, info, reconstructedBundleName); + } + + dataEntry.InternalId = dataEntry.InternalId.Remove(dataEntry.InternalId.Length - builtBundleNames[i].Length) + outputBundleNames[i]; + SetPrimaryKey(dataEntry, outputBundleNames[i], aaContext); + + if (!m_BundleToInternalId.ContainsKey(builtBundleNames[i])) + m_BundleToInternalId.Add(builtBundleNames[i], dataEntry.InternalId); + + if (dataEntry.InternalId.StartsWith("http:\\", StringComparison.Ordinal)) + dataEntry.InternalId = dataEntry.InternalId.Replace("http:\\", "http://").Replace("\\", "/"); + else if (dataEntry.InternalId.StartsWith("https:\\", StringComparison.Ordinal)) + dataEntry.InternalId = dataEntry.InternalId.Replace("https:\\", "https://").Replace("\\", "/"); + } + else + { + Debug.LogWarningFormat("Unable to find ContentCatalogDataEntry for bundle {0}.", outputBundleNames[i]); + } + + var targetPath = Path.Combine(path, outputBundleNames[i]); + bundleResultInfo.FilePath = targetPath; + var srcPath = Path.Combine(assetGroup.Settings.buildSettings.bundleBuildPath, builtBundleNames[i]); + + if (assetGroup.GetSchema()?.BundleNaming == BundledAssetGroupSchema.BundleNamingStyle.NoHash) + outputBundleNames[i] = StripHashFromBundleLocation(outputBundleNames[i]); + + bundleRenameMap.Add(builtBundleNames[i], outputBundleNames[i]); + MoveFileToDestinationWithTimestampIfDifferent(srcPath, targetPath, m_Log); + AddPostCatalogUpdatesInternal(assetGroup, postCatalogUpdateCallbacks, dataEntry, targetPath, registry); + + if (addrResult != null) + addrResult.AssetBundleBuildResults.Add(bundleResultInfo); + + registry.AddFile(targetPath); + } + } + + internal void AddPostCatalogUpdatesInternal(AddressableAssetGroup assetGroup, List postCatalogUpdates, ContentCatalogDataEntry dataEntry, string targetBundlePath, + FileRegistry registry) + { + if (assetGroup.GetSchema()?.BundleNaming == + BundledAssetGroupSchema.BundleNamingStyle.NoHash) + { + postCatalogUpdates.Add(() => + { + //This is where we strip out the temporary hash for the final bundle location and filename + string bundlePathWithoutHash = StripHashFromBundleLocation(targetBundlePath); + if (File.Exists(targetBundlePath)) + { + if (File.Exists(bundlePathWithoutHash)) + File.Delete(bundlePathWithoutHash); + string destFolder = Path.GetDirectoryName(bundlePathWithoutHash); + if (!string.IsNullOrEmpty(destFolder) && !Directory.Exists(destFolder)) + Directory.CreateDirectory(destFolder); + + File.Move(targetBundlePath, bundlePathWithoutHash); + } + + if (registry != null) + { + if (!registry.ReplaceBundleEntry(targetBundlePath, bundlePathWithoutHash)) + Debug.LogErrorFormat("Unable to find registered file for bundle {0}.", targetBundlePath); + } + + if (dataEntry != null) + if (DataEntryDiffersFromBundleFilename(dataEntry, bundlePathWithoutHash)) + dataEntry.InternalId = StripHashFromBundleLocation(dataEntry.InternalId); + }); + } + } + + // if false, there is no need to remove the hash from dataEntry.InternalId + bool DataEntryDiffersFromBundleFilename(ContentCatalogDataEntry dataEntry, string bundlePathWithoutHash) + { + string dataEntryId = dataEntry.InternalId; + string dataEntryFilename = Path.GetFileName(dataEntryId); + string bundleFileName = Path.GetFileName(bundlePathWithoutHash); + + return dataEntryFilename != bundleFileName; + } + + /// + /// Creates a name for an asset bundle using the provided information. + /// + /// The asset group. + /// The schema of the group. + /// The bundle information. + /// The base name of the asset bundle. + /// Returns the asset bundle name with the provided information. + protected virtual string ConstructAssetBundleName(AddressableAssetGroup assetGroup, BundledAssetGroupSchema schema, BundleDetails info, string assetBundleName) + { + if (assetGroup != null) + { + string groupName = assetGroup.Name.Replace(" ", "").Replace('\\', '/').Replace("//", "/").ToLower(); + assetBundleName = groupName + "_" + assetBundleName; + } + + string bundleNameWithHashing = BuildUtility.GetNameWithHashNaming(schema.BundleNaming, info.Hash.ToString(), assetBundleName); + //For no hash, we need the hash temporarily for content update purposes. This will be stripped later on. + if (schema.BundleNaming == BundledAssetGroupSchema.BundleNamingStyle.NoHash) + { + bundleNameWithHashing = bundleNameWithHashing.Replace(".bundle", "_" + info.Hash.ToString() + ".bundle"); + } + + return bundleNameWithHashing; + } + + /// + /// Sets the primary key of the given location. Syncing with other locations that have a dependency on this location + /// + /// CatalogEntry to set the primary key for + /// New Primary key to set on location + /// Addressables build context to collect and assign other location data + /// + private void SetPrimaryKey(ContentCatalogDataEntry forLocation, string newPrimaryKey, AddressableAssetsBuildContext aaContext) + { + if (forLocation == null || forLocation.Keys == null || forLocation.Keys.Count == 0) + throw new ArgumentException("Cannot change primary key. Invalid catalog entry"); + + string originalKey = forLocation.Keys[0] as string; + if (string.IsNullOrEmpty(originalKey)) + throw new ArgumentException("Invalid primary key for catalog entry " + forLocation.ToString()); + + forLocation.Keys[0] = newPrimaryKey; + aaContext.PrimaryKeyToLocation.Remove(originalKey); + aaContext.PrimaryKeyToLocation.Add(newPrimaryKey, forLocation); + + if (!aaContext.PrimaryKeyToDependerLocations.TryGetValue(originalKey, out var dependers)) + return; // nothing depends on it + + foreach (ContentCatalogDataEntry location in dependers) + { + for (int i = 0; i < location.Dependencies.Count; ++i) + { + string keyString = location.Dependencies[i] as string; + if (string.IsNullOrEmpty(keyString)) + continue; + if (keyString == originalKey) + { + location.Dependencies[i] = newPrimaryKey; + break; + } + } + } + + aaContext.PrimaryKeyToDependerLocations.Remove(originalKey); + aaContext.PrimaryKeyToDependerLocations.Add(newPrimaryKey, dependers); + } + + private static long GetFileSize(string fileName) + { + try + { + return new FileInfo(fileName).Length; + } + catch (Exception e) + { + Debug.LogException(e); + return 0; + } + } + + /// + public override void ClearCachedData() + { + if (Directory.Exists(Addressables.BuildPath)) + { + try + { +#if ENABLE_BINARY_CATALOG + var catalogPath = Addressables.BuildPath + "/catalog.bin"; + DeleteFile(catalogPath); +#else + var catalogPath = Addressables.BuildPath + "/catalog.json"; + DeleteFile(catalogPath); +#endif + var settingsPath = Addressables.BuildPath + "/settings.json"; + DeleteFile(settingsPath); + Directory.Delete(Addressables.BuildPath, true); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + } + + /// + public override bool IsDataBuilt() + { + var settingsPath = Addressables.BuildPath + "/settings.json"; + return !String.IsNullOrEmpty(m_CatalogBuildPath) && + File.Exists(m_CatalogBuildPath) && + File.Exists(settingsPath); + } + } +} diff --git a/Editor/Build/DataBuilders/BuildScriptPackedMode.cs.meta b/Editor/Build/DataBuilders/BuildScriptPackedMode.cs.meta index 07456613..e21795b3 100644 --- a/Editor/Build/DataBuilders/BuildScriptPackedMode.cs.meta +++ b/Editor/Build/DataBuilders/BuildScriptPackedMode.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 3e2e0ffa088c91d41a086d0b8cb16bdc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 3e2e0ffa088c91d41a086d0b8cb16bdc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs b/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs index 4837de7b..8405227c 100644 --- a/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs +++ b/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs @@ -1,94 +1,94 @@ -using System; -using System.IO; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.AddressableAssets.Initialization; - -namespace UnityEditor.AddressableAssets.Build.DataBuilders -{ - /// - /// Uses data built by BuildScriptPacked class. This script just sets up the correct variables and runs. - /// - [CreateAssetMenu(fileName = "BuildScriptPackedPlayMode.asset", menuName = "Addressables/Content Builders/Use Existing Build (requires built groups)")] - public class BuildScriptPackedPlayMode : BuildScriptBase - { - /// - public override string Name - { - get { return "Use Existing Build (requires built groups)"; } - } - - private bool m_DataBuilt; - - /// - public override void ClearCachedData() - { - m_DataBuilt = false; - } - - /// - public override bool IsDataBuilt() - { - return m_DataBuilt; - } - - /// - public override bool CanBuildData() - { - return typeof(T).IsAssignableFrom(typeof(AddressablesPlayModeBuildResult)); - } - - /// - protected override TResult BuildDataImplementation(AddressablesDataBuilderInput builderInput) - { - var timer = new System.Diagnostics.Stopwatch(); - timer.Start(); - var settingsPath = Addressables.BuildPath + "/settings.json"; - var buildLogsPath = Addressables.BuildPath + "/buildLogs.json"; - if (!File.Exists(settingsPath)) - { - IDataBuilderResult resE = new AddressablesPlayModeBuildResult() - { - Error = "Player content must be built before entering play mode with packed data. This can be done from the Addressables window in the Build->Build Player Content menu command." - }; - return (TResult)resE; - } - - var rtd = JsonUtility.FromJson(File.ReadAllText(settingsPath)); - if (rtd == null) - { - IDataBuilderResult resE = new AddressablesPlayModeBuildResult() - { - Error = string.Format("Unable to load initialization data from path {0}. This can be done from the Addressables window in the Build->Build Player Content menu command.", - settingsPath) - }; - return (TResult)resE; - } - - PackedPlayModeBuildLogs buildLogs = new PackedPlayModeBuildLogs(); - BuildTarget dataBuildTarget = BuildTarget.NoTarget; - if (!Enum.TryParse(rtd.BuildTarget, out dataBuildTarget)) - { - buildLogs.RuntimeBuildLogs.Add(new PackedPlayModeBuildLogs.RuntimeBuildLog(LogType.Warning, - $"Unable to parse build target from initialization data: '{rtd.BuildTarget}'.")); - } - - else if (BuildPipeline.GetBuildTargetGroup(dataBuildTarget) != BuildTargetGroup.Standalone) - { - buildLogs.RuntimeBuildLogs.Add(new PackedPlayModeBuildLogs.RuntimeBuildLog(LogType.Warning, - $"Asset bundles built with build target {dataBuildTarget} may not be compatible with running in the Editor.")); - } - - if (buildLogs.RuntimeBuildLogs.Count > 0) - File.WriteAllText(buildLogsPath, JsonUtility.ToJson(buildLogs)); - - //TODO: detect if the data that does exist is out of date.. - var runtimeSettingsPath = "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/settings.json"; - PlayerPrefs.SetString(Addressables.kAddressablesRuntimeDataPath, runtimeSettingsPath); - PlayerPrefs.SetString(Addressables.kAddressablesRuntimeBuildLogPath, buildLogsPath); - IDataBuilderResult res = new AddressablesPlayModeBuildResult() {OutputPath = settingsPath, Duration = timer.Elapsed.TotalSeconds}; - m_DataBuilt = true; - return (TResult)res; - } - } -} +using System; +using System.IO; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.AddressableAssets.Initialization; + +namespace UnityEditor.AddressableAssets.Build.DataBuilders +{ + /// + /// Uses data built by BuildScriptPacked class. This script just sets up the correct variables and runs. + /// + [CreateAssetMenu(fileName = "BuildScriptPackedPlayMode.asset", menuName = "Addressables/Content Builders/Use Existing Build (requires built groups)")] + public class BuildScriptPackedPlayMode : BuildScriptBase + { + /// + public override string Name + { + get { return "Use Existing Build (requires built groups)"; } + } + + private bool m_DataBuilt; + + /// + public override void ClearCachedData() + { + m_DataBuilt = false; + } + + /// + public override bool IsDataBuilt() + { + return m_DataBuilt; + } + + /// + public override bool CanBuildData() + { + return typeof(T).IsAssignableFrom(typeof(AddressablesPlayModeBuildResult)); + } + + /// + protected override TResult BuildDataImplementation(AddressablesDataBuilderInput builderInput) + { + var timer = new System.Diagnostics.Stopwatch(); + timer.Start(); + var settingsPath = Addressables.BuildPath + "/settings.json"; + var buildLogsPath = Addressables.BuildPath + "/buildLogs.json"; + if (!File.Exists(settingsPath)) + { + IDataBuilderResult resE = new AddressablesPlayModeBuildResult() + { + Error = "Player content must be built before entering play mode with packed data. This can be done from the Addressables window in the Build->Build Player Content menu command." + }; + return (TResult)resE; + } + + var rtd = JsonUtility.FromJson(File.ReadAllText(settingsPath)); + if (rtd == null) + { + IDataBuilderResult resE = new AddressablesPlayModeBuildResult() + { + Error = string.Format("Unable to load initialization data from path {0}. This can be done from the Addressables window in the Build->Build Player Content menu command.", + settingsPath) + }; + return (TResult)resE; + } + + PackedPlayModeBuildLogs buildLogs = new PackedPlayModeBuildLogs(); + BuildTarget dataBuildTarget = BuildTarget.NoTarget; + if (!Enum.TryParse(rtd.BuildTarget, out dataBuildTarget)) + { + buildLogs.RuntimeBuildLogs.Add(new PackedPlayModeBuildLogs.RuntimeBuildLog(LogType.Warning, + $"Unable to parse build target from initialization data: '{rtd.BuildTarget}'.")); + } + + else if (BuildPipeline.GetBuildTargetGroup(dataBuildTarget) != BuildTargetGroup.Standalone) + { + buildLogs.RuntimeBuildLogs.Add(new PackedPlayModeBuildLogs.RuntimeBuildLog(LogType.Warning, + $"Asset bundles built with build target {dataBuildTarget} may not be compatible with running in the Editor.")); + } + + if (buildLogs.RuntimeBuildLogs.Count > 0) + File.WriteAllText(buildLogsPath, JsonUtility.ToJson(buildLogs)); + + //TODO: detect if the data that does exist is out of date.. + var runtimeSettingsPath = "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/settings.json"; + PlayerPrefs.SetString(Addressables.kAddressablesRuntimeDataPath, runtimeSettingsPath); + PlayerPrefs.SetString(Addressables.kAddressablesRuntimeBuildLogPath, buildLogsPath); + IDataBuilderResult res = new AddressablesPlayModeBuildResult() {OutputPath = settingsPath, Duration = timer.Elapsed.TotalSeconds}; + m_DataBuilt = true; + return (TResult)res; + } + } +} diff --git a/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs.meta b/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs.meta index 8b2a8faf..2367ec44 100644 --- a/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs.meta +++ b/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: ad8c280d42ee0ed41a27db23b43dd2bf -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: ad8c280d42ee0ed41a27db23b43dd2bf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/DataBuilders/BuildScriptVirtualMode.cs b/Editor/Build/DataBuilders/BuildScriptVirtualMode.cs index 85e9150d..7b55c667 100644 --- a/Editor/Build/DataBuilders/BuildScriptVirtualMode.cs +++ b/Editor/Build/DataBuilders/BuildScriptVirtualMode.cs @@ -1,437 +1,437 @@ -using System; -using System.Collections.Generic; -using UnityEditor.AddressableAssets.Build.BuildPipelineTasks; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.AddressableAssets.Settings.GroupSchemas; -using UnityEditor.Build.Pipeline; -using UnityEditor.Build.Pipeline.Interfaces; -using UnityEditor.Build.Pipeline.Tasks; -using UnityEditor.SceneManagement; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.AddressableAssets.Initialization; -using UnityEngine.AddressableAssets.ResourceLocators; -using UnityEngine.AddressableAssets.ResourceProviders; -using UnityEngine.ResourceManagement.ResourceProviders; -using UnityEngine.ResourceManagement.ResourceProviders.Simulation; -using UnityEngine.ResourceManagement.Util; -using System.IO; -using System.Linq; -using System.Reflection; -using UnityEditor.Experimental; - -namespace UnityEditor.AddressableAssets.Build.DataBuilders -{ - /// - /// Build script for creating virtual asset bundle dat for running in the editor. - /// - [CreateAssetMenu(fileName = "BuildScriptVirtual.asset", menuName = "Addressables/Content Builders/Simulate Groups (advanced)")] - public class BuildScriptVirtualMode : BuildScriptBase - { - protected internal const string kCatalogExt = -#if ENABLE_BINARY_CATALOG - ".bin"; -#else - ".json"; -#endif - /// - public override string Name - { - get { return "Simulate Groups (advanced)"; } - } - - /// - public override bool CanBuildData() - { - return typeof(T).IsAssignableFrom(typeof(AddressablesPlayModeBuildResult)); - } - string m_PathSuffix = ""; - string GetCatalogPath(string relPath = "") - { - return $"{relPath}{Addressables.LibraryPath}catalog{m_PathSuffix}{kCatalogExt}"; - } - - string GetSettingsPath(string relPath = "") - { - return $"{relPath}{Addressables.LibraryPath}settings{m_PathSuffix}.json"; - } - - /// - public override void ClearCachedData() - { - DeleteFile(GetCatalogPath()); - DeleteFile(GetSettingsPath()); - } - - /// - public override bool IsDataBuilt() - { - return File.Exists(GetCatalogPath()) && File.Exists(GetSettingsPath()); - } - - List m_ResourceProviderData; - List m_AllBundleInputDefinitions; - Dictionary m_CreatedProviderIds; - - /// - protected override TResult BuildDataImplementation(AddressablesDataBuilderInput builderInput) - { - TResult result = default(TResult); - - var timer = new System.Diagnostics.Stopwatch(); - timer.Start(); - var aaSettings = builderInput.AddressableSettings; - - m_PathSuffix = builderInput.PathSuffix; - - - //gather entries - var aaContext = new AddressableAssetsBuildContext - { - Settings = aaSettings, - runtimeData = new ResourceManagerRuntimeData(), - bundleToAssetGroup = new Dictionary(), - locations = new List(), - providerTypes = new HashSet(), - assetEntries = new List(), - buildStartTime = DateTime.Now - }; - m_AllBundleInputDefinitions = new List(); - aaContext.runtimeData.BuildTarget = builderInput.Target.ToString(); - aaContext.runtimeData.ProfileEvents = ProjectConfigData.PostProfilerEvents; - aaContext.runtimeData.LogResourceManagerExceptions = aaSettings.buildSettings.LogResourceManagerExceptions; - aaContext.runtimeData.ProfileEvents = ProjectConfigData.PostProfilerEvents; - aaContext.runtimeData.MaxConcurrentWebRequests = aaSettings.MaxConcurrentWebRequests; - aaContext.runtimeData.CatalogRequestsTimeout = aaSettings.CatalogRequestsTimeout; - aaContext.runtimeData.CatalogLocations.Add(new ResourceLocationData( - new[] { ResourceManagerRuntimeData.kCatalogAddress }, - GetCatalogPath("file://{UnityEngine.Application.dataPath}/../"), - typeof(ContentCatalogProvider), typeof(ContentCatalogData))); - aaContext.runtimeData.AddressablesVersion = PackageManager.PackageInfo.FindForAssembly(typeof(Addressables).Assembly)?.version; - m_CreatedProviderIds = new Dictionary(); - m_ResourceProviderData = new List(); - - var errorString = ProcessAllGroups(aaContext); - if (!string.IsNullOrEmpty(errorString)) - result = AddressableAssetBuildResult.CreateResult(null, 0, errorString); - - if (result == null) - { - result = DoBuild(builderInput, aaSettings, aaContext); - } - - if (result != null) - result.Duration = timer.Elapsed.TotalSeconds; - return result; - } - - TResult DoBuild(AddressablesDataBuilderInput builderInput, AddressableAssetSettings aaSettings, AddressableAssetsBuildContext aaContext) where TResult : IDataBuilderResult - { - if (m_AllBundleInputDefinitions.Count > 0) - { - if (!BuildUtility.CheckModifiedScenesAndAskToSave()) - return AddressableAssetBuildResult.CreateResult(null, 0, "Unsaved scenes"); - - var buildTarget = builderInput.Target; - var buildTargetGroup = builderInput.TargetGroup; - var buildParams = new AddressableAssetsBundleBuildParameters(aaSettings, aaContext.bundleToAssetGroup, buildTarget, buildTargetGroup, aaSettings.buildSettings.bundleBuildPath); - var builtinShaderBundleName = aaSettings.DefaultGroup.Name.ToLower().Replace(" ", "").Replace('\\', '/').Replace("//", "/") + "_unitybuiltinshaders.bundle"; - var buildTasks = RuntimeDataBuildTasks(aaSettings.buildSettings.compileScriptsInVirtualMode, builtinShaderBundleName); - ExtractDataTask extractData = new ExtractDataTask(); - buildTasks.Add(extractData); - - string aaPath = aaSettings.AssetPath; - IBundleBuildResults results; - var exitCode = ContentPipeline.BuildAssetBundles(buildParams, new BundleBuildContent(m_AllBundleInputDefinitions), out results, buildTasks, aaContext); - - if (exitCode < ReturnCode.Success) - return AddressableAssetBuildResult.CreateResult(null, 0, "SBP Error" + exitCode); - - if (aaSettings == null && !string.IsNullOrEmpty(aaPath)) - aaSettings = AssetDatabase.LoadAssetAtPath(aaPath); - } - - var bundledAssets = new Dictionary>(); - foreach (var loc in aaContext.locations) - { - if (loc.Dependencies != null && loc.Dependencies.Count > 0) - { - for (int i = 0; i < loc.Dependencies.Count; i++) - { - var dep = loc.Dependencies[i]; - HashSet assetsInBundle; - if (!bundledAssets.TryGetValue(dep, out assetsInBundle)) - bundledAssets.Add(dep, assetsInBundle = new HashSet()); - if (i == 0 && !assetsInBundle.Contains(loc.InternalId)) //only add the asset to the first bundle... - assetsInBundle.Add(loc.InternalId); - } - } - } - - foreach (var bd in bundledAssets) - { - AddressableAssetGroup group = aaSettings.DefaultGroup; - string groupGuid; - if (aaContext.bundleToAssetGroup.TryGetValue(bd.Key as string, out groupGuid)) - group = aaSettings.FindGroup(g => g.Guid == groupGuid); - - var schema = group.GetSchema(); - if (schema != null) - { - var bundleLocData = aaContext.locations.First(s => s.Keys[0] == bd.Key); - var isLocalBundle = IsInternalIdLocal(bundleLocData.InternalId); - uint crc = (uint)UnityEngine.Random.Range(0, int.MaxValue); - var hash = Guid.NewGuid().ToString(); - - string originalBundleName = bd.Key as string; - string newBundleName = BuildUtility.GetNameWithHashNaming(schema.BundleNaming, hash, originalBundleName); - bundleLocData.InternalId = bundleLocData.InternalId.Remove(bundleLocData.InternalId.Length - originalBundleName.Length) + newBundleName; - var abb = m_AllBundleInputDefinitions.FirstOrDefault(a => a.assetBundleName == originalBundleName); - var virtualBundleName = AddressablesRuntimeProperties.EvaluateString(bundleLocData.InternalId); - var bundleData = new VirtualAssetBundle(virtualBundleName, isLocalBundle, crc, hash); - - long dataSize = 0; - long headerSize = 0; - foreach (var a in bd.Value) - { - var i = Array.IndexOf(abb.addressableNames, a); - var assetPath = abb.assetNames[i]; - var size = ComputeSize(assetPath); - var vab = new VirtualAssetBundleEntry(a, size); - vab.m_AssetPath = assetPath; - bundleData.Assets.Add(vab); - dataSize += size; - headerSize += a.Length * 5; //assume 5x path length overhead size per item, probably much less - } - - if (bd.Value.Count == 0) - { - dataSize = 100 * 1024; - headerSize = 1024; - } - - bundleData.SetSize(dataSize, headerSize); - - - var requestOptions = new VirtualAssetBundleRequestOptions - { - Crc = schema.UseAssetBundleCrc ? crc : 0, - Hash = schema.UseAssetBundleCache ? hash : "", - ChunkedTransfer = schema.ChunkedTransfer, - RedirectLimit = schema.RedirectLimit, - RetryCount = schema.RetryCount, - Timeout = schema.Timeout, - BundleName = Path.GetFileName(bundleLocData.InternalId), - AssetLoadMode = schema.AssetLoadMode, - BundleSize = dataSize + headerSize - }; - bundleLocData.Data = requestOptions; - - var bundleProviderId = schema.GetBundleCachedProviderId(); - var virtualBundleRuntimeData = m_CreatedProviderIds[bundleProviderId]; - virtualBundleRuntimeData.AssetBundles.Add(bundleData); - } - } - - foreach (var kvp in m_CreatedProviderIds) - { - if (kvp.Value != null) - { - var bundleProviderData = ObjectInitializationData.CreateSerializedInitializationData(kvp.Key, kvp.Value); - m_ResourceProviderData.Add(bundleProviderData); - } - } -#if ENABLE_BINARY_CATALOG - var contentCatalog = new ContentCatalogData(ResourceManagerRuntimeData.kCatalogAddress); - - contentCatalog.ResourceProviderData.AddRange(m_ResourceProviderData); - foreach (var t in aaContext.providerTypes) - contentCatalog.ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(t)); - - contentCatalog.InstanceProviderData = ObjectInitializationData.CreateSerializedInitializationData(instanceProviderType.Value); - contentCatalog.SceneProviderData = ObjectInitializationData.CreateSerializedInitializationData(sceneProviderType.Value); - - contentCatalog.SetData(aaContext.locations.OrderBy(f => f.InternalId).ToList()); - //save catalog - WriteFile(GetCatalogPath(), contentCatalog.SerializeToByteArray(), builderInput.Registry); - -#else - var contentCatalog = new ContentCatalogData(ResourceManagerRuntimeData.kCatalogAddress); - contentCatalog.SetData(aaContext.locations.OrderBy(f => f.InternalId).ToList()); - - contentCatalog.ResourceProviderData.AddRange(m_ResourceProviderData); - foreach (var t in aaContext.providerTypes) - contentCatalog.ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(t)); - - contentCatalog.InstanceProviderData = ObjectInitializationData.CreateSerializedInitializationData(instanceProviderType.Value); - contentCatalog.SceneProviderData = ObjectInitializationData.CreateSerializedInitializationData(sceneProviderType.Value); - - //save catalog - WriteFile(GetCatalogPath(), JsonUtility.ToJson(contentCatalog), builderInput.Registry); -#endif - - - foreach (var io in aaSettings.InitializationObjects) - { - if (io is IObjectInitializationDataProvider) - aaContext.runtimeData.InitializationObjects.Add((io as IObjectInitializationDataProvider).CreateObjectInitializationData()); - } - - var settingsPath = GetSettingsPath(); - WriteFile(settingsPath, JsonUtility.ToJson(aaContext.runtimeData), builderInput.Registry); - - //inform runtime of the init data path - var runtimeSettingsPath = GetSettingsPath("file://{UnityEngine.Application.dataPath}/../"); - PlayerPrefs.SetString(Addressables.kAddressablesRuntimeDataPath, runtimeSettingsPath); - var result = AddressableAssetBuildResult.CreateResult(settingsPath, aaContext.locations.Count); - return result; - } - - /// - protected override string ProcessGroup(AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext) - { - var errorString = string.Empty; - PlayerDataGroupSchema playerSchema = assetGroup.GetSchema(); - if (playerSchema != null) - { - if (CreateLocationsForPlayerData(playerSchema, assetGroup, aaContext.locations, aaContext.providerTypes)) - { - if (!m_CreatedProviderIds.ContainsKey(typeof(LegacyResourcesProvider).Name)) - { - m_CreatedProviderIds.Add(typeof(LegacyResourcesProvider).Name, null); - m_ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(typeof(LegacyResourcesProvider))); - } - } - - return errorString; - } - - var schema = assetGroup.GetSchema(); - if (schema == null) - return errorString; - - var bundledProviderId = schema.GetBundleCachedProviderId(); - var assetProviderId = schema.GetAssetCachedProviderId(); - if (!m_CreatedProviderIds.ContainsKey(bundledProviderId)) - { - //TODO: pull from schema instead of ProjectConfigData - var virtualBundleRuntimeData = new VirtualAssetBundleRuntimeData(ProjectConfigData.LocalLoadSpeed, ProjectConfigData.RemoteLoadSpeed); - //save virtual runtime data to collect assets into virtual bundles - m_CreatedProviderIds.Add(bundledProviderId, virtualBundleRuntimeData); - } - - if (!m_CreatedProviderIds.ContainsKey(assetProviderId)) - { - m_CreatedProviderIds.Add(assetProviderId, null); - - var assetProviderData = ObjectInitializationData.CreateSerializedInitializationData(assetProviderId); - m_ResourceProviderData.Add(assetProviderData); - } - - - var bundleInputDefs = new List(); - List list = BuildScriptPackedMode.PrepGroupBundlePacking(assetGroup, bundleInputDefs, schema); - aaContext.assetEntries.AddRange(list); - for (int i = 0; i < bundleInputDefs.Count; i++) - { - if (aaContext.bundleToAssetGroup.ContainsKey(bundleInputDefs[i].assetBundleName)) - { - var bid = bundleInputDefs[i]; - int count = 1; - var newName = bid.assetBundleName; - while (aaContext.bundleToAssetGroup.ContainsKey(newName) && count < 1000) - newName = bid.assetBundleName.Replace(".bundle", string.Format("{0}.bundle", count++)); - bundleInputDefs[i] = new AssetBundleBuild - {assetBundleName = newName, addressableNames = bid.addressableNames, assetBundleVariant = bid.assetBundleVariant, assetNames = bid.assetNames}; - } - - aaContext.bundleToAssetGroup.Add(bundleInputDefs[i].assetBundleName, assetGroup.Guid); - } - - m_AllBundleInputDefinitions.AddRange(bundleInputDefs); - - return errorString; - } - - static bool IsInternalIdLocal(string path) - { - return path.StartsWith("{UnityEngine.AddressableAssets.Addressables.RuntimePath}", StringComparison.Ordinal); - } - - static string OutputLibraryPathForAsset(string a) - { - var guid = AssetDatabase.AssetPathToGUID(a); - var legacyPath = string.Format("Library/metadata/{0}{1}/{2}", guid[0], guid[1], guid); -#if UNITY_2020_2_OR_NEWER - var artifactID = Experimental.AssetDatabaseExperimental.ProduceArtifact(new ArtifactKey(new GUID(guid))); - if (Experimental.AssetDatabaseExperimental.GetArtifactPaths(artifactID, out var paths)) - return Path.GetFullPath(paths[0]); - else - legacyPath = String.Empty; -#elif UNITY_2020_1_OR_NEWER - var hash = Experimental.AssetDatabaseExperimental.GetArtifactHash(guid); - if (Experimental.AssetDatabaseExperimental.GetArtifactPaths(hash, out var paths)) - return Path.GetFullPath(paths[0]); - else - legacyPath = String.Empty; // legacy path is never valid in 2020.1+ -#else - if (IsAssetDatabaseV2Enabled()) // AssetDatabase V2 is optional in 2019.3 and 2019.4 - { - var hash = Experimental.AssetDatabaseExperimental.GetArtifactHash(guid); - if (Experimental.AssetDatabaseExperimental.GetArtifactPaths(hash, out var paths)) - return Path.GetFullPath(paths[0]); - } -#endif - return legacyPath; - } - - static bool IsAssetDatabaseV2Enabled() - { - // method is internal - var methodInfo = typeof(AssetDatabase).GetMethod("IsV2Enabled", BindingFlags.Static | BindingFlags.NonPublic); - return methodInfo != null && (bool)methodInfo.Invoke(null, null); - } - - static long ComputeSize(string a) - { - var path = OutputLibraryPathForAsset(a); - if (!File.Exists(path)) - { - return 1024 * 1024; - } - - return new FileInfo(path).Length; - } - - static IList RuntimeDataBuildTasks(bool compileScripts, string builtinShaderBundleName) - { - var buildTasks = new List(); - - // Setup - buildTasks.Add(new SwitchToBuildPlatform()); - buildTasks.Add(new RebuildSpriteAtlasCache()); - - // Player Scripts - if (compileScripts) - { - buildTasks.Add(new BuildPlayerScripts()); - buildTasks.Add(new PostScriptsCallback()); - } - - // Dependency - buildTasks.Add(new PreviewSceneDependencyData()); - buildTasks.Add(new CalculateAssetDependencyData()); - buildTasks.Add(new StripUnusedSpriteSources()); - buildTasks.Add(new CreateBuiltInShadersBundle(builtinShaderBundleName)); - buildTasks.Add(new PostDependencyCallback()); - - // Packing - buildTasks.Add(new GenerateBundlePacking()); - buildTasks.Add(new UpdateBundleObjectLayout()); - buildTasks.Add(new GenerateLocationListsTask()); - buildTasks.Add(new PostPackingCallback()); - - return buildTasks; - } - } -} +using System; +using System.Collections.Generic; +using UnityEditor.AddressableAssets.Build.BuildPipelineTasks; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEditor.Build.Pipeline; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEditor.Build.Pipeline.Tasks; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.AddressableAssets.Initialization; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.AddressableAssets.ResourceProviders; +using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.ResourceManagement.ResourceProviders.Simulation; +using UnityEngine.ResourceManagement.Util; +using System.IO; +using System.Linq; +using System.Reflection; +using UnityEditor.Experimental; + +namespace UnityEditor.AddressableAssets.Build.DataBuilders +{ + /// + /// Build script for creating virtual asset bundle dat for running in the editor. + /// + [CreateAssetMenu(fileName = "BuildScriptVirtual.asset", menuName = "Addressables/Content Builders/Simulate Groups (advanced)")] + public class BuildScriptVirtualMode : BuildScriptBase + { + protected internal const string kCatalogExt = +#if ENABLE_BINARY_CATALOG + ".bin"; +#else + ".json"; +#endif + /// + public override string Name + { + get { return "Simulate Groups (advanced)"; } + } + + /// + public override bool CanBuildData() + { + return typeof(T).IsAssignableFrom(typeof(AddressablesPlayModeBuildResult)); + } + string m_PathSuffix = ""; + string GetCatalogPath(string relPath = "") + { + return $"{relPath}{Addressables.LibraryPath}catalog{m_PathSuffix}{kCatalogExt}"; + } + + string GetSettingsPath(string relPath = "") + { + return $"{relPath}{Addressables.LibraryPath}settings{m_PathSuffix}.json"; + } + + /// + public override void ClearCachedData() + { + DeleteFile(GetCatalogPath()); + DeleteFile(GetSettingsPath()); + } + + /// + public override bool IsDataBuilt() + { + return File.Exists(GetCatalogPath()) && File.Exists(GetSettingsPath()); + } + + List m_ResourceProviderData; + List m_AllBundleInputDefinitions; + Dictionary m_CreatedProviderIds; + + /// + protected override TResult BuildDataImplementation(AddressablesDataBuilderInput builderInput) + { + TResult result = default(TResult); + + var timer = new System.Diagnostics.Stopwatch(); + timer.Start(); + var aaSettings = builderInput.AddressableSettings; + + m_PathSuffix = builderInput.PathSuffix; + + + //gather entries + var aaContext = new AddressableAssetsBuildContext + { + Settings = aaSettings, + runtimeData = new ResourceManagerRuntimeData(), + bundleToAssetGroup = new Dictionary(), + locations = new List(), + providerTypes = new HashSet(), + assetEntries = new List(), + buildStartTime = DateTime.Now + }; + m_AllBundleInputDefinitions = new List(); + aaContext.runtimeData.BuildTarget = builderInput.Target.ToString(); + aaContext.runtimeData.ProfileEvents = ProjectConfigData.PostProfilerEvents; + aaContext.runtimeData.LogResourceManagerExceptions = aaSettings.buildSettings.LogResourceManagerExceptions; + aaContext.runtimeData.ProfileEvents = ProjectConfigData.PostProfilerEvents; + aaContext.runtimeData.MaxConcurrentWebRequests = aaSettings.MaxConcurrentWebRequests; + aaContext.runtimeData.CatalogRequestsTimeout = aaSettings.CatalogRequestsTimeout; + aaContext.runtimeData.CatalogLocations.Add(new ResourceLocationData( + new[] { ResourceManagerRuntimeData.kCatalogAddress }, + GetCatalogPath("file://{UnityEngine.Application.dataPath}/../"), + typeof(ContentCatalogProvider), typeof(ContentCatalogData))); + aaContext.runtimeData.AddressablesVersion = PackageManager.PackageInfo.FindForAssembly(typeof(Addressables).Assembly)?.version; + m_CreatedProviderIds = new Dictionary(); + m_ResourceProviderData = new List(); + + var errorString = ProcessAllGroups(aaContext); + if (!string.IsNullOrEmpty(errorString)) + result = AddressableAssetBuildResult.CreateResult(null, 0, errorString); + + if (result == null) + { + result = DoBuild(builderInput, aaSettings, aaContext); + } + + if (result != null) + result.Duration = timer.Elapsed.TotalSeconds; + return result; + } + + TResult DoBuild(AddressablesDataBuilderInput builderInput, AddressableAssetSettings aaSettings, AddressableAssetsBuildContext aaContext) where TResult : IDataBuilderResult + { + if (m_AllBundleInputDefinitions.Count > 0) + { + if (!BuildUtility.CheckModifiedScenesAndAskToSave()) + return AddressableAssetBuildResult.CreateResult(null, 0, "Unsaved scenes"); + + var buildTarget = builderInput.Target; + var buildTargetGroup = builderInput.TargetGroup; + var buildParams = new AddressableAssetsBundleBuildParameters(aaSettings, aaContext.bundleToAssetGroup, buildTarget, buildTargetGroup, aaSettings.buildSettings.bundleBuildPath); + var builtinShaderBundleName = aaSettings.DefaultGroup.Name.ToLower().Replace(" ", "").Replace('\\', '/').Replace("//", "/") + "_unitybuiltinshaders.bundle"; + var buildTasks = RuntimeDataBuildTasks(aaSettings.buildSettings.compileScriptsInVirtualMode, builtinShaderBundleName); + ExtractDataTask extractData = new ExtractDataTask(); + buildTasks.Add(extractData); + + string aaPath = aaSettings.AssetPath; + IBundleBuildResults results; + var exitCode = ContentPipeline.BuildAssetBundles(buildParams, new BundleBuildContent(m_AllBundleInputDefinitions), out results, buildTasks, aaContext); + + if (exitCode < ReturnCode.Success) + return AddressableAssetBuildResult.CreateResult(null, 0, "SBP Error" + exitCode); + + if (aaSettings == null && !string.IsNullOrEmpty(aaPath)) + aaSettings = AssetDatabase.LoadAssetAtPath(aaPath); + } + + var bundledAssets = new Dictionary>(); + foreach (var loc in aaContext.locations) + { + if (loc.Dependencies != null && loc.Dependencies.Count > 0) + { + for (int i = 0; i < loc.Dependencies.Count; i++) + { + var dep = loc.Dependencies[i]; + HashSet assetsInBundle; + if (!bundledAssets.TryGetValue(dep, out assetsInBundle)) + bundledAssets.Add(dep, assetsInBundle = new HashSet()); + if (i == 0 && !assetsInBundle.Contains(loc.InternalId)) //only add the asset to the first bundle... + assetsInBundle.Add(loc.InternalId); + } + } + } + + foreach (var bd in bundledAssets) + { + AddressableAssetGroup group = aaSettings.DefaultGroup; + string groupGuid; + if (aaContext.bundleToAssetGroup.TryGetValue(bd.Key as string, out groupGuid)) + group = aaSettings.FindGroup(g => g.Guid == groupGuid); + + var schema = group.GetSchema(); + if (schema != null) + { + var bundleLocData = aaContext.locations.First(s => s.Keys[0] == bd.Key); + var isLocalBundle = IsInternalIdLocal(bundleLocData.InternalId); + uint crc = (uint)UnityEngine.Random.Range(0, int.MaxValue); + var hash = Guid.NewGuid().ToString(); + + string originalBundleName = bd.Key as string; + string newBundleName = BuildUtility.GetNameWithHashNaming(schema.BundleNaming, hash, originalBundleName); + bundleLocData.InternalId = bundleLocData.InternalId.Remove(bundleLocData.InternalId.Length - originalBundleName.Length) + newBundleName; + var abb = m_AllBundleInputDefinitions.FirstOrDefault(a => a.assetBundleName == originalBundleName); + var virtualBundleName = AddressablesRuntimeProperties.EvaluateString(bundleLocData.InternalId); + var bundleData = new VirtualAssetBundle(virtualBundleName, isLocalBundle, crc, hash); + + long dataSize = 0; + long headerSize = 0; + foreach (var a in bd.Value) + { + var i = Array.IndexOf(abb.addressableNames, a); + var assetPath = abb.assetNames[i]; + var size = ComputeSize(assetPath); + var vab = new VirtualAssetBundleEntry(a, size); + vab.m_AssetPath = assetPath; + bundleData.Assets.Add(vab); + dataSize += size; + headerSize += a.Length * 5; //assume 5x path length overhead size per item, probably much less + } + + if (bd.Value.Count == 0) + { + dataSize = 100 * 1024; + headerSize = 1024; + } + + bundleData.SetSize(dataSize, headerSize); + + + var requestOptions = new VirtualAssetBundleRequestOptions + { + Crc = schema.UseAssetBundleCrc ? crc : 0, + Hash = schema.UseAssetBundleCache ? hash : "", + ChunkedTransfer = schema.ChunkedTransfer, + RedirectLimit = schema.RedirectLimit, + RetryCount = schema.RetryCount, + Timeout = schema.Timeout, + BundleName = Path.GetFileName(bundleLocData.InternalId), + AssetLoadMode = schema.AssetLoadMode, + BundleSize = dataSize + headerSize + }; + bundleLocData.Data = requestOptions; + + var bundleProviderId = schema.GetBundleCachedProviderId(); + var virtualBundleRuntimeData = m_CreatedProviderIds[bundleProviderId]; + virtualBundleRuntimeData.AssetBundles.Add(bundleData); + } + } + + foreach (var kvp in m_CreatedProviderIds) + { + if (kvp.Value != null) + { + var bundleProviderData = ObjectInitializationData.CreateSerializedInitializationData(kvp.Key, kvp.Value); + m_ResourceProviderData.Add(bundleProviderData); + } + } +#if ENABLE_BINARY_CATALOG + var contentCatalog = new ContentCatalogData(ResourceManagerRuntimeData.kCatalogAddress); + + contentCatalog.ResourceProviderData.AddRange(m_ResourceProviderData); + foreach (var t in aaContext.providerTypes) + contentCatalog.ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(t)); + + contentCatalog.InstanceProviderData = ObjectInitializationData.CreateSerializedInitializationData(instanceProviderType.Value); + contentCatalog.SceneProviderData = ObjectInitializationData.CreateSerializedInitializationData(sceneProviderType.Value); + + contentCatalog.SetData(aaContext.locations.OrderBy(f => f.InternalId).ToList()); + //save catalog + WriteFile(GetCatalogPath(), contentCatalog.SerializeToByteArray(), builderInput.Registry); + +#else + var contentCatalog = new ContentCatalogData(ResourceManagerRuntimeData.kCatalogAddress); + contentCatalog.SetData(aaContext.locations.OrderBy(f => f.InternalId).ToList()); + + contentCatalog.ResourceProviderData.AddRange(m_ResourceProviderData); + foreach (var t in aaContext.providerTypes) + contentCatalog.ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(t)); + + contentCatalog.InstanceProviderData = ObjectInitializationData.CreateSerializedInitializationData(instanceProviderType.Value); + contentCatalog.SceneProviderData = ObjectInitializationData.CreateSerializedInitializationData(sceneProviderType.Value); + + //save catalog + WriteFile(GetCatalogPath(), JsonUtility.ToJson(contentCatalog), builderInput.Registry); +#endif + + + foreach (var io in aaSettings.InitializationObjects) + { + if (io is IObjectInitializationDataProvider) + aaContext.runtimeData.InitializationObjects.Add((io as IObjectInitializationDataProvider).CreateObjectInitializationData()); + } + + var settingsPath = GetSettingsPath(); + WriteFile(settingsPath, JsonUtility.ToJson(aaContext.runtimeData), builderInput.Registry); + + //inform runtime of the init data path + var runtimeSettingsPath = GetSettingsPath("file://{UnityEngine.Application.dataPath}/../"); + PlayerPrefs.SetString(Addressables.kAddressablesRuntimeDataPath, runtimeSettingsPath); + var result = AddressableAssetBuildResult.CreateResult(settingsPath, aaContext.locations.Count); + return result; + } + + /// + protected override string ProcessGroup(AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext) + { + var errorString = string.Empty; + PlayerDataGroupSchema playerSchema = assetGroup.GetSchema(); + if (playerSchema != null) + { + if (CreateLocationsForPlayerData(playerSchema, assetGroup, aaContext.locations, aaContext.providerTypes)) + { + if (!m_CreatedProviderIds.ContainsKey(typeof(LegacyResourcesProvider).Name)) + { + m_CreatedProviderIds.Add(typeof(LegacyResourcesProvider).Name, null); + m_ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(typeof(LegacyResourcesProvider))); + } + } + + return errorString; + } + + var schema = assetGroup.GetSchema(); + if (schema == null) + return errorString; + + var bundledProviderId = schema.GetBundleCachedProviderId(); + var assetProviderId = schema.GetAssetCachedProviderId(); + if (!m_CreatedProviderIds.ContainsKey(bundledProviderId)) + { + //TODO: pull from schema instead of ProjectConfigData + var virtualBundleRuntimeData = new VirtualAssetBundleRuntimeData(ProjectConfigData.LocalLoadSpeed, ProjectConfigData.RemoteLoadSpeed); + //save virtual runtime data to collect assets into virtual bundles + m_CreatedProviderIds.Add(bundledProviderId, virtualBundleRuntimeData); + } + + if (!m_CreatedProviderIds.ContainsKey(assetProviderId)) + { + m_CreatedProviderIds.Add(assetProviderId, null); + + var assetProviderData = ObjectInitializationData.CreateSerializedInitializationData(assetProviderId); + m_ResourceProviderData.Add(assetProviderData); + } + + + var bundleInputDefs = new List(); + List list = BuildScriptPackedMode.PrepGroupBundlePacking(assetGroup, bundleInputDefs, schema); + aaContext.assetEntries.AddRange(list); + for (int i = 0; i < bundleInputDefs.Count; i++) + { + if (aaContext.bundleToAssetGroup.ContainsKey(bundleInputDefs[i].assetBundleName)) + { + var bid = bundleInputDefs[i]; + int count = 1; + var newName = bid.assetBundleName; + while (aaContext.bundleToAssetGroup.ContainsKey(newName) && count < 1000) + newName = bid.assetBundleName.Replace(".bundle", string.Format("{0}.bundle", count++)); + bundleInputDefs[i] = new AssetBundleBuild + {assetBundleName = newName, addressableNames = bid.addressableNames, assetBundleVariant = bid.assetBundleVariant, assetNames = bid.assetNames}; + } + + aaContext.bundleToAssetGroup.Add(bundleInputDefs[i].assetBundleName, assetGroup.Guid); + } + + m_AllBundleInputDefinitions.AddRange(bundleInputDefs); + + return errorString; + } + + static bool IsInternalIdLocal(string path) + { + return path.StartsWith("{UnityEngine.AddressableAssets.Addressables.RuntimePath}", StringComparison.Ordinal); + } + + static string OutputLibraryPathForAsset(string a) + { + var guid = AssetDatabase.AssetPathToGUID(a); + var legacyPath = string.Format("Library/metadata/{0}{1}/{2}", guid[0], guid[1], guid); +#if UNITY_2020_2_OR_NEWER + var artifactID = Experimental.AssetDatabaseExperimental.ProduceArtifact(new ArtifactKey(new GUID(guid))); + if (Experimental.AssetDatabaseExperimental.GetArtifactPaths(artifactID, out var paths)) + return Path.GetFullPath(paths[0]); + else + legacyPath = String.Empty; +#elif UNITY_2020_1_OR_NEWER + var hash = Experimental.AssetDatabaseExperimental.GetArtifactHash(guid); + if (Experimental.AssetDatabaseExperimental.GetArtifactPaths(hash, out var paths)) + return Path.GetFullPath(paths[0]); + else + legacyPath = String.Empty; // legacy path is never valid in 2020.1+ +#else + if (IsAssetDatabaseV2Enabled()) // AssetDatabase V2 is optional in 2019.3 and 2019.4 + { + var hash = Experimental.AssetDatabaseExperimental.GetArtifactHash(guid); + if (Experimental.AssetDatabaseExperimental.GetArtifactPaths(hash, out var paths)) + return Path.GetFullPath(paths[0]); + } +#endif + return legacyPath; + } + + static bool IsAssetDatabaseV2Enabled() + { + // method is internal + var methodInfo = typeof(AssetDatabase).GetMethod("IsV2Enabled", BindingFlags.Static | BindingFlags.NonPublic); + return methodInfo != null && (bool)methodInfo.Invoke(null, null); + } + + static long ComputeSize(string a) + { + var path = OutputLibraryPathForAsset(a); + if (!File.Exists(path)) + { + return 1024 * 1024; + } + + return new FileInfo(path).Length; + } + + static IList RuntimeDataBuildTasks(bool compileScripts, string builtinShaderBundleName) + { + var buildTasks = new List(); + + // Setup + buildTasks.Add(new SwitchToBuildPlatform()); + buildTasks.Add(new RebuildSpriteAtlasCache()); + + // Player Scripts + if (compileScripts) + { + buildTasks.Add(new BuildPlayerScripts()); + buildTasks.Add(new PostScriptsCallback()); + } + + // Dependency + buildTasks.Add(new PreviewSceneDependencyData()); + buildTasks.Add(new CalculateAssetDependencyData()); + buildTasks.Add(new StripUnusedSpriteSources()); + buildTasks.Add(new CreateBuiltInShadersBundle(builtinShaderBundleName)); + buildTasks.Add(new PostDependencyCallback()); + + // Packing + buildTasks.Add(new GenerateBundlePacking()); + buildTasks.Add(new UpdateBundleObjectLayout()); + buildTasks.Add(new GenerateLocationListsTask()); + buildTasks.Add(new PostPackingCallback()); + + return buildTasks; + } + } +} diff --git a/Editor/Build/DataBuilders/BuildScriptVirtualMode.cs.meta b/Editor/Build/DataBuilders/BuildScriptVirtualMode.cs.meta index 0a7556c7..adc1c53b 100644 --- a/Editor/Build/DataBuilders/BuildScriptVirtualMode.cs.meta +++ b/Editor/Build/DataBuilders/BuildScriptVirtualMode.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: bb0e4994b34add1409fd8ccaf4a82de5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: bb0e4994b34add1409fd8ccaf4a82de5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/DirectoryUtility.cs b/Editor/Build/DirectoryUtility.cs index 5cac0dd8..06210d0d 100644 --- a/Editor/Build/DirectoryUtility.cs +++ b/Editor/Build/DirectoryUtility.cs @@ -1,88 +1,88 @@ -using System.IO; -using System.Linq; -using UnityEditor; -using UnityEngine; - -internal static class DirectoryUtility -{ - internal static void DeleteDirectory(string directoryPath, bool onlyIfEmpty = true, bool recursiveDelete = true) - { - if (!Directory.Exists(directoryPath)) - return; - - bool isEmpty = !Directory.EnumerateFiles(directoryPath, "*", SearchOption.AllDirectories).Any() - && !Directory.EnumerateDirectories(directoryPath, "*", SearchOption.AllDirectories).Any(); - if (!onlyIfEmpty || isEmpty) - { - // check if the folder is valid in the AssetDatabase before deleting through standard file system - string relativePath = directoryPath.Replace("\\", "/").Replace(Application.dataPath, "Assets"); - if (AssetDatabase.IsValidFolder(relativePath)) - AssetDatabase.DeleteAsset(relativePath); - else - Directory.Delete(directoryPath, recursiveDelete); - } - } - - internal static void DirectoryMove(string sourceDirName, string destDirName) - { - if (!Directory.Exists(sourceDirName)) - { - Debug.LogError($"Could not Move directory {sourceDirName}, directory not found."); - return; - } - - if (Directory.Exists(destDirName)) - { - Debug.LogError($"Could not Move to directory {destDirName}, directory arlready exists."); - return; - } - - Directory.Move(sourceDirName, destDirName); - // check if the folder is valid in the AssetDatabase before deleting through standard file system - string relativePath = sourceDirName.Replace("\\", "/").Replace(Application.dataPath, "Assets"); - if (AssetDatabase.IsValidFolder(relativePath)) - { - // recreate the root folder so that it can be removed via adb - Directory.CreateDirectory(sourceDirName); - AssetDatabase.DeleteAsset(relativePath); - } - else if (File.Exists(sourceDirName + ".meta")) - File.Delete(sourceDirName + ".meta"); - } - - internal static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs) - { - // Get the subdirectories for the specified directory. - DirectoryInfo dir = new DirectoryInfo(sourceDirName); - - if (!dir.Exists) - { - throw new DirectoryNotFoundException( - "Source directory does not exist or could not be found: " - + sourceDirName); - } - - DirectoryInfo[] dirs = dir.GetDirectories(); - // If the destination directory doesn't exist, create it. - if (!Directory.Exists(destDirName)) - Directory.CreateDirectory(destDirName); - - // Get the files in the directory and copy them to the new location. - FileInfo[] files = dir.GetFiles(); - foreach (FileInfo file in files) - { - string temppath = Path.Combine(destDirName, file.Name); - file.CopyTo(temppath, true); - } - - // If copying subdirectories, copy them and their contents to new location. - if (copySubDirs) - { - foreach (DirectoryInfo subdir in dirs) - { - string temppath = Path.Combine(destDirName, subdir.Name); - DirectoryCopy(subdir.FullName, temppath, true); - } - } - } -} +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; + +internal static class DirectoryUtility +{ + internal static void DeleteDirectory(string directoryPath, bool onlyIfEmpty = true, bool recursiveDelete = true) + { + if (!Directory.Exists(directoryPath)) + return; + + bool isEmpty = !Directory.EnumerateFiles(directoryPath, "*", SearchOption.AllDirectories).Any() + && !Directory.EnumerateDirectories(directoryPath, "*", SearchOption.AllDirectories).Any(); + if (!onlyIfEmpty || isEmpty) + { + // check if the folder is valid in the AssetDatabase before deleting through standard file system + string relativePath = directoryPath.Replace("\\", "/").Replace(Application.dataPath, "Assets"); + if (AssetDatabase.IsValidFolder(relativePath)) + AssetDatabase.DeleteAsset(relativePath); + else + Directory.Delete(directoryPath, recursiveDelete); + } + } + + internal static void DirectoryMove(string sourceDirName, string destDirName) + { + if (!Directory.Exists(sourceDirName)) + { + Debug.LogError($"Could not Move directory {sourceDirName}, directory not found."); + return; + } + + if (Directory.Exists(destDirName)) + { + Debug.LogError($"Could not Move to directory {destDirName}, directory arlready exists."); + return; + } + + Directory.Move(sourceDirName, destDirName); + // check if the folder is valid in the AssetDatabase before deleting through standard file system + string relativePath = sourceDirName.Replace("\\", "/").Replace(Application.dataPath, "Assets"); + if (AssetDatabase.IsValidFolder(relativePath)) + { + // recreate the root folder so that it can be removed via adb + Directory.CreateDirectory(sourceDirName); + AssetDatabase.DeleteAsset(relativePath); + } + else if (File.Exists(sourceDirName + ".meta")) + File.Delete(sourceDirName + ".meta"); + } + + internal static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs) + { + // Get the subdirectories for the specified directory. + DirectoryInfo dir = new DirectoryInfo(sourceDirName); + + if (!dir.Exists) + { + throw new DirectoryNotFoundException( + "Source directory does not exist or could not be found: " + + sourceDirName); + } + + DirectoryInfo[] dirs = dir.GetDirectories(); + // If the destination directory doesn't exist, create it. + if (!Directory.Exists(destDirName)) + Directory.CreateDirectory(destDirName); + + // Get the files in the directory and copy them to the new location. + FileInfo[] files = dir.GetFiles(); + foreach (FileInfo file in files) + { + string temppath = Path.Combine(destDirName, file.Name); + file.CopyTo(temppath, true); + } + + // If copying subdirectories, copy them and their contents to new location. + if (copySubDirs) + { + foreach (DirectoryInfo subdir in dirs) + { + string temppath = Path.Combine(destDirName, subdir.Name); + DirectoryCopy(subdir.FullName, temppath, true); + } + } + } +} diff --git a/Editor/Build/DirectoryUtility.cs.meta b/Editor/Build/DirectoryUtility.cs.meta index ec5a3e6c..012530d3 100644 --- a/Editor/Build/DirectoryUtility.cs.meta +++ b/Editor/Build/DirectoryUtility.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: f8683601388ff6b4bb7d1f1a52ee6108 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: f8683601388ff6b4bb7d1f1a52ee6108 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/FastModeInitializationOperation.cs b/Editor/Build/FastModeInitializationOperation.cs index 5ad81288..6dc2fce4 100644 --- a/Editor/Build/FastModeInitializationOperation.cs +++ b/Editor/Build/FastModeInitializationOperation.cs @@ -1,130 +1,130 @@ -using System.Collections.Generic; -using UnityEditor.AddressableAssets.Build; -using UnityEditor.AddressableAssets.Build.DataBuilders; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.AddressableAssets.ResourceLocators; -using UnityEngine.AddressableAssets.ResourceProviders; -using UnityEngine.AddressableAssets.Utility; -using UnityEngine.ResourceManagement; -using UnityEngine.ResourceManagement.AsyncOperations; -using UnityEngine.ResourceManagement.ResourceProviders; -using UnityEngine.ResourceManagement.Util; - -namespace UnityEditor.AddressableAssets.Settings -{ - internal class FastModeInitializationOperation : AsyncOperationBase - { - AddressablesImpl m_addressables; - AddressableAssetSettings m_settings; - internal ResourceManagerDiagnostics m_Diagnostics; - AsyncOperationHandle> groupOp; - - public FastModeInitializationOperation(AddressablesImpl addressables, AddressableAssetSettings settings) - { - m_addressables = addressables; - m_settings = settings; - m_addressables.ResourceManager.RegisterForCallbacks(); - m_Diagnostics = new ResourceManagerDiagnostics(m_addressables.ResourceManager); - } - - internal static T GetBuilderOfType(AddressableAssetSettings settings, bool includeSubclasses) where T : class, IDataBuilder - { - System.Type typeToFind = typeof(T); - if (!includeSubclasses) - { - foreach (var db in settings.DataBuilders) - if (db.GetType() == typeToFind) - return db as T; - return null; - } - - ScriptableObject dataBuilder = null; - foreach (var db in settings.DataBuilders) - { - var currentType = db.GetType(); - if (dataBuilder == null) - { - if (currentType == typeToFind || currentType.IsSubclassOf(typeToFind)) - dataBuilder = db; - } - else if (currentType.IsSubclassOf(dataBuilder.GetType())) - dataBuilder = db; - } - - return dataBuilder as T; - } - - /// - protected override bool InvokeWaitForCompletion() - { - if (IsDone) - return true; - - m_RM?.Update(Time.unscaledDeltaTime); - if (!HasExecuted) - InvokeExecute(); - return true; - } - - protected override void Execute() - { - var db = GetBuilderOfType(m_settings, true); - if (db == null) - UnityEngine.Debug.Log($"Unable to find {nameof(BuildScriptFastMode)} or subclass builder in settings assets. Using default Instance and Scene Providers."); - - var locator = new AddressableAssetSettingsLocator(m_settings); - m_addressables.AddResourceLocator(locator); - m_addressables.AddResourceLocator(new DynamicResourceLocator(m_addressables)); - m_addressables.ResourceManager.postProfilerEvents = ProjectConfigData.PostProfilerEvents; - if (!m_addressables.ResourceManager.postProfilerEvents) - { - m_Diagnostics.Dispose(); - m_Diagnostics = null; - m_addressables.ResourceManager.ClearDiagnosticCallbacks(); - } - - if (!m_settings.buildSettings.LogResourceManagerExceptions) - ResourceManager.ExceptionHandler = null; - - //NOTE: for some reason, the data builders can get lost from the settings asset during a domain reload - this only happens in tests and custom instance and scene providers are not needed - m_addressables.InstanceProvider = - db == null ? new InstanceProvider() : ObjectInitializationData.CreateSerializedInitializationData(db.instanceProviderType.Value).CreateInstance(); - m_addressables.SceneProvider = db == null ? new SceneProvider() : ObjectInitializationData.CreateSerializedInitializationData(db.sceneProviderType.Value).CreateInstance(); - m_addressables.ResourceManager.ResourceProviders.Add(new AssetDatabaseProvider()); - m_addressables.ResourceManager.ResourceProviders.Add(new TextDataProvider()); - m_addressables.ResourceManager.ResourceProviders.Add(new JsonAssetProvider()); - m_addressables.ResourceManager.ResourceProviders.Add(new LegacyResourcesProvider()); - m_addressables.ResourceManager.ResourceProviders.Add(new AtlasSpriteProvider()); - m_addressables.ResourceManager.ResourceProviders.Add(new ContentCatalogProvider(m_addressables.ResourceManager)); - WebRequestQueue.SetMaxConcurrentRequests(m_settings.MaxConcurrentWebRequests); - m_addressables.CatalogRequestsTimeout = m_settings.CatalogRequestsTimeout; - - if (m_settings.InitializationObjects.Count == 0) - { - Complete(locator, true, null); - } - else - { - List initOperations = new List(); - foreach (var io in m_settings.InitializationObjects) - { - if (io is IObjectInitializationDataProvider) - { - var ioData = (io as IObjectInitializationDataProvider).CreateObjectInitializationData(); - var h = ioData.GetAsyncInitHandle(m_addressables.ResourceManager); - initOperations.Add(h); - } - } - - groupOp = m_addressables.ResourceManager.CreateGenericGroupOperation(initOperations, true); - groupOp.Completed += op => - { - bool success = op.Status == AsyncOperationStatus.Succeeded; - Complete(locator, success, success ? "" : $"{op.DebugName}, status={op.Status}, result={op.Result} failed initialization."); - m_addressables.Release(op); - }; - } - } - } -} +using System.Collections.Generic; +using UnityEditor.AddressableAssets.Build; +using UnityEditor.AddressableAssets.Build.DataBuilders; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.AddressableAssets.ResourceProviders; +using UnityEngine.AddressableAssets.Utility; +using UnityEngine.ResourceManagement; +using UnityEngine.ResourceManagement.AsyncOperations; +using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.ResourceManagement.Util; + +namespace UnityEditor.AddressableAssets.Settings +{ + internal class FastModeInitializationOperation : AsyncOperationBase + { + AddressablesImpl m_addressables; + AddressableAssetSettings m_settings; + internal ResourceManagerDiagnostics m_Diagnostics; + AsyncOperationHandle> groupOp; + + public FastModeInitializationOperation(AddressablesImpl addressables, AddressableAssetSettings settings) + { + m_addressables = addressables; + m_settings = settings; + m_addressables.ResourceManager.RegisterForCallbacks(); + m_Diagnostics = new ResourceManagerDiagnostics(m_addressables.ResourceManager); + } + + internal static T GetBuilderOfType(AddressableAssetSettings settings, bool includeSubclasses) where T : class, IDataBuilder + { + System.Type typeToFind = typeof(T); + if (!includeSubclasses) + { + foreach (var db in settings.DataBuilders) + if (db.GetType() == typeToFind) + return db as T; + return null; + } + + ScriptableObject dataBuilder = null; + foreach (var db in settings.DataBuilders) + { + var currentType = db.GetType(); + if (dataBuilder == null) + { + if (currentType == typeToFind || currentType.IsSubclassOf(typeToFind)) + dataBuilder = db; + } + else if (currentType.IsSubclassOf(dataBuilder.GetType())) + dataBuilder = db; + } + + return dataBuilder as T; + } + + /// + protected override bool InvokeWaitForCompletion() + { + if (IsDone) + return true; + + m_RM?.Update(Time.unscaledDeltaTime); + if (!HasExecuted) + InvokeExecute(); + return true; + } + + protected override void Execute() + { + var db = GetBuilderOfType(m_settings, true); + if (db == null) + UnityEngine.Debug.Log($"Unable to find {nameof(BuildScriptFastMode)} or subclass builder in settings assets. Using default Instance and Scene Providers."); + + var locator = new AddressableAssetSettingsLocator(m_settings); + m_addressables.AddResourceLocator(locator); + m_addressables.AddResourceLocator(new DynamicResourceLocator(m_addressables)); + m_addressables.ResourceManager.postProfilerEvents = ProjectConfigData.PostProfilerEvents; + if (!m_addressables.ResourceManager.postProfilerEvents) + { + m_Diagnostics.Dispose(); + m_Diagnostics = null; + m_addressables.ResourceManager.ClearDiagnosticCallbacks(); + } + + if (!m_settings.buildSettings.LogResourceManagerExceptions) + ResourceManager.ExceptionHandler = null; + + //NOTE: for some reason, the data builders can get lost from the settings asset during a domain reload - this only happens in tests and custom instance and scene providers are not needed + m_addressables.InstanceProvider = + db == null ? new InstanceProvider() : ObjectInitializationData.CreateSerializedInitializationData(db.instanceProviderType.Value).CreateInstance(); + m_addressables.SceneProvider = db == null ? new SceneProvider() : ObjectInitializationData.CreateSerializedInitializationData(db.sceneProviderType.Value).CreateInstance(); + m_addressables.ResourceManager.ResourceProviders.Add(new AssetDatabaseProvider()); + m_addressables.ResourceManager.ResourceProviders.Add(new TextDataProvider()); + m_addressables.ResourceManager.ResourceProviders.Add(new JsonAssetProvider()); + m_addressables.ResourceManager.ResourceProviders.Add(new LegacyResourcesProvider()); + m_addressables.ResourceManager.ResourceProviders.Add(new AtlasSpriteProvider()); + m_addressables.ResourceManager.ResourceProviders.Add(new ContentCatalogProvider(m_addressables.ResourceManager)); + WebRequestQueue.SetMaxConcurrentRequests(m_settings.MaxConcurrentWebRequests); + m_addressables.CatalogRequestsTimeout = m_settings.CatalogRequestsTimeout; + + if (m_settings.InitializationObjects.Count == 0) + { + Complete(locator, true, null); + } + else + { + List initOperations = new List(); + foreach (var io in m_settings.InitializationObjects) + { + if (io is IObjectInitializationDataProvider) + { + var ioData = (io as IObjectInitializationDataProvider).CreateObjectInitializationData(); + var h = ioData.GetAsyncInitHandle(m_addressables.ResourceManager); + initOperations.Add(h); + } + } + + groupOp = m_addressables.ResourceManager.CreateGenericGroupOperation(initOperations, true); + groupOp.Completed += op => + { + bool success = op.Status == AsyncOperationStatus.Succeeded; + Complete(locator, success, success ? "" : $"{op.DebugName}, status={op.Status}, result={op.Result} failed initialization."); + m_addressables.Release(op); + }; + } + } + } +} diff --git a/Editor/Build/FastModeInitializationOperation.cs.meta b/Editor/Build/FastModeInitializationOperation.cs.meta index 96e43218..37f48062 100644 --- a/Editor/Build/FastModeInitializationOperation.cs.meta +++ b/Editor/Build/FastModeInitializationOperation.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: bb8458bc10d7afe4f8ad0204ab6f1fd8 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: bb8458bc10d7afe4f8ad0204ab6f1fd8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/FileRegistry.cs b/Editor/Build/FileRegistry.cs index cb861f25..ec8062f7 100644 --- a/Editor/Build/FileRegistry.cs +++ b/Editor/Build/FileRegistry.cs @@ -1,80 +1,80 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEditor.AddressableAssets.Settings; - -namespace UnityEditor.AddressableAssets.Build -{ - /// - /// Use to contain files created during a build. - /// - public class FileRegistry - { - private readonly HashSet m_FilePaths; - - /// - /// Initializes a new file registry instance. - /// - public FileRegistry() - { - m_FilePaths = new HashSet(); - } - - /// - /// Retrieves all the stored file paths. - /// - /// Returns all file paths as an IEnumerable. - public IEnumerable GetFilePaths() - { - return new HashSet(m_FilePaths); - } - - /// - /// Adds a file path to our set of file paths. - /// - /// The file path. - public void AddFile(string path) - { - m_FilePaths.Add(path); - } - - /// - /// Removes a file path from our set of file paths. - /// - /// The file path. - public void RemoveFile(string path) - { - m_FilePaths.Remove(path); - } - - /// - /// Given a bundle name, determine the file path for the bundle. - /// - /// The name of the bundle. - /// The full file path. - public string GetFilePathForBundle(string bundleName) - { - bundleName = Path.GetFileNameWithoutExtension(bundleName); - return m_FilePaths.FirstOrDefault((entry) => AddressableAssetUtility.StringContains(entry, bundleName, StringComparison.Ordinal)); - } - - /// - /// Replace an entry in the File Registry with a new bundle name. - /// - /// The bundle name to replace. - /// The new file registry bundle name. - /// Returns true if a successful replacement occured. - public bool ReplaceBundleEntry(string bundleName, string newFileRegistryEntry) - { - if (!m_FilePaths.Contains(newFileRegistryEntry)) - { - m_FilePaths.RemoveWhere((entry) => AddressableAssetUtility.StringContains(entry, bundleName, StringComparison.Ordinal)); - AddFile(newFileRegistryEntry); - return true; - } - - return false; - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor.AddressableAssets.Settings; + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// Use to contain files created during a build. + /// + public class FileRegistry + { + private readonly HashSet m_FilePaths; + + /// + /// Initializes a new file registry instance. + /// + public FileRegistry() + { + m_FilePaths = new HashSet(); + } + + /// + /// Retrieves all the stored file paths. + /// + /// Returns all file paths as an IEnumerable. + public IEnumerable GetFilePaths() + { + return new HashSet(m_FilePaths); + } + + /// + /// Adds a file path to our set of file paths. + /// + /// The file path. + public void AddFile(string path) + { + m_FilePaths.Add(path); + } + + /// + /// Removes a file path from our set of file paths. + /// + /// The file path. + public void RemoveFile(string path) + { + m_FilePaths.Remove(path); + } + + /// + /// Given a bundle name, determine the file path for the bundle. + /// + /// The name of the bundle. + /// The full file path. + public string GetFilePathForBundle(string bundleName) + { + bundleName = Path.GetFileNameWithoutExtension(bundleName); + return m_FilePaths.FirstOrDefault((entry) => AddressableAssetUtility.StringContains(entry, bundleName, StringComparison.Ordinal)); + } + + /// + /// Replace an entry in the File Registry with a new bundle name. + /// + /// The bundle name to replace. + /// The new file registry bundle name. + /// Returns true if a successful replacement occured. + public bool ReplaceBundleEntry(string bundleName, string newFileRegistryEntry) + { + if (!m_FilePaths.Contains(newFileRegistryEntry)) + { + m_FilePaths.RemoveWhere((entry) => AddressableAssetUtility.StringContains(entry, bundleName, StringComparison.Ordinal)); + AddFile(newFileRegistryEntry); + return true; + } + + return false; + } + } +} diff --git a/Editor/Build/FileRegistry.cs.meta b/Editor/Build/FileRegistry.cs.meta index 6430bf92..f60aa387 100644 --- a/Editor/Build/FileRegistry.cs.meta +++ b/Editor/Build/FileRegistry.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 776e8b00aee724f69a02402947a3967f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 776e8b00aee724f69a02402947a3967f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Layout.meta b/Editor/Build/Layout.meta index b8f3c98b..92283171 100644 --- a/Editor/Build/Layout.meta +++ b/Editor/Build/Layout.meta @@ -1,8 +1,8 @@ -fileFormatVersion: 2 -guid: 0c39c5a44c2b90c4787a92f26e3286f4 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 0c39c5a44c2b90c4787a92f26e3286f4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Layout/BuildLayout.cs b/Editor/Build/Layout/BuildLayout.cs index f8531af8..d0dcbb0d 100644 --- a/Editor/Build/Layout/BuildLayout.cs +++ b/Editor/Build/Layout/BuildLayout.cs @@ -1,1380 +1,1380 @@ -using System; -using System.Collections.Generic; -using System.IO; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.Build.Content; -using UnityEngine; -using UnityEngine.AddressableAssets.ResourceLocators; -using UnityEngine.ResourceManagement.ResourceProviders; - -namespace UnityEditor.AddressableAssets.Build.Layout -{ - /// - /// A storage class used to gather data about an Addressable build. - /// - [Serializable] - public class BuildLayout - { - /// - /// Helper class to wrap header values for BuildLayout - /// - public class LayoutHeader - { - /// - /// Build layout for this header - /// - internal BuildLayout m_BuildLayout; - - /// - /// Build Platform Addressables build is targeting - /// - public BuildTarget BuildTarget - { - get - { - if (m_BuildLayout == null) - return BuildTarget.NoTarget; - return m_BuildLayout.BuildTarget; - } - } - - /// - /// Hash of the build results - /// - public string BuildResultHash - { - get - { - if (m_BuildLayout == null) - return null; - return m_BuildLayout.BuildResultHash; - } - } - - /// - /// If the build was a new build or an update for a previous build - /// - public BuildType BuildType - { - get - { - if (m_BuildLayout == null) - return BuildType.NewBuild; - return m_BuildLayout.BuildType; - } - } - - /// - /// DateTime at the start of building Addressables - /// - public DateTime BuildStart - { - get - { - if (m_BuildLayout == null) - return DateTime.MinValue; - return m_BuildLayout.BuildStart; - } - } - - /// - /// Time in seconds taken to build Addressables Content - /// - public double Duration - { - get - { - if (m_BuildLayout == null) - return 0; - return m_BuildLayout.Duration; - } - } - - /// - /// Null or Empty if the build completed successfully, else contains error causing the failure - /// - public string BuildError - { - get - { - if (m_BuildLayout == null) - return ""; - return m_BuildLayout.BuildError; - } - } - } - - /// - /// Helper object to get header values for this build layout - /// - public LayoutHeader Header - { - get - { - if (m_Header == null) - m_Header = new LayoutHeader() {m_BuildLayout = this}; - return m_Header; - } - } - - private LayoutHeader m_Header; - - #region HeaderValues // Any values in here should also be in BuildLayoutHeader class - - /// - /// Build Platform Addressables build is targeting - /// - public BuildTarget BuildTarget; - - /// - /// Hash of the build results - /// - public string BuildResultHash; - - /// - /// If the build was a new build or an update for a previous build - /// - public BuildType BuildType; - - /// - /// DateTime at the start of building Addressables - /// - public DateTime BuildStart - { - get - { - if (m_BuildStartDateTime.Year > 2000) - return m_BuildStartDateTime; - if (DateTime.TryParse(BuildStartTime, out DateTime result)) - { - m_BuildStartDateTime = result; - return m_BuildStartDateTime; - } - return DateTime.MinValue; - } - set - { - BuildStartTime = value.ToString(); - } - } - private DateTime m_BuildStartDateTime; - - [SerializeField] - internal string BuildStartTime; - - /// - /// Time in seconds taken to build Addressables Content - /// - public double Duration; - - /// - /// Null or Empty if the build completed successfully, else contains error causing the failure - /// - public string BuildError; - - #endregion // End of header values - - /// - /// Version of the Unity edtior used to perform the build. - /// - public string UnityVersion; - - /// - /// Version of the Addressables package used to perform the build. - /// - public string PackageVersion; - - /// - /// Player build version for the build, this is a timestamp if PlayerVersionOverride is not set in the settings - /// - public string PlayerBuildVersion; - - /// - /// Settings used by the Addressables settings at the time of building - /// - public AddressablesEditorData AddressablesEditorSettings; - - /// - /// Values used by the Addressables runtime - /// - public AddressablesRuntimeData AddressablesRuntimeSettings; - - /// - /// Name of the build script to build - /// - public string BuildScript; - - /// - /// Default group at the time of building - /// - [SerializeReference] - public Group DefaultGroup; - - /// - /// The Addressable Groups that reference this data - /// - [SerializeReference] - public List Groups = new List(); - - /// - /// The List of AssetBundles that were built without a group associated to them, such as the BuiltIn Shaders Bundle and the MonoScript Bundle - /// - [SerializeReference] - public List BuiltInBundles = new List(); - - /// - /// List of assets with implicitly included Objects - /// - public List DuplicatedAssets = new List(); - - /// - /// The build path on disk of the default local content catalog - /// - [SerializeField] - internal string LocalCatalogBuildPath; - - /// - /// The build path of the remote content catalog, if one was built - /// - [SerializeField] - internal string RemoteCatalogBuildPath; - - internal string m_FilePath; - - private bool m_HeaderRead = false; - private bool m_BodyRead = false; - - private FileStream m_FileStream = null; - private StreamReader m_StreamReader = null; - - /// - /// Used for serialising the header info for the BuildLayout. - /// Names must match values in BuildLayout class - /// - [Serializable] - private class BuildLayoutHeader - { - public BuildTarget BuildTarget; - public string BuildResultHash; - public BuildType BuildType; - public string BuildStartTime; - public double Duration; - public string BuildError; - } - - /// - /// - /// - /// Path to the BuildLayout json file on disk - /// If the basic header information should be read - /// If the full build layout should be read - /// - public static BuildLayout Open(string path, bool readHeader = true, bool readFullFile = false) - { - if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) - { - Debug.LogError($"Invalid path provided : {path}"); - return null; - } - - BuildLayout readLayout = new BuildLayout - { - m_FilePath = path - }; - - if (readFullFile) - readLayout.ReadFull(); - else if (readHeader) - readLayout.ReadHeader(); - - return readLayout; - } - - /// - /// Writes json file for the build layout to the destination path - /// - /// File path to write build layout - /// If json should be written using pretty print - public void WriteToFile(string destinationPath, bool prettyPrint) - { - Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); - - string versionElementString = "\"UnityVersion\":"; - string headerJson = null; - string bodyJson = JsonUtility.ToJson(this, prettyPrint); - - if (prettyPrint) - { - BuildLayoutHeader header = new BuildLayoutHeader() - { - BuildTarget = this.BuildTarget, - BuildResultHash = this.BuildResultHash, - BuildType = this.BuildType, - BuildStartTime = this.BuildStartTime, - Duration = this.Duration, - BuildError = this.BuildError - }; - headerJson = JsonUtility.ToJson(header, false); - headerJson = headerJson.Remove(headerJson.Length - 1, 1) + ','; - } - - int index = bodyJson.IndexOf(versionElementString); - if (prettyPrint) - bodyJson = bodyJson.Remove(0, index); - else - bodyJson = bodyJson.Insert(index, "\n"); - - using (FileStream s = System.IO.File.Open(destinationPath, FileMode.Create)) - { - using (StreamWriter sw = new StreamWriter(s)) - { - if (prettyPrint) - sw.WriteLine(headerJson); - sw.Write(bodyJson); - } - } - } - - /// - /// Closes streams for loading the build layout - /// - public void Close() - { - if (m_StreamReader != null) - { - m_StreamReader.Close(); - m_StreamReader = null; - } - - if (m_FileStream != null) - { - m_FileStream.Close(); - m_FileStream = null; - } - } - - /// - /// Reads basic information about the build layout - /// - /// If false, the file will be closed after reading the header line. - /// true is successful, else false - public bool ReadHeader(bool keepFileStreamsActive = false) - { - if (m_HeaderRead) - return true; - - if (string.IsNullOrEmpty(m_FilePath)) - { - Debug.LogError("Cannot read BuildLayout header, A file has not been selected to open. Open must be called before reading any data"); - return false; - } - - try - { - if (m_FileStream == null) - { - m_FileStream = System.IO.File.Open(m_FilePath, FileMode.Open); - m_StreamReader = new StreamReader(m_FileStream); - } - - string fileJsonText = m_StreamReader.ReadLine(); - int lastComma = fileJsonText.LastIndexOf(','); - if (lastComma > 0) - { - fileJsonText = fileJsonText.Remove(lastComma) + '}'; - try - { - EditorJsonUtility.FromJsonOverwrite(fileJsonText, this); - } - catch (Exception e) - { - Debug.LogError($"Failed to read header for BuildLayout at {m_FilePath}, with exception: {e.Message}"); - return false; - } - } - else - { - Debug.LogError($"Failed to read header for BuildLayout at {m_FilePath}, invalid json format"); - return false; - } - - m_HeaderRead = true; - } - catch (Exception e) - { - Debug.LogException(e); - return false; - } - finally - { - if (!keepFileStreamsActive) - Close(); - } - - return true; - } - - /// - /// Reads the full build layout data from file - /// - /// true is successful, else false - public bool ReadFull() - { - if (m_BodyRead) - return true; - - if (string.IsNullOrEmpty(m_FilePath)) - { - Debug.LogError("Cannot read BuildLayout header, BuildLayout has not open for a file"); - return false; - } - - try - { - if (m_FileStream == null) - { - m_FileStream = System.IO.File.Open(m_FilePath, FileMode.Open); - m_StreamReader = new StreamReader(m_FileStream); - } - else if (m_HeaderRead) - { - // reset to read the whole file - m_FileStream.Position = 0; - m_StreamReader.DiscardBufferedData(); - } - - string fileJsonText = m_StreamReader.ReadToEnd(); - EditorJsonUtility.FromJsonOverwrite(fileJsonText, this); - m_HeaderRead = true; - m_BodyRead = true; - } - catch (Exception e) - { - Debug.LogError($"Failed to read header for BuildLayout at {m_FilePath}, with exception: {e.Message}"); - return false; - } - finally - { - Close(); - } - - return true; - } - - /// - /// Values set for the AddressablesAssetSettings at the time of building - /// - [Serializable] - public class AddressablesEditorData - { - /// - /// Hash value of the settings at the time of building - /// - public string SettingsHash; - - /// - /// Active Addressables profile set at time of Building - /// - public Profile ActiveProfile; - - /// - /// Addressables setting value set for building the remote catalog - /// - public bool BuildRemoteCatalog; - - /// - /// Load path for the remote catalog if enabled - /// - public string RemoteCatalogLoadPath; - - /// - /// Addressables setting value set for bundling the local catalog - /// - public bool BundleLocalCatalog; - - /// - /// Addressables setting value set for optimising the catalog size - /// - public bool OptimizeCatalogSize; - - /// - /// Addressables setting value set for time out when downloading catalogs - /// - public int CatalogRequestsTimeout; - - /// - /// Runtime setting value set for the maximum number of concurrent web requests - /// - public int MaxConcurrentWebRequests; - - /// - /// Addressables setting value set for is to update the remote catalog on startup - /// - public bool DisableCatalogUpdateOnStartup; - - /// - /// Addressables setting value set for if the build created unique bundle ids - /// - public bool UniqueBundleIds; - - /// - /// Addressables setting value set for if the build used non recursive dependency calculation - /// - public bool NonRecursiveBuilding; - - /// - /// Addressables setting value set for if the build used contiguous bundle objects - /// - public bool ContiguousBundles; - - /// - /// Addressables setting value set for disabling sub asset representation in the Bundle - /// - public bool DisableSubAssetRepresentations; - - /// - /// Internal naming prefix of the built in shaders bundle - /// - public string ShaderBundleNaming; - - /// - /// Internal naming prefix of the monoScript bundle, - /// No MonoScript bundle is built if set to disabled - /// - public string MonoScriptBundleNaming; - - /// - /// Addressables setting value set for is the unity version was stripped from the built bundles - /// - public bool StripUnityVersionFromBundleBuild; - } - - /// - /// Values set for runtime initialisation of Addressables - /// - [Serializable] - public class AddressablesRuntimeData - { - /// - /// Runtime setting value set for if the runtime will submit profiler events - /// - public bool ProfilerEvents; - - /// - /// Runtime setting value set for if resource manager exceptions are logged or not - /// - public bool LogResourceManagerExceptions; - - /// - /// Runtime setting value set for catalogs to load (First catalog found in the list is used) - /// - public List CatalogLoadPaths = new List(); - - /// - /// Hash of the build catalog - /// - public string CatalogHash; - } - - /// - /// Information about the AssetBundleObject - /// - [Serializable] - public class AssetBundleObjectInfo - { - /// - /// The size, in bytes, of the AssetBundleObject - /// - public ulong Size; - } - - /// - /// Key value pair of string type - /// - [Serializable] - public struct StringPair - { - /// - /// String key - /// - public string Key; - - /// - /// String value - /// - public string Value; - } - - /// - /// Addressables Profile data - /// - [Serializable] - public class Profile - { - /// - /// Name of the profile - /// - public string Name; - - /// - /// ID assigned within the ProfileSettings of the profile - /// - public string Id; - - /// - /// Profile variables assigned to the profile - /// - public StringPair[] Values; - } - - /// - /// Data about the AddressableAssetGroup that gets processed during a build. - /// - [Serializable] - public class Group - { - /// - /// The Name of the AdressableAssetGroup - /// - public string Name; - - /// - /// The Guid of the AddressableAssetGroup - /// - public string Guid; - - /// - /// The packing mode as defined by the BundledAssetGroupSchema on the AddressableAssetGroup - /// - public string PackingMode; - - /// - /// A list of the AssetBundles associated with the Group - /// - [SerializeReference] - public List Bundles = new List(); - - /// - /// Data about the AddressableAssetGroupSchemas associated with the Group - /// - [SerializeReference] - public List Schemas = new List(); - } - - /// - /// Data container for AddressableAssetGroupSchemas - /// - [Serializable] - public class SchemaData : ISerializationCallbackReceiver - { - /// - /// The Guid of the AddressableAssetGroupSchema - /// - public string Guid; - - /// - /// The class type of the AddressableAssetGroupSchema - /// - public string Type; - - /// - /// These key-value-pairs include data about the AddressableAssetGroupSchema, such as PackingMode and Compression. - /// - public List> KvpDetails = new List>(); - - [SerializeField] - private StringPair[] SchemaDataPairs; - - /// - /// Converts the unserializable KvpDetails to a serializable type for writing - /// - public void OnBeforeSerialize() - { - SchemaDataPairs = new StringPair[KvpDetails.Count]; - for (int i = 0; i < SchemaDataPairs.Length; ++i) - SchemaDataPairs[i] = new StringPair() {Key = KvpDetails[i].Item1, Value = KvpDetails[i].Item2}; - } - - /// - /// Writes data to KvpDetails after Deserializing to temporary data fields - /// - public void OnAfterDeserialize() - { - for (int i = 0; i < SchemaDataPairs.Length; ++i) - KvpDetails.Add(new Tuple(SchemaDataPairs[i].Key, SchemaDataPairs[i].Value)); - SchemaDataPairs = null; - } - } - - /// - /// Data store for AssetBundle information. - /// - [Serializable] - public class Bundle - { - /// - /// The name of the AssetBundle - /// - public string Name; - - /// - /// Name used to identify the asset bundle - /// - public string InternalName; - - /// - /// The file size of the AssetBundle on disk, in bytes - /// - public ulong FileSize; - - /// - /// Status of the bundle after an update build - /// - public BundleBuildStatus BuildStatus; - - /// - /// The file size of all of the Expanded Dependencies of this AssetBundle, in bytes - /// Expanded dependencies are the dependencies of this AssetBundle's dependencies - /// - public ulong ExpandedDependencyFileSize; - - /// - /// The file size - /// - public ulong DependencyFileSize; - - /// - /// The file size of the AssetBundle on disk when uncompressed, in bytes - /// - public ulong UncompressedFileSize - { - get - { - ulong total = 0; - foreach (File file in Files) - total += file.UncompressedSize; - return total; - } - } - - /// - /// The number of Assets contained within the bundle - /// - public int AssetCount = 0; - - /// - /// Represents a dependency from the containing Bundle to dependentBundle, with AssetDependencies representing each of the assets in parentBundle that create the link to dependentBundle - /// - [Serializable] - public class BundleDependency - { - /// - /// The bundle that the parent bundle depends on - /// - [SerializeReference] - public Bundle DependencyBundle; - - /// - /// The list of assets that link the parent bundle to the DependencyBundle - /// - public List AssetDependencies; - - /// - /// Percentage of Efficiency asset usage that uses the entire dependency tree of this bundle dependency. - /// This includes DependencyBundle and all bundles beneath it. - /// Value is equal to [Total Filesize of Dependency Assets] / [Total size of all dependency bundles on disk] - /// Example: There are 3 bundles A, B, and C, that are each 10 MB on disk. A depends on 2 MB worth of assets in B, and B depends on 4 MB worth of assets in C. - /// The Efficiency of the dependencyLink from A->B would be 2/10 -> 20% and the ExpandedEfficiency of A->B would be (2 + 4)/(10 + 10) -> 6/20 -> 30% - /// - public float ExpandedEfficiency; - - /// - /// The Efficiency of the connection between the parent bundle and DependencyBundle irrespective of the full dependency tree below DependencyBundle. - /// Value is equal to [Serialized Filesize of assets In Dependency Bundle Referenced By Parent]/[Total size of Dependency Bundle on disk] - /// Example: Given two Bundles A and B that are each 10 MB on disk, and A depends on 5 MB worth of assets in B, then the Efficiency of DependencyLink A->B is 5/10 = .5 - /// - public float Efficiency; - - private HashSet referencedAssets = new HashSet(); - - /// - /// The number of uniquely assets that the parent bundle uniquely references in dependency bundle. This is used to calculate Efficiency without double counting. - /// - internal ulong referencedAssetsFileSize = 0; - - internal BundleDependency(Bundle b) - { - DependencyBundle = b; - AssetDependencies = new List(); - } - - internal void CreateAssetDependency(ExplicitAsset root, ExplicitAsset dependencyAsset) - { - if (referencedAssets.Contains(dependencyAsset)) - return; - referencedAssets.Add(dependencyAsset); - AssetDependencies.Add(new AssetDependency(root, dependencyAsset)); - referencedAssetsFileSize += dependencyAsset.SerializedSize; - } - - - /// - /// Represents a dependency from a root Asset to a dependent Asset. - /// - [Serializable] - public struct AssetDependency - { - [SerializeReference] - internal ExplicitAsset rootAsset; - - [SerializeReference] - internal ExplicitAsset dependencyAsset; - - internal AssetDependency(ExplicitAsset root, ExplicitAsset depAsset) - { - rootAsset = root; - dependencyAsset = depAsset; - } - } - } - - internal Dictionary BundleDependencyMap = new Dictionary(); - - /// - /// A list of bundles that this bundle depends upon. - /// - [SerializeField] - public BundleDependency[] BundleDependencies = Array.Empty(); - - - /// - /// Convert BundleDependencyMap to a format that is able to be serialized and plays nicer with - /// CalculateEfficiency - this must be called on a bundle before CalculateEfficiency can be called. - /// - internal void SerializeBundleToBundleDependency() - { - BundleDependencies = new BundleDependency[BundleDependencyMap.Values.Count]; - BundleDependencyMap.Values.CopyTo(BundleDependencies, 0); - } - - /// - /// Updates the BundleDependency from the current bundle to the bundle that contains referencedAsset. If no such BundleDependency exists, - /// one is created. Does nothing if rootAsset's bundle is not the current bundle or - /// if the two assets are in the same bundle. - /// - /// - /// - internal void UpdateBundleDependency(ExplicitAsset rootAsset, ExplicitAsset referencedAsset) - { - if (rootAsset.Bundle != this || referencedAsset.Bundle == rootAsset.Bundle) - return; - - if (!BundleDependencyMap.ContainsKey(referencedAsset.Bundle)) - BundleDependencyMap.Add(referencedAsset.Bundle, new BundleDependency(referencedAsset.Bundle)); - BundleDependencyMap[referencedAsset.Bundle].CreateAssetDependency(rootAsset, referencedAsset); - } - - // Helper struct for calculating Efficiency - internal struct EfficiencyInfo - { - internal ulong totalAssetFileSize; - internal ulong referencedAssetFileSize; - } - - - /// - /// The Compression method used for the AssetBundle. - /// - public string Compression; - - /// - /// Cyclic redundancy check of the content contained inside of the asset bundle. - /// This value will not change between identical asset bundles with different compression options. - /// - public uint CRC; - - /// - /// The hash version of the contents contained inside of the asset bundle. - /// This value will not change between identical asset bundles with different compression options. - /// - public Hash128 Hash; - - /// - /// A reference to the Group data that this AssetBundle was generated from - /// - [SerializeReference] - public Group Group; - - /// - /// Path Provider uses to load the Asset Bundle - /// - public string LoadPath; - - /// - /// Provider used to load the Asset Bundle - /// - public string Provider; - - /// - /// Result provided by the Provider loading the Asset Bundle - /// - public string ResultType; - - /// - /// List of the Files referenced by the AssetBundle - /// - [SerializeReference] - public List Files = new List(); - - /// - /// A list of the bundles that directly depend on this AssetBundle - /// - [SerializeReference] - public List DependentBundles = new List(); - - /// - /// A list of the direct dependencies of the AssetBundle - /// - [SerializeReference] - public List Dependencies; - - /// - /// The second order dependencies and greater of a bundle - /// - [SerializeReference] - public List ExpandedDependencies; - } - - /// - /// Data store for resource files generated by the build pipeline and referenced by a main File - /// - [Serializable] - public class SubFile - { - /// - /// The name of the sub-file - /// - public string Name; - - /// - /// If the main File is a serialized file, this will be true. - /// - public bool IsSerializedFile; - - /// - /// The size of the sub-file, in bytes - /// - public ulong Size; - } - - /// - /// Data store for the main File created for the AssetBundle - /// - [Serializable] - public class File - { - /// - /// The name of the File. - /// - public string Name; - - /// - /// The AssetBundle data that relates to a built file. - /// - [SerializeReference] - public Bundle Bundle; - - /// - /// The file size of the AssetBundle on disk when uncompressed, in bytes - /// - public ulong UncompressedSize - { - get - { - ulong total = 0; - foreach (SubFile subFile in SubFiles) - total += subFile.Size; - return total; - } - } - - /// - /// List of the resource files created by the build pipeline that a File references - /// - [SerializeReference] - public List SubFiles = new List(); - - /// - /// A list of the explicit asset defined in the AssetBundle - /// - [SerializeReference] - public List Assets = new List(); - - /// - /// A list of implicit assets built into the AssetBundle, typically through references by Assets that are explicitly defined. - /// - [SerializeReference] - public List OtherAssets = new List(); - - [SerializeReference] - internal List ExternalReferences = new List(); - - /// - /// The final filename of the AssetBundle file - /// - public string WriteResultFilename; - - /// - /// Data about the AssetBundleObject - /// - public AssetBundleObjectInfo BundleObjectInfo; - - /// - /// The size of the data that needs to be preloaded for this File. - /// - public int PreloadInfoSize; - - /// - /// The number of Mono scripts referenced by the File - /// - public int MonoScriptCount; - - /// - /// The size of the Mono scripts referenced by the File - /// - public ulong MonoScriptSize; - } - - /// - /// A representation of an object in an asset file. - /// - [Serializable] - public class ObjectData - { - /// - /// FileId of Object in Asset File - /// - public long LocalIdentifierInFile; - - /// - /// Object name within the Asset - /// - [SerializeField] internal string ObjectName; - - /// - /// Component name if AssetType is a MonoBehaviour or Component - /// - [SerializeField] internal string ComponentName; - - /// - /// Type of Object - /// - public AssetType AssetType; - - /// - /// The size of the file on disk. - /// - public ulong SerializedSize; - - /// - /// The size of the streamed Asset. - /// - public ulong StreamedSize; - - /// - /// References to other Objects - /// - [SerializeField] internal List References = new List(); - } - - /// - /// Identification of an Object within the same file - /// - [Serializable] - internal class ObjectReference - { - public int AssetId; - public List ObjectIds; - } - - /// - /// Data store for Assets explicitly defined in an AssetBundle - /// - [Serializable] - public class ExplicitAsset - { - /// - /// The Asset Guid. - /// - public string Guid; - - /// - /// The Asset path on disk - /// - public string AssetPath; - - /// - /// Name used to identify the asset within the asset bundle containing it - /// - public string InternalId; - - /// - /// Hash of the asset content - /// - public Hash128 AssetHash; - - /// - /// Objects that consist of the overall asset - /// - public List Objects = new List(); - - /// - /// AssetType of the main Object for the Asset - /// - public AssetType MainAssetType; - - /// - /// True if is a scene asset, else false - /// - public bool IsScene => AssetPath.EndsWith(".unity", StringComparison.Ordinal); - - /// - /// Guid of the Addressable group this Asset entry was built using. - /// - public string GroupGuid; - - /// - /// The Addressable address defined in the Addressable Group window for an Asset. - /// - public string AddressableName; - - /// - /// Addressable labels for this asset entry. - /// - [SerializeField] - public string[] Labels = Array.Empty(); - - /// - /// The size of the file on disk. - /// - public ulong SerializedSize; - - /// - /// The size of the streamed Asset. - /// - public ulong StreamedSize; - - /// - /// The file that the Asset was added to - /// - [SerializeReference] - public File File; - - /// - /// The AssetBundle that contains the asset - /// - [SerializeReference] - public Bundle Bundle; - - /// - /// List of data from other Assets referenced by an Asset in the File - /// - [SerializeReference] - public List InternalReferencedOtherAssets = new List(); - - /// - /// List of explicit Assets referenced by this asset that are in the same AssetBundle - /// - [SerializeReference] - public List InternalReferencedExplicitAssets = new List(); - - /// - /// List of explicit Assets referenced by this asset that are in a different AssetBundle - /// - [SerializeReference] - public List ExternallyReferencedAssets = new List(); - - /// - /// List of Assets that reference this Asset - /// - [SerializeReference] - internal List ReferencingAssets = new List(); - } - - /// - /// Data store for implicit Asset references - /// - [Serializable] - public class DataFromOtherAsset - { - /// - /// The Guid of the Asset - /// - public string AssetGuid; - - /// - /// The Asset path on disk - /// - public string AssetPath; - - /// - /// The file that the Asset was added to - /// - [SerializeReference] - public File File; - - /// - /// Objects that consist of the overall asset - /// - public List Objects = new List(); - - /// - /// AssetType of the main Object for the Asset - /// - public AssetType MainAssetType; - - /// - /// True if is a scene asset, else false - /// - public bool IsScene => AssetPath.EndsWith(".unity", StringComparison.Ordinal); - - /// - /// A list of Assets that reference this data - /// - [SerializeReference] - public List ReferencingAssets = new List(); - - /// - /// The number of Objects in the data - /// - public int ObjectCount; - - /// - /// The size of the data on disk - /// - public ulong SerializedSize; - - /// - /// The size of the streamed data - /// - public ulong StreamedSize; - } - - /// - /// Data store for duplicated Implicit Asset information - /// - [Serializable] - public class AssetDuplicationData - { - /// - /// The Guid of the Asset with duplicates - /// - public string AssetGuid; - /// - /// A list of duplicated objects and the bundles that contain them. - /// - public List DuplicatedObjects = new List(); - } - - /// - /// Data store for duplicated Object information - /// - [Serializable] - public class ObjectDuplicationData - { - /// - /// The local identifier for an object. - /// - public long LocalIdentifierInFile; - /// - /// A list of bundles that include the referenced file. - /// - [SerializeReference] public List IncludedInBundleFiles = new List(); - } - } - - /// - /// Utility used to quickly reference data built with the build pipeline - /// - public class LayoutLookupTables - { - /// - /// The default AssetBundle name to the Bundle data map. - /// - public Dictionary Bundles = new Dictionary(); - - /// - /// File name to File data map. - /// - public Dictionary Files = new Dictionary(); - - internal Dictionary FileToFileObjectData = new Dictionary(); - - /// - /// Guid to ExplicitAsset data map. - /// - public Dictionary GuidToExplicitAsset = new Dictionary(); - - /// - /// Group name to Group data map. - /// - public Dictionary GroupLookup = new Dictionary(); - - /// - /// The remapped AssetBundle name to the Bundle data map - /// - internal Dictionary FilenameToBundle = new Dictionary(); - - - /// Maps used for lookups while building the BuildLayout - internal Dictionary> UsedImplicits = new Dictionary>(); - - internal Dictionary BundleNameToRequestOptions = new Dictionary(); - - internal Dictionary BundleNameToPreviousRequestOptions = new Dictionary(); - - internal Dictionary BundleNameToCatalogEntry = new Dictionary(); - - internal Dictionary GroupNameToBuildPath = new Dictionary(); - - internal Dictionary GuidToEntry = new Dictionary(); - internal Dictionary AssetPathToTypeMap = new Dictionary(); - } - - internal class FileObjectData - { - // id's for internal explicit asset and implicit asset - public Dictionary InternalObjectIds = new Dictionary(); - - public Dictionary Objects = new Dictionary(); - - public void Add(ObjectIdentifier buildObjectIdentifier, BuildLayout.ObjectData layoutObject, int assetId, int objectIndex) - { - InternalObjectIds[buildObjectIdentifier] = (assetId, objectIndex); - Objects[layoutObject] = buildObjectIdentifier; - } - - public bool TryGetObjectReferenceData(ObjectIdentifier obj, out (int, int) value) - { - if (!InternalObjectIds.TryGetValue(obj, out (int, int) data)) - { - value = default; - return false; - } - - value = data; - return true; - } - - public bool TryGetObjectIdentifier(BuildLayout.ObjectData obj, out ObjectIdentifier objectIdOut) - { - if (!Objects.TryGetValue(obj, out objectIdOut)) - { - objectIdOut = default; - return false; - } - - return true; - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.Build.Content; +using UnityEngine; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.ResourceManagement.ResourceProviders; + +namespace UnityEditor.AddressableAssets.Build.Layout +{ + /// + /// A storage class used to gather data about an Addressable build. + /// + [Serializable] + public class BuildLayout + { + /// + /// Helper class to wrap header values for BuildLayout + /// + public class LayoutHeader + { + /// + /// Build layout for this header + /// + internal BuildLayout m_BuildLayout; + + /// + /// Build Platform Addressables build is targeting + /// + public BuildTarget BuildTarget + { + get + { + if (m_BuildLayout == null) + return BuildTarget.NoTarget; + return m_BuildLayout.BuildTarget; + } + } + + /// + /// Hash of the build results + /// + public string BuildResultHash + { + get + { + if (m_BuildLayout == null) + return null; + return m_BuildLayout.BuildResultHash; + } + } + + /// + /// If the build was a new build or an update for a previous build + /// + public BuildType BuildType + { + get + { + if (m_BuildLayout == null) + return BuildType.NewBuild; + return m_BuildLayout.BuildType; + } + } + + /// + /// DateTime at the start of building Addressables + /// + public DateTime BuildStart + { + get + { + if (m_BuildLayout == null) + return DateTime.MinValue; + return m_BuildLayout.BuildStart; + } + } + + /// + /// Time in seconds taken to build Addressables Content + /// + public double Duration + { + get + { + if (m_BuildLayout == null) + return 0; + return m_BuildLayout.Duration; + } + } + + /// + /// Null or Empty if the build completed successfully, else contains error causing the failure + /// + public string BuildError + { + get + { + if (m_BuildLayout == null) + return ""; + return m_BuildLayout.BuildError; + } + } + } + + /// + /// Helper object to get header values for this build layout + /// + public LayoutHeader Header + { + get + { + if (m_Header == null) + m_Header = new LayoutHeader() {m_BuildLayout = this}; + return m_Header; + } + } + + private LayoutHeader m_Header; + + #region HeaderValues // Any values in here should also be in BuildLayoutHeader class + + /// + /// Build Platform Addressables build is targeting + /// + public BuildTarget BuildTarget; + + /// + /// Hash of the build results + /// + public string BuildResultHash; + + /// + /// If the build was a new build or an update for a previous build + /// + public BuildType BuildType; + + /// + /// DateTime at the start of building Addressables + /// + public DateTime BuildStart + { + get + { + if (m_BuildStartDateTime.Year > 2000) + return m_BuildStartDateTime; + if (DateTime.TryParse(BuildStartTime, out DateTime result)) + { + m_BuildStartDateTime = result; + return m_BuildStartDateTime; + } + return DateTime.MinValue; + } + set + { + BuildStartTime = value.ToString(); + } + } + private DateTime m_BuildStartDateTime; + + [SerializeField] + internal string BuildStartTime; + + /// + /// Time in seconds taken to build Addressables Content + /// + public double Duration; + + /// + /// Null or Empty if the build completed successfully, else contains error causing the failure + /// + public string BuildError; + + #endregion // End of header values + + /// + /// Version of the Unity edtior used to perform the build. + /// + public string UnityVersion; + + /// + /// Version of the Addressables package used to perform the build. + /// + public string PackageVersion; + + /// + /// Player build version for the build, this is a timestamp if PlayerVersionOverride is not set in the settings + /// + public string PlayerBuildVersion; + + /// + /// Settings used by the Addressables settings at the time of building + /// + public AddressablesEditorData AddressablesEditorSettings; + + /// + /// Values used by the Addressables runtime + /// + public AddressablesRuntimeData AddressablesRuntimeSettings; + + /// + /// Name of the build script to build + /// + public string BuildScript; + + /// + /// Default group at the time of building + /// + [SerializeReference] + public Group DefaultGroup; + + /// + /// The Addressable Groups that reference this data + /// + [SerializeReference] + public List Groups = new List(); + + /// + /// The List of AssetBundles that were built without a group associated to them, such as the BuiltIn Shaders Bundle and the MonoScript Bundle + /// + [SerializeReference] + public List BuiltInBundles = new List(); + + /// + /// List of assets with implicitly included Objects + /// + public List DuplicatedAssets = new List(); + + /// + /// The build path on disk of the default local content catalog + /// + [SerializeField] + internal string LocalCatalogBuildPath; + + /// + /// The build path of the remote content catalog, if one was built + /// + [SerializeField] + internal string RemoteCatalogBuildPath; + + internal string m_FilePath; + + private bool m_HeaderRead = false; + private bool m_BodyRead = false; + + private FileStream m_FileStream = null; + private StreamReader m_StreamReader = null; + + /// + /// Used for serialising the header info for the BuildLayout. + /// Names must match values in BuildLayout class + /// + [Serializable] + private class BuildLayoutHeader + { + public BuildTarget BuildTarget; + public string BuildResultHash; + public BuildType BuildType; + public string BuildStartTime; + public double Duration; + public string BuildError; + } + + /// + /// + /// + /// Path to the BuildLayout json file on disk + /// If the basic header information should be read + /// If the full build layout should be read + /// + public static BuildLayout Open(string path, bool readHeader = true, bool readFullFile = false) + { + if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) + { + Debug.LogError($"Invalid path provided : {path}"); + return null; + } + + BuildLayout readLayout = new BuildLayout + { + m_FilePath = path + }; + + if (readFullFile) + readLayout.ReadFull(); + else if (readHeader) + readLayout.ReadHeader(); + + return readLayout; + } + + /// + /// Writes json file for the build layout to the destination path + /// + /// File path to write build layout + /// If json should be written using pretty print + public void WriteToFile(string destinationPath, bool prettyPrint) + { + Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); + + string versionElementString = "\"UnityVersion\":"; + string headerJson = null; + string bodyJson = JsonUtility.ToJson(this, prettyPrint); + + if (prettyPrint) + { + BuildLayoutHeader header = new BuildLayoutHeader() + { + BuildTarget = this.BuildTarget, + BuildResultHash = this.BuildResultHash, + BuildType = this.BuildType, + BuildStartTime = this.BuildStartTime, + Duration = this.Duration, + BuildError = this.BuildError + }; + headerJson = JsonUtility.ToJson(header, false); + headerJson = headerJson.Remove(headerJson.Length - 1, 1) + ','; + } + + int index = bodyJson.IndexOf(versionElementString); + if (prettyPrint) + bodyJson = bodyJson.Remove(0, index); + else + bodyJson = bodyJson.Insert(index, "\n"); + + using (FileStream s = System.IO.File.Open(destinationPath, FileMode.Create)) + { + using (StreamWriter sw = new StreamWriter(s)) + { + if (prettyPrint) + sw.WriteLine(headerJson); + sw.Write(bodyJson); + } + } + } + + /// + /// Closes streams for loading the build layout + /// + public void Close() + { + if (m_StreamReader != null) + { + m_StreamReader.Close(); + m_StreamReader = null; + } + + if (m_FileStream != null) + { + m_FileStream.Close(); + m_FileStream = null; + } + } + + /// + /// Reads basic information about the build layout + /// + /// If false, the file will be closed after reading the header line. + /// true is successful, else false + public bool ReadHeader(bool keepFileStreamsActive = false) + { + if (m_HeaderRead) + return true; + + if (string.IsNullOrEmpty(m_FilePath)) + { + Debug.LogError("Cannot read BuildLayout header, A file has not been selected to open. Open must be called before reading any data"); + return false; + } + + try + { + if (m_FileStream == null) + { + m_FileStream = System.IO.File.Open(m_FilePath, FileMode.Open); + m_StreamReader = new StreamReader(m_FileStream); + } + + string fileJsonText = m_StreamReader.ReadLine(); + int lastComma = fileJsonText.LastIndexOf(','); + if (lastComma > 0) + { + fileJsonText = fileJsonText.Remove(lastComma) + '}'; + try + { + EditorJsonUtility.FromJsonOverwrite(fileJsonText, this); + } + catch (Exception e) + { + Debug.LogError($"Failed to read header for BuildLayout at {m_FilePath}, with exception: {e.Message}"); + return false; + } + } + else + { + Debug.LogError($"Failed to read header for BuildLayout at {m_FilePath}, invalid json format"); + return false; + } + + m_HeaderRead = true; + } + catch (Exception e) + { + Debug.LogException(e); + return false; + } + finally + { + if (!keepFileStreamsActive) + Close(); + } + + return true; + } + + /// + /// Reads the full build layout data from file + /// + /// true is successful, else false + public bool ReadFull() + { + if (m_BodyRead) + return true; + + if (string.IsNullOrEmpty(m_FilePath)) + { + Debug.LogError("Cannot read BuildLayout header, BuildLayout has not open for a file"); + return false; + } + + try + { + if (m_FileStream == null) + { + m_FileStream = System.IO.File.Open(m_FilePath, FileMode.Open); + m_StreamReader = new StreamReader(m_FileStream); + } + else if (m_HeaderRead) + { + // reset to read the whole file + m_FileStream.Position = 0; + m_StreamReader.DiscardBufferedData(); + } + + string fileJsonText = m_StreamReader.ReadToEnd(); + EditorJsonUtility.FromJsonOverwrite(fileJsonText, this); + m_HeaderRead = true; + m_BodyRead = true; + } + catch (Exception e) + { + Debug.LogError($"Failed to read header for BuildLayout at {m_FilePath}, with exception: {e.Message}"); + return false; + } + finally + { + Close(); + } + + return true; + } + + /// + /// Values set for the AddressablesAssetSettings at the time of building + /// + [Serializable] + public class AddressablesEditorData + { + /// + /// Hash value of the settings at the time of building + /// + public string SettingsHash; + + /// + /// Active Addressables profile set at time of Building + /// + public Profile ActiveProfile; + + /// + /// Addressables setting value set for building the remote catalog + /// + public bool BuildRemoteCatalog; + + /// + /// Load path for the remote catalog if enabled + /// + public string RemoteCatalogLoadPath; + + /// + /// Addressables setting value set for bundling the local catalog + /// + public bool BundleLocalCatalog; + + /// + /// Addressables setting value set for optimising the catalog size + /// + public bool OptimizeCatalogSize; + + /// + /// Addressables setting value set for time out when downloading catalogs + /// + public int CatalogRequestsTimeout; + + /// + /// Runtime setting value set for the maximum number of concurrent web requests + /// + public int MaxConcurrentWebRequests; + + /// + /// Addressables setting value set for is to update the remote catalog on startup + /// + public bool DisableCatalogUpdateOnStartup; + + /// + /// Addressables setting value set for if the build created unique bundle ids + /// + public bool UniqueBundleIds; + + /// + /// Addressables setting value set for if the build used non recursive dependency calculation + /// + public bool NonRecursiveBuilding; + + /// + /// Addressables setting value set for if the build used contiguous bundle objects + /// + public bool ContiguousBundles; + + /// + /// Addressables setting value set for disabling sub asset representation in the Bundle + /// + public bool DisableSubAssetRepresentations; + + /// + /// Internal naming prefix of the built in shaders bundle + /// + public string ShaderBundleNaming; + + /// + /// Internal naming prefix of the monoScript bundle, + /// No MonoScript bundle is built if set to disabled + /// + public string MonoScriptBundleNaming; + + /// + /// Addressables setting value set for is the unity version was stripped from the built bundles + /// + public bool StripUnityVersionFromBundleBuild; + } + + /// + /// Values set for runtime initialisation of Addressables + /// + [Serializable] + public class AddressablesRuntimeData + { + /// + /// Runtime setting value set for if the runtime will submit profiler events + /// + public bool ProfilerEvents; + + /// + /// Runtime setting value set for if resource manager exceptions are logged or not + /// + public bool LogResourceManagerExceptions; + + /// + /// Runtime setting value set for catalogs to load (First catalog found in the list is used) + /// + public List CatalogLoadPaths = new List(); + + /// + /// Hash of the build catalog + /// + public string CatalogHash; + } + + /// + /// Information about the AssetBundleObject + /// + [Serializable] + public class AssetBundleObjectInfo + { + /// + /// The size, in bytes, of the AssetBundleObject + /// + public ulong Size; + } + + /// + /// Key value pair of string type + /// + [Serializable] + public struct StringPair + { + /// + /// String key + /// + public string Key; + + /// + /// String value + /// + public string Value; + } + + /// + /// Addressables Profile data + /// + [Serializable] + public class Profile + { + /// + /// Name of the profile + /// + public string Name; + + /// + /// ID assigned within the ProfileSettings of the profile + /// + public string Id; + + /// + /// Profile variables assigned to the profile + /// + public StringPair[] Values; + } + + /// + /// Data about the AddressableAssetGroup that gets processed during a build. + /// + [Serializable] + public class Group + { + /// + /// The Name of the AdressableAssetGroup + /// + public string Name; + + /// + /// The Guid of the AddressableAssetGroup + /// + public string Guid; + + /// + /// The packing mode as defined by the BundledAssetGroupSchema on the AddressableAssetGroup + /// + public string PackingMode; + + /// + /// A list of the AssetBundles associated with the Group + /// + [SerializeReference] + public List Bundles = new List(); + + /// + /// Data about the AddressableAssetGroupSchemas associated with the Group + /// + [SerializeReference] + public List Schemas = new List(); + } + + /// + /// Data container for AddressableAssetGroupSchemas + /// + [Serializable] + public class SchemaData : ISerializationCallbackReceiver + { + /// + /// The Guid of the AddressableAssetGroupSchema + /// + public string Guid; + + /// + /// The class type of the AddressableAssetGroupSchema + /// + public string Type; + + /// + /// These key-value-pairs include data about the AddressableAssetGroupSchema, such as PackingMode and Compression. + /// + public List> KvpDetails = new List>(); + + [SerializeField] + private StringPair[] SchemaDataPairs; + + /// + /// Converts the unserializable KvpDetails to a serializable type for writing + /// + public void OnBeforeSerialize() + { + SchemaDataPairs = new StringPair[KvpDetails.Count]; + for (int i = 0; i < SchemaDataPairs.Length; ++i) + SchemaDataPairs[i] = new StringPair() {Key = KvpDetails[i].Item1, Value = KvpDetails[i].Item2}; + } + + /// + /// Writes data to KvpDetails after Deserializing to temporary data fields + /// + public void OnAfterDeserialize() + { + for (int i = 0; i < SchemaDataPairs.Length; ++i) + KvpDetails.Add(new Tuple(SchemaDataPairs[i].Key, SchemaDataPairs[i].Value)); + SchemaDataPairs = null; + } + } + + /// + /// Data store for AssetBundle information. + /// + [Serializable] + public class Bundle + { + /// + /// The name of the AssetBundle + /// + public string Name; + + /// + /// Name used to identify the asset bundle + /// + public string InternalName; + + /// + /// The file size of the AssetBundle on disk, in bytes + /// + public ulong FileSize; + + /// + /// Status of the bundle after an update build + /// + public BundleBuildStatus BuildStatus; + + /// + /// The file size of all of the Expanded Dependencies of this AssetBundle, in bytes + /// Expanded dependencies are the dependencies of this AssetBundle's dependencies + /// + public ulong ExpandedDependencyFileSize; + + /// + /// The file size + /// + public ulong DependencyFileSize; + + /// + /// The file size of the AssetBundle on disk when uncompressed, in bytes + /// + public ulong UncompressedFileSize + { + get + { + ulong total = 0; + foreach (File file in Files) + total += file.UncompressedSize; + return total; + } + } + + /// + /// The number of Assets contained within the bundle + /// + public int AssetCount = 0; + + /// + /// Represents a dependency from the containing Bundle to dependentBundle, with AssetDependencies representing each of the assets in parentBundle that create the link to dependentBundle + /// + [Serializable] + public class BundleDependency + { + /// + /// The bundle that the parent bundle depends on + /// + [SerializeReference] + public Bundle DependencyBundle; + + /// + /// The list of assets that link the parent bundle to the DependencyBundle + /// + public List AssetDependencies; + + /// + /// Percentage of Efficiency asset usage that uses the entire dependency tree of this bundle dependency. + /// This includes DependencyBundle and all bundles beneath it. + /// Value is equal to [Total Filesize of Dependency Assets] / [Total size of all dependency bundles on disk] + /// Example: There are 3 bundles A, B, and C, that are each 10 MB on disk. A depends on 2 MB worth of assets in B, and B depends on 4 MB worth of assets in C. + /// The Efficiency of the dependencyLink from A->B would be 2/10 -> 20% and the ExpandedEfficiency of A->B would be (2 + 4)/(10 + 10) -> 6/20 -> 30% + /// + public float ExpandedEfficiency; + + /// + /// The Efficiency of the connection between the parent bundle and DependencyBundle irrespective of the full dependency tree below DependencyBundle. + /// Value is equal to [Serialized Filesize of assets In Dependency Bundle Referenced By Parent]/[Total size of Dependency Bundle on disk] + /// Example: Given two Bundles A and B that are each 10 MB on disk, and A depends on 5 MB worth of assets in B, then the Efficiency of DependencyLink A->B is 5/10 = .5 + /// + public float Efficiency; + + private HashSet referencedAssets = new HashSet(); + + /// + /// The number of uniquely assets that the parent bundle uniquely references in dependency bundle. This is used to calculate Efficiency without double counting. + /// + internal ulong referencedAssetsFileSize = 0; + + internal BundleDependency(Bundle b) + { + DependencyBundle = b; + AssetDependencies = new List(); + } + + internal void CreateAssetDependency(ExplicitAsset root, ExplicitAsset dependencyAsset) + { + if (referencedAssets.Contains(dependencyAsset)) + return; + referencedAssets.Add(dependencyAsset); + AssetDependencies.Add(new AssetDependency(root, dependencyAsset)); + referencedAssetsFileSize += dependencyAsset.SerializedSize; + } + + + /// + /// Represents a dependency from a root Asset to a dependent Asset. + /// + [Serializable] + public struct AssetDependency + { + [SerializeReference] + internal ExplicitAsset rootAsset; + + [SerializeReference] + internal ExplicitAsset dependencyAsset; + + internal AssetDependency(ExplicitAsset root, ExplicitAsset depAsset) + { + rootAsset = root; + dependencyAsset = depAsset; + } + } + } + + internal Dictionary BundleDependencyMap = new Dictionary(); + + /// + /// A list of bundles that this bundle depends upon. + /// + [SerializeField] + public BundleDependency[] BundleDependencies = Array.Empty(); + + + /// + /// Convert BundleDependencyMap to a format that is able to be serialized and plays nicer with + /// CalculateEfficiency - this must be called on a bundle before CalculateEfficiency can be called. + /// + internal void SerializeBundleToBundleDependency() + { + BundleDependencies = new BundleDependency[BundleDependencyMap.Values.Count]; + BundleDependencyMap.Values.CopyTo(BundleDependencies, 0); + } + + /// + /// Updates the BundleDependency from the current bundle to the bundle that contains referencedAsset. If no such BundleDependency exists, + /// one is created. Does nothing if rootAsset's bundle is not the current bundle or + /// if the two assets are in the same bundle. + /// + /// + /// + internal void UpdateBundleDependency(ExplicitAsset rootAsset, ExplicitAsset referencedAsset) + { + if (rootAsset.Bundle != this || referencedAsset.Bundle == rootAsset.Bundle) + return; + + if (!BundleDependencyMap.ContainsKey(referencedAsset.Bundle)) + BundleDependencyMap.Add(referencedAsset.Bundle, new BundleDependency(referencedAsset.Bundle)); + BundleDependencyMap[referencedAsset.Bundle].CreateAssetDependency(rootAsset, referencedAsset); + } + + // Helper struct for calculating Efficiency + internal struct EfficiencyInfo + { + internal ulong totalAssetFileSize; + internal ulong referencedAssetFileSize; + } + + + /// + /// The Compression method used for the AssetBundle. + /// + public string Compression; + + /// + /// Cyclic redundancy check of the content contained inside of the asset bundle. + /// This value will not change between identical asset bundles with different compression options. + /// + public uint CRC; + + /// + /// The hash version of the contents contained inside of the asset bundle. + /// This value will not change between identical asset bundles with different compression options. + /// + public Hash128 Hash; + + /// + /// A reference to the Group data that this AssetBundle was generated from + /// + [SerializeReference] + public Group Group; + + /// + /// Path Provider uses to load the Asset Bundle + /// + public string LoadPath; + + /// + /// Provider used to load the Asset Bundle + /// + public string Provider; + + /// + /// Result provided by the Provider loading the Asset Bundle + /// + public string ResultType; + + /// + /// List of the Files referenced by the AssetBundle + /// + [SerializeReference] + public List Files = new List(); + + /// + /// A list of the bundles that directly depend on this AssetBundle + /// + [SerializeReference] + public List DependentBundles = new List(); + + /// + /// A list of the direct dependencies of the AssetBundle + /// + [SerializeReference] + public List Dependencies; + + /// + /// The second order dependencies and greater of a bundle + /// + [SerializeReference] + public List ExpandedDependencies; + } + + /// + /// Data store for resource files generated by the build pipeline and referenced by a main File + /// + [Serializable] + public class SubFile + { + /// + /// The name of the sub-file + /// + public string Name; + + /// + /// If the main File is a serialized file, this will be true. + /// + public bool IsSerializedFile; + + /// + /// The size of the sub-file, in bytes + /// + public ulong Size; + } + + /// + /// Data store for the main File created for the AssetBundle + /// + [Serializable] + public class File + { + /// + /// The name of the File. + /// + public string Name; + + /// + /// The AssetBundle data that relates to a built file. + /// + [SerializeReference] + public Bundle Bundle; + + /// + /// The file size of the AssetBundle on disk when uncompressed, in bytes + /// + public ulong UncompressedSize + { + get + { + ulong total = 0; + foreach (SubFile subFile in SubFiles) + total += subFile.Size; + return total; + } + } + + /// + /// List of the resource files created by the build pipeline that a File references + /// + [SerializeReference] + public List SubFiles = new List(); + + /// + /// A list of the explicit asset defined in the AssetBundle + /// + [SerializeReference] + public List Assets = new List(); + + /// + /// A list of implicit assets built into the AssetBundle, typically through references by Assets that are explicitly defined. + /// + [SerializeReference] + public List OtherAssets = new List(); + + [SerializeReference] + internal List ExternalReferences = new List(); + + /// + /// The final filename of the AssetBundle file + /// + public string WriteResultFilename; + + /// + /// Data about the AssetBundleObject + /// + public AssetBundleObjectInfo BundleObjectInfo; + + /// + /// The size of the data that needs to be preloaded for this File. + /// + public int PreloadInfoSize; + + /// + /// The number of Mono scripts referenced by the File + /// + public int MonoScriptCount; + + /// + /// The size of the Mono scripts referenced by the File + /// + public ulong MonoScriptSize; + } + + /// + /// A representation of an object in an asset file. + /// + [Serializable] + public class ObjectData + { + /// + /// FileId of Object in Asset File + /// + public long LocalIdentifierInFile; + + /// + /// Object name within the Asset + /// + [SerializeField] internal string ObjectName; + + /// + /// Component name if AssetType is a MonoBehaviour or Component + /// + [SerializeField] internal string ComponentName; + + /// + /// Type of Object + /// + public AssetType AssetType; + + /// + /// The size of the file on disk. + /// + public ulong SerializedSize; + + /// + /// The size of the streamed Asset. + /// + public ulong StreamedSize; + + /// + /// References to other Objects + /// + [SerializeField] internal List References = new List(); + } + + /// + /// Identification of an Object within the same file + /// + [Serializable] + internal class ObjectReference + { + public int AssetId; + public List ObjectIds; + } + + /// + /// Data store for Assets explicitly defined in an AssetBundle + /// + [Serializable] + public class ExplicitAsset + { + /// + /// The Asset Guid. + /// + public string Guid; + + /// + /// The Asset path on disk + /// + public string AssetPath; + + /// + /// Name used to identify the asset within the asset bundle containing it + /// + public string InternalId; + + /// + /// Hash of the asset content + /// + public Hash128 AssetHash; + + /// + /// Objects that consist of the overall asset + /// + public List Objects = new List(); + + /// + /// AssetType of the main Object for the Asset + /// + public AssetType MainAssetType; + + /// + /// True if is a scene asset, else false + /// + public bool IsScene => AssetPath.EndsWith(".unity", StringComparison.Ordinal); + + /// + /// Guid of the Addressable group this Asset entry was built using. + /// + public string GroupGuid; + + /// + /// The Addressable address defined in the Addressable Group window for an Asset. + /// + public string AddressableName; + + /// + /// Addressable labels for this asset entry. + /// + [SerializeField] + public string[] Labels = Array.Empty(); + + /// + /// The size of the file on disk. + /// + public ulong SerializedSize; + + /// + /// The size of the streamed Asset. + /// + public ulong StreamedSize; + + /// + /// The file that the Asset was added to + /// + [SerializeReference] + public File File; + + /// + /// The AssetBundle that contains the asset + /// + [SerializeReference] + public Bundle Bundle; + + /// + /// List of data from other Assets referenced by an Asset in the File + /// + [SerializeReference] + public List InternalReferencedOtherAssets = new List(); + + /// + /// List of explicit Assets referenced by this asset that are in the same AssetBundle + /// + [SerializeReference] + public List InternalReferencedExplicitAssets = new List(); + + /// + /// List of explicit Assets referenced by this asset that are in a different AssetBundle + /// + [SerializeReference] + public List ExternallyReferencedAssets = new List(); + + /// + /// List of Assets that reference this Asset + /// + [SerializeReference] + internal List ReferencingAssets = new List(); + } + + /// + /// Data store for implicit Asset references + /// + [Serializable] + public class DataFromOtherAsset + { + /// + /// The Guid of the Asset + /// + public string AssetGuid; + + /// + /// The Asset path on disk + /// + public string AssetPath; + + /// + /// The file that the Asset was added to + /// + [SerializeReference] + public File File; + + /// + /// Objects that consist of the overall asset + /// + public List Objects = new List(); + + /// + /// AssetType of the main Object for the Asset + /// + public AssetType MainAssetType; + + /// + /// True if is a scene asset, else false + /// + public bool IsScene => AssetPath.EndsWith(".unity", StringComparison.Ordinal); + + /// + /// A list of Assets that reference this data + /// + [SerializeReference] + public List ReferencingAssets = new List(); + + /// + /// The number of Objects in the data + /// + public int ObjectCount; + + /// + /// The size of the data on disk + /// + public ulong SerializedSize; + + /// + /// The size of the streamed data + /// + public ulong StreamedSize; + } + + /// + /// Data store for duplicated Implicit Asset information + /// + [Serializable] + public class AssetDuplicationData + { + /// + /// The Guid of the Asset with duplicates + /// + public string AssetGuid; + /// + /// A list of duplicated objects and the bundles that contain them. + /// + public List DuplicatedObjects = new List(); + } + + /// + /// Data store for duplicated Object information + /// + [Serializable] + public class ObjectDuplicationData + { + /// + /// The local identifier for an object. + /// + public long LocalIdentifierInFile; + /// + /// A list of bundles that include the referenced file. + /// + [SerializeReference] public List IncludedInBundleFiles = new List(); + } + } + + /// + /// Utility used to quickly reference data built with the build pipeline + /// + public class LayoutLookupTables + { + /// + /// The default AssetBundle name to the Bundle data map. + /// + public Dictionary Bundles = new Dictionary(); + + /// + /// File name to File data map. + /// + public Dictionary Files = new Dictionary(); + + internal Dictionary FileToFileObjectData = new Dictionary(); + + /// + /// Guid to ExplicitAsset data map. + /// + public Dictionary GuidToExplicitAsset = new Dictionary(); + + /// + /// Group name to Group data map. + /// + public Dictionary GroupLookup = new Dictionary(); + + /// + /// The remapped AssetBundle name to the Bundle data map + /// + internal Dictionary FilenameToBundle = new Dictionary(); + + + /// Maps used for lookups while building the BuildLayout + internal Dictionary> UsedImplicits = new Dictionary>(); + + internal Dictionary BundleNameToRequestOptions = new Dictionary(); + + internal Dictionary BundleNameToPreviousRequestOptions = new Dictionary(); + + internal Dictionary BundleNameToCatalogEntry = new Dictionary(); + + internal Dictionary GroupNameToBuildPath = new Dictionary(); + + internal Dictionary GuidToEntry = new Dictionary(); + internal Dictionary AssetPathToTypeMap = new Dictionary(); + } + + internal class FileObjectData + { + // id's for internal explicit asset and implicit asset + public Dictionary InternalObjectIds = new Dictionary(); + + public Dictionary Objects = new Dictionary(); + + public void Add(ObjectIdentifier buildObjectIdentifier, BuildLayout.ObjectData layoutObject, int assetId, int objectIndex) + { + InternalObjectIds[buildObjectIdentifier] = (assetId, objectIndex); + Objects[layoutObject] = buildObjectIdentifier; + } + + public bool TryGetObjectReferenceData(ObjectIdentifier obj, out (int, int) value) + { + if (!InternalObjectIds.TryGetValue(obj, out (int, int) data)) + { + value = default; + return false; + } + + value = data; + return true; + } + + public bool TryGetObjectIdentifier(BuildLayout.ObjectData obj, out ObjectIdentifier objectIdOut) + { + if (!Objects.TryGetValue(obj, out objectIdOut)) + { + objectIdOut = default; + return false; + } + + return true; + } + } +} diff --git a/Editor/Build/Layout/BuildLayout.cs.meta b/Editor/Build/Layout/BuildLayout.cs.meta index 8e1d8393..1eca3408 100644 --- a/Editor/Build/Layout/BuildLayout.cs.meta +++ b/Editor/Build/Layout/BuildLayout.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: a4c1f91c2b38c564e9e4ab0c5ff1ac1a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: a4c1f91c2b38c564e9e4ab0c5ff1ac1a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Layout/BuildLayoutEnums.cs b/Editor/Build/Layout/BuildLayoutEnums.cs index 8b2de132..b8287f2f 100644 --- a/Editor/Build/Layout/BuildLayoutEnums.cs +++ b/Editor/Build/Layout/BuildLayoutEnums.cs @@ -1,274 +1,274 @@ -namespace UnityEditor.AddressableAssets.Build.Layout -{ - /// - /// UnityEngine Object types found as Assets - /// - public enum AssetType - { - /// - /// Unknown type that is not handled - /// - Other = 0, - - // Other - /// - /// Font asset - /// - Font, - - /// - /// GUISkin asset - /// - GUISkin, - - // Animation - /// - /// AnimationClip, often a subObject of a Model asset - /// - AnimationClip, - - /// - /// Avatar asset - /// - Avatar, - - /// - /// AnimationController asset - /// - AnimationController, - - // Audio - /// - /// AudioClip asset - /// - AudioClip, - - /// - /// AudioMixer asset - /// - AudioMixer, - - // Video - /// - /// Video asset - /// - VideoClip, - - // Shader - /// - /// Shader asset - /// - Shader, - - /// - /// ComputeShader asset - /// - ComputeShader, - - // Mesh - /// - /// Mesh, often a subObject of a model asset - /// - Mesh, - - // Texture - /// - /// Generic Texture asset - /// - Texture, - - /// - /// 2D image texture asset - /// - Texture2D, - - /// - /// Texture3D asset - /// - Texture3D, - - /// - /// Sprite Object, often a subObject to a Texture or SpriteAtlas - /// - Sprite, - - // Scriptable Object - /// - /// ScriptableObject asset - /// - ScriptableObject, - - // Prefab - /// - /// Prefab asset - /// - Prefab, - - /// - /// Special prefab type for Imported model assets - /// - Model, - - // Material - /// - /// Rendering Material asset - /// - Material, - - /// - /// PhysicsMaterial asset - /// - PhysicsMaterial, - - /// - /// PhysicalMaterial2D asset - /// - PhysicsMaterial2D, - - // Other Assets - /// - /// TextAsset - /// - TextAsset, - - // Scene - /// - /// Scene asset - /// - Scene, - - // Serialize Content -> combined into Scene, Prefab, Scriptable Object - /// - /// GameObject, can be a Prefab or Scene subObject - /// - GameObject, - - /// - /// Generic Scene Object that has an undefined AssetType - /// - SceneObject, - - /// - /// MonoBehaviour scripts - /// - MonoBehaviour, - - /// - /// Components on a GameObject not of MonoBehaviour type - /// - Component, - - /// - /// MonoScript object - /// - MonoScript, - - // Scene Objects that are parsed from string by the scene object type path - /// - /// Cubemap scene Object - /// - Cubemap, - - /// - /// Scene Camera component - /// - Camera, - - /// - /// Scene AudioListener component - /// - AudioListener, - - /// - /// Scene Light component - /// - Light, - - /// - /// Scene NavMeshSettings Object - /// - NavMeshSettings, - - /// - /// Scene RenderSettings Object - /// - RenderSettings, - - /// - /// Scene LightmapSettings Object - /// - LightmapSettings, - - /// - /// Scene Transform component - /// - Transform, - - /// - /// Scene MeshRenderer component - /// - MeshRenderer, - - /// - /// Scene MeshFilter component - /// - MeshFilter, - - /// - /// Scene BoxCollider2D component - /// - BoxCollider2D, - - /// - /// Scene BoxCollider component - /// - BoxCollider, - - /// - /// Scene SphereCollider component - /// - SphereCollider, - } - - /// - /// Type of Addressables build - /// - public enum BuildType - { - /// - /// Was made with an Addressables build made for new Player builds - /// - NewBuild = 0, - - /// - /// Was made with an Addressables update build, for a previous new build - /// - UpdateBuild - } - - /// - /// Bundle status after an update build - /// - public enum BundleBuildStatus - { - /// - /// Asset bundle is newly created for this build - /// - New = 0, - - /// - /// Asset bundle has been modified (Remote bundle expected) - /// - Modified, - - /// - /// Prevent updates, updated Asset bundle has been modified and reverted to previous details - /// - ModifiedUpdatePrevented, - - /// - /// Asset bundle was not modified and data remains the same - /// - Unmodified - } -} +namespace UnityEditor.AddressableAssets.Build.Layout +{ + /// + /// UnityEngine Object types found as Assets + /// + public enum AssetType + { + /// + /// Unknown type that is not handled + /// + Other = 0, + + // Other + /// + /// Font asset + /// + Font, + + /// + /// GUISkin asset + /// + GUISkin, + + // Animation + /// + /// AnimationClip, often a subObject of a Model asset + /// + AnimationClip, + + /// + /// Avatar asset + /// + Avatar, + + /// + /// AnimationController asset + /// + AnimationController, + + // Audio + /// + /// AudioClip asset + /// + AudioClip, + + /// + /// AudioMixer asset + /// + AudioMixer, + + // Video + /// + /// Video asset + /// + VideoClip, + + // Shader + /// + /// Shader asset + /// + Shader, + + /// + /// ComputeShader asset + /// + ComputeShader, + + // Mesh + /// + /// Mesh, often a subObject of a model asset + /// + Mesh, + + // Texture + /// + /// Generic Texture asset + /// + Texture, + + /// + /// 2D image texture asset + /// + Texture2D, + + /// + /// Texture3D asset + /// + Texture3D, + + /// + /// Sprite Object, often a subObject to a Texture or SpriteAtlas + /// + Sprite, + + // Scriptable Object + /// + /// ScriptableObject asset + /// + ScriptableObject, + + // Prefab + /// + /// Prefab asset + /// + Prefab, + + /// + /// Special prefab type for Imported model assets + /// + Model, + + // Material + /// + /// Rendering Material asset + /// + Material, + + /// + /// PhysicsMaterial asset + /// + PhysicsMaterial, + + /// + /// PhysicalMaterial2D asset + /// + PhysicsMaterial2D, + + // Other Assets + /// + /// TextAsset + /// + TextAsset, + + // Scene + /// + /// Scene asset + /// + Scene, + + // Serialize Content -> combined into Scene, Prefab, Scriptable Object + /// + /// GameObject, can be a Prefab or Scene subObject + /// + GameObject, + + /// + /// Generic Scene Object that has an undefined AssetType + /// + SceneObject, + + /// + /// MonoBehaviour scripts + /// + MonoBehaviour, + + /// + /// Components on a GameObject not of MonoBehaviour type + /// + Component, + + /// + /// MonoScript object + /// + MonoScript, + + // Scene Objects that are parsed from string by the scene object type path + /// + /// Cubemap scene Object + /// + Cubemap, + + /// + /// Scene Camera component + /// + Camera, + + /// + /// Scene AudioListener component + /// + AudioListener, + + /// + /// Scene Light component + /// + Light, + + /// + /// Scene NavMeshSettings Object + /// + NavMeshSettings, + + /// + /// Scene RenderSettings Object + /// + RenderSettings, + + /// + /// Scene LightmapSettings Object + /// + LightmapSettings, + + /// + /// Scene Transform component + /// + Transform, + + /// + /// Scene MeshRenderer component + /// + MeshRenderer, + + /// + /// Scene MeshFilter component + /// + MeshFilter, + + /// + /// Scene BoxCollider2D component + /// + BoxCollider2D, + + /// + /// Scene BoxCollider component + /// + BoxCollider, + + /// + /// Scene SphereCollider component + /// + SphereCollider, + } + + /// + /// Type of Addressables build + /// + public enum BuildType + { + /// + /// Was made with an Addressables build made for new Player builds + /// + NewBuild = 0, + + /// + /// Was made with an Addressables update build, for a previous new build + /// + UpdateBuild + } + + /// + /// Bundle status after an update build + /// + public enum BundleBuildStatus + { + /// + /// Asset bundle is newly created for this build + /// + New = 0, + + /// + /// Asset bundle has been modified (Remote bundle expected) + /// + Modified, + + /// + /// Prevent updates, updated Asset bundle has been modified and reverted to previous details + /// + ModifiedUpdatePrevented, + + /// + /// Asset bundle was not modified and data remains the same + /// + Unmodified + } +} diff --git a/Editor/Build/Layout/BuildLayoutEnums.cs.meta b/Editor/Build/Layout/BuildLayoutEnums.cs.meta index 5c927325..b81cd9ff 100644 --- a/Editor/Build/Layout/BuildLayoutEnums.cs.meta +++ b/Editor/Build/Layout/BuildLayoutEnums.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 1d660cd53240140bd9d3975354f1fae0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 1d660cd53240140bd9d3975354f1fae0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Layout/BuildLayoutHelpers.cs b/Editor/Build/Layout/BuildLayoutHelpers.cs index 071e6568..d1275dea 100644 --- a/Editor/Build/Layout/BuildLayoutHelpers.cs +++ b/Editor/Build/Layout/BuildLayoutHelpers.cs @@ -1,153 +1,153 @@ -using System.Collections; -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEditor.AddressableAssets.Settings; -using UnityEngine; - -namespace UnityEditor.AddressableAssets.Build.Layout -{ - /// - /// Helper methods for gathering data about a build layout. - /// - public class BuildLayoutHelpers - { - /// - /// Gather a list of Explicit Assets defined in a BuildLayout - /// - /// The BuildLayout generated during a build - /// A list of ExplicitAsset data. - public static IEnumerable EnumerateAssets(BuildLayout layout) - { - return EnumerateBundles(layout).SelectMany(b => b.Files).SelectMany(f => f.Assets); - } - - internal static IEnumerable EnumerateImplicitAssets(BuildLayout layout) - { - return EnumerateBundles(layout).SelectMany(b => b.Files).SelectMany(f => f.Assets).SelectMany(a => a.InternalReferencedOtherAssets); - } - - internal static IEnumerable EnumerateImplicitAssets(BuildLayout.Bundle bundle) - { - return bundle.Files.SelectMany(f => f.OtherAssets); - } - - /// - /// Gather a list of Explicit Assets defined in a Bundle - /// - /// The Bundle data generated during a build - /// A list of ExplicitAssets defined in the Bundle - public static IEnumerable EnumerateAssets(BuildLayout.Bundle bundle) - { - return bundle.Files.SelectMany(f => f.Assets); - } - - /// - /// Gather a list of Bundle data defined in a BuildLayout - /// - /// The BuildLayout generated during a build - /// A list of the Bundle data defined in a BuildLayout - public static IEnumerable EnumerateBundles(BuildLayout layout) - { - foreach (BuildLayout.Bundle b in layout.BuiltInBundles) - yield return b; - - foreach (BuildLayout.Bundle b in layout.Groups.SelectMany(g => g.Bundles)) - yield return b; - } - - /// - /// Gather a list of File data defined in a BuildLayout - /// - /// The BuildLayout generated during a build - /// A list of File data - public static IEnumerable EnumerateFiles(BuildLayout layout) - { - return EnumerateBundles(layout).SelectMany(b => b.Files); - } - - private static Dictionary m_SystemTypeToAssetType = null; - private static Dictionary SystemTypeToAssetType - { - get - { - if (m_SystemTypeToAssetType == null) - { - m_SystemTypeToAssetType = new Dictionary() - { - { typeof(SceneAsset), AssetType.Scene } - }; - } - return m_SystemTypeToAssetType; - } - } - - private static List<(System.Type, AssetType)> m_AssignableSystemTypeToAssetType = null; - private static List<(System.Type, AssetType)> AssignableSystemTypeToAssetType - { - get - { - if (m_AssignableSystemTypeToAssetType == null) - { - m_AssignableSystemTypeToAssetType = new List<(Type, AssetType)>() - { - (typeof(ScriptableObject), AssetType.ScriptableObject), - (typeof(MonoBehaviour), AssetType.MonoBehaviour), - (typeof(Component), AssetType.Component) - }; - } - return m_AssignableSystemTypeToAssetType; - } - } - - private static Dictionary m_RuntimeSystemTypeToAssetType = null; - private static Dictionary RuntimeSystemTypeToAssetType - { - get - { - if (m_RuntimeSystemTypeToAssetType == null) - { - m_RuntimeSystemTypeToAssetType = new Dictionary() - { - { typeof(RuntimeAnimatorController), AssetType.AnimationController } - }; - } - return m_RuntimeSystemTypeToAssetType; - } - } - - /// - /// Gets the enum AssetType associated with the param systemType ofType - /// - /// The Type of the asset - /// An AssetType or if null or unknown. - public static AssetType GetAssetType(Type ofType) - { - if (ofType == null) - return AssetType.Other; - - if (AssetType.TryParse(ofType.Name, out AssetType assetType)) - return assetType; - - // types where the class name doesn't equal the AssetType (legacy enum values) - if (SystemTypeToAssetType.TryGetValue(ofType, out assetType)) - return assetType; - - foreach ((Type, AssetType) typeAssignment in AssignableSystemTypeToAssetType) - { - if (typeAssignment.Item1.IsAssignableFrom(ofType)) - return typeAssignment.Item2; - } - - ofType = AddressableAssetUtility.MapEditorTypeToRuntimeType(ofType, false); - if (ofType == null) - return AssetType.Other; - if (SystemTypeToAssetType.TryGetValue(ofType, out assetType)) - return assetType; - if (RuntimeSystemTypeToAssetType.TryGetValue(ofType, out assetType)) - return assetType; - - return AssetType.Other; - } - } -} +using System.Collections; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.AddressableAssets.Settings; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build.Layout +{ + /// + /// Helper methods for gathering data about a build layout. + /// + public class BuildLayoutHelpers + { + /// + /// Gather a list of Explicit Assets defined in a BuildLayout + /// + /// The BuildLayout generated during a build + /// A list of ExplicitAsset data. + public static IEnumerable EnumerateAssets(BuildLayout layout) + { + return EnumerateBundles(layout).SelectMany(b => b.Files).SelectMany(f => f.Assets); + } + + internal static IEnumerable EnumerateImplicitAssets(BuildLayout layout) + { + return EnumerateBundles(layout).SelectMany(b => b.Files).SelectMany(f => f.Assets).SelectMany(a => a.InternalReferencedOtherAssets); + } + + internal static IEnumerable EnumerateImplicitAssets(BuildLayout.Bundle bundle) + { + return bundle.Files.SelectMany(f => f.OtherAssets); + } + + /// + /// Gather a list of Explicit Assets defined in a Bundle + /// + /// The Bundle data generated during a build + /// A list of ExplicitAssets defined in the Bundle + public static IEnumerable EnumerateAssets(BuildLayout.Bundle bundle) + { + return bundle.Files.SelectMany(f => f.Assets); + } + + /// + /// Gather a list of Bundle data defined in a BuildLayout + /// + /// The BuildLayout generated during a build + /// A list of the Bundle data defined in a BuildLayout + public static IEnumerable EnumerateBundles(BuildLayout layout) + { + foreach (BuildLayout.Bundle b in layout.BuiltInBundles) + yield return b; + + foreach (BuildLayout.Bundle b in layout.Groups.SelectMany(g => g.Bundles)) + yield return b; + } + + /// + /// Gather a list of File data defined in a BuildLayout + /// + /// The BuildLayout generated during a build + /// A list of File data + public static IEnumerable EnumerateFiles(BuildLayout layout) + { + return EnumerateBundles(layout).SelectMany(b => b.Files); + } + + private static Dictionary m_SystemTypeToAssetType = null; + private static Dictionary SystemTypeToAssetType + { + get + { + if (m_SystemTypeToAssetType == null) + { + m_SystemTypeToAssetType = new Dictionary() + { + { typeof(SceneAsset), AssetType.Scene } + }; + } + return m_SystemTypeToAssetType; + } + } + + private static List<(System.Type, AssetType)> m_AssignableSystemTypeToAssetType = null; + private static List<(System.Type, AssetType)> AssignableSystemTypeToAssetType + { + get + { + if (m_AssignableSystemTypeToAssetType == null) + { + m_AssignableSystemTypeToAssetType = new List<(Type, AssetType)>() + { + (typeof(ScriptableObject), AssetType.ScriptableObject), + (typeof(MonoBehaviour), AssetType.MonoBehaviour), + (typeof(Component), AssetType.Component) + }; + } + return m_AssignableSystemTypeToAssetType; + } + } + + private static Dictionary m_RuntimeSystemTypeToAssetType = null; + private static Dictionary RuntimeSystemTypeToAssetType + { + get + { + if (m_RuntimeSystemTypeToAssetType == null) + { + m_RuntimeSystemTypeToAssetType = new Dictionary() + { + { typeof(RuntimeAnimatorController), AssetType.AnimationController } + }; + } + return m_RuntimeSystemTypeToAssetType; + } + } + + /// + /// Gets the enum AssetType associated with the param systemType ofType + /// + /// The Type of the asset + /// An AssetType or if null or unknown. + public static AssetType GetAssetType(Type ofType) + { + if (ofType == null) + return AssetType.Other; + + if (AssetType.TryParse(ofType.Name, out AssetType assetType)) + return assetType; + + // types where the class name doesn't equal the AssetType (legacy enum values) + if (SystemTypeToAssetType.TryGetValue(ofType, out assetType)) + return assetType; + + foreach ((Type, AssetType) typeAssignment in AssignableSystemTypeToAssetType) + { + if (typeAssignment.Item1.IsAssignableFrom(ofType)) + return typeAssignment.Item2; + } + + ofType = AddressableAssetUtility.MapEditorTypeToRuntimeType(ofType, false); + if (ofType == null) + return AssetType.Other; + if (SystemTypeToAssetType.TryGetValue(ofType, out assetType)) + return assetType; + if (RuntimeSystemTypeToAssetType.TryGetValue(ofType, out assetType)) + return assetType; + + return AssetType.Other; + } + } +} diff --git a/Editor/Build/Layout/BuildLayoutHelpers.cs.meta b/Editor/Build/Layout/BuildLayoutHelpers.cs.meta index 8c4896a2..80a1760d 100644 --- a/Editor/Build/Layout/BuildLayoutHelpers.cs.meta +++ b/Editor/Build/Layout/BuildLayoutHelpers.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: ac62285cba7c64612b59f2c0c4124c96 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: ac62285cba7c64612b59f2c0c4124c96 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Layout/BuildLayoutPrinter.cs b/Editor/Build/Layout/BuildLayoutPrinter.cs index ee9a8933..54051486 100644 --- a/Editor/Build/Layout/BuildLayoutPrinter.cs +++ b/Editor/Build/Layout/BuildLayoutPrinter.cs @@ -1,283 +1,283 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEngine; - -namespace UnityEditor.AddressableAssets.Build.Layout -{ - class BuildLayoutPrinter - { - static public string GetFriendlySize(ulong byteSize) - { - string[] sizes = {"B", "KB", "MB", "GB", "TB"}; - int order = 0; - ulong prevOrderRemainder = 0; - while (byteSize >= 1024 && order < sizes.Length - 1) - { - order++; - prevOrderRemainder = byteSize % 1024; - byteSize = byteSize / 1024; - } - - double byteSizeFloat = (double)byteSize + (double)prevOrderRemainder / 1024; - - string result = String.Format("{0:0.##}{1}", byteSizeFloat, sizes[order]); - return result; - } - - class TabWriter - { - public StreamWriter Writer; - private int Indentation; - - public TabWriter(StreamWriter writer) - { - Writer = writer; - } - - class TabWriterIdentScope : IDisposable - { - TabWriter m_Writer; - - public TabWriterIdentScope(TabWriter writer) - { - m_Writer = writer; - writer.Indentation++; - } - - public void Dispose() - { - m_Writer.Indentation--; - } - } - - public IDisposable IndentScope(string text = null) - { - if (text != null) - WriteLine(text); - return new TabWriterIdentScope(this); - } - - public void WriteLine(string line) - { - Writer.WriteLine(new String('\t', Indentation) + line); - } - } - - class AttrBuilder - { - List> m_Items = new List>(); - - public void Add(string k, string v) - { - m_Items.Add(new Tuple(k, v)); - } - - public void AddSize(string k, ulong size) - { - m_Items.Add(new Tuple(k, GetFriendlySize(size))); - } - - public override string ToString() - { - return "(" + string.Join(", ", m_Items.Select(x => $"{x.Item1}: {x.Item2}")) + ")"; - } - } - - - static void PrintAsset(TabWriter writer, BuildLayout.ExplicitAsset asset, int fileIndex) - { - AttrBuilder attr = new AttrBuilder(); - attr.AddSize("Total Size", asset.SerializedSize + asset.StreamedSize); - attr.AddSize("Size from Objects", asset.SerializedSize); - attr.AddSize("Size from Streamed Data", asset.StreamedSize); - attr.Add("File Index", fileIndex.ToString()); - attr.Add("Addressable Name", asset.AddressableName); - using (writer.IndentScope($"{asset.AssetPath} {attr}")) - { - if (asset.ExternallyReferencedAssets.Count > 0) - { - writer.WriteLine("External References: " + string.Join(", ", asset.ExternallyReferencedAssets.Select(x => x.AssetPath))); - } - - if (asset.InternalReferencedOtherAssets.Count > 0) - { - writer.WriteLine("Internal References: " + string.Join(", ", asset.InternalReferencedOtherAssets.Select(x => x.AssetPath))); - } - } - } - - static void PrintDataFromOtherAsset(TabWriter writer, BuildLayout.DataFromOtherAsset asset) - { - AttrBuilder attr = new AttrBuilder(); - attr.AddSize("Size", asset.SerializedSize + asset.StreamedSize); - attr.AddSize("Size from Objects", asset.SerializedSize); - attr.AddSize("Size from Streamed Data", asset.StreamedSize); - attr.Add("Object Count", asset.ObjectCount.ToString()); - using (writer.IndentScope($"{asset.AssetPath} {attr}")) - { - writer.WriteLine($"Referencing Assets: {string.Join(", ", asset.ReferencingAssets.Select(x => x.AssetPath))}"); - } - } - - static void PrintFile(TabWriter writer, BuildLayout.File file, int i) - { - AttrBuilder attr = new AttrBuilder(); - if (file.PreloadInfoSize > 0) - attr.AddSize("PreloadInfoSize", (ulong)file.PreloadInfoSize); - - attr.Add("MonoScripts", file.MonoScriptCount.ToString()); - attr.AddSize("MonoScript Size", file.MonoScriptSize); - - using (writer.IndentScope($"File {i} {attr}")) - { - foreach (BuildLayout.SubFile sf in file.SubFiles) - { - AttrBuilder attr2 = new AttrBuilder(); - attr2.AddSize("Size", sf.Size); - writer.WriteLine($"{sf.Name} {attr2}"); - } - - using (writer.IndentScope($"Data From Other Assets ({file.OtherAssets.Count})")) - { - foreach (BuildLayout.DataFromOtherAsset otherData in file.OtherAssets) - { - PrintDataFromOtherAsset(writer, otherData); - } - } - } - } - - static void PrintArchive(TabWriter writer, BuildLayout.Bundle archive) - { - AttrBuilder attr = new AttrBuilder(); - attr.AddSize("Size", archive.FileSize); - attr.Add("Compression", archive.Compression); - - ulong bundleSize = archive.Files.First(x => x.BundleObjectInfo != null).BundleObjectInfo.Size; - attr.AddSize("Asset Bundle Object Size", bundleSize); - - using (writer.IndentScope($"Archive {archive.Name} {attr}")) - { - if (archive.Dependencies != null) - writer.WriteLine("Bundle Dependencies: " + string.Join(", ", archive.Dependencies.Select(x => x.Name))); - - if (archive.ExpandedDependencies != null) - writer.WriteLine("Expanded Bundle Dependencies: " + string.Join(", ", archive.ExpandedDependencies.Select(x => x.Name))); - - using (writer.IndentScope($"Explicit Assets")) - { - for (int i = 0; i < archive.Files.Count; i++) - { - BuildLayout.File f = archive.Files[i]; - foreach (BuildLayout.ExplicitAsset asset in f.Assets) - { - PrintAsset(writer, asset, i); - } - } - } - - using (writer.IndentScope($"Files:")) - { - for (int i = 0; i < archive.Files.Count; i++) - PrintFile(writer, archive.Files[i], i); - } - } - } - - static void PrintSchema(TabWriter writer, BuildLayout.SchemaData sd) - { - string text = sd.Type; - if (sd.KvpDetails.Count > 0) - { - AttrBuilder attr = new AttrBuilder(); - sd.KvpDetails.ForEach(x => attr.Add(x.Item1, x.Item2)); - text += " " + attr; - } - - writer.WriteLine(text); - } - - static void PrintGroup(TabWriter writer, BuildLayout.Group grp) - { - int explicitAssetCount = grp.Bundles.Sum(x => x.Files.Sum(y => y.Assets.Count)); - AttrBuilder attr = new AttrBuilder(); - attr.Add("Bundles", grp.Bundles.Count.ToString()); - attr.AddSize("Total Size", (ulong)grp.Bundles.Sum(x => (long)x.FileSize)); - attr.Add("Explicit Asset Count", explicitAssetCount.ToString()); - - using (writer.IndentScope($"Group {grp.Name} {attr}")) - { - using (writer.IndentScope("Schemas")) - grp.Schemas.ForEach(x => PrintSchema(writer, x)); - - foreach (BuildLayout.Bundle archive in grp.Bundles) - PrintArchive(writer, archive); - } - } - - internal static void WriteBundleLayout(Stream stream, BuildLayout layout) - { - using (StreamWriter sw = new StreamWriter(stream)) - { - TabWriter writer = new TabWriter(sw); - - writer.WriteLine("WARNING! The formatting in this file may change in future package versions."); - writer.WriteLine($"Unity Version: {layout.UnityVersion}"); - if (!string.IsNullOrEmpty(layout.PackageVersion)) - writer.WriteLine(layout.PackageVersion); - - WriteSummary(writer, layout); - writer.WriteLine(""); - - - foreach (BuildLayout.Group grp in layout.Groups) - { - PrintGroup(writer, grp); - } - - using (writer.IndentScope("BuiltIn Bundles")) - foreach (BuildLayout.Bundle b in layout.BuiltInBundles) - PrintArchive(writer, b); - } - } - - static void WriteSummary(TabWriter writer, BuildLayout layout) - { - int ExplicitAssetCount = 0; - int SceneBundleCount = 0; - int AssetBundleCount = 0; - ulong TotalBuildSize = 0; - ulong MonoScriptSize = 0; - ulong BundleOverheadSize = 0; - - foreach (BuildLayout.File f in BuildLayoutHelpers.EnumerateFiles(layout)) - { - BundleOverheadSize += f.BundleObjectInfo != null ? f.BundleObjectInfo.Size : 0; - MonoScriptSize += f.MonoScriptSize; - } - - foreach (BuildLayout.Bundle b in BuildLayoutHelpers.EnumerateBundles(layout)) - { - bool sceneBundle = BuildLayoutHelpers.EnumerateAssets(b).FirstOrDefault(x => x.AssetPath.EndsWith(".unity", StringComparison.OrdinalIgnoreCase)) != null; - SceneBundleCount += sceneBundle ? 1 : 0; - AssetBundleCount += sceneBundle ? 0 : 1; - TotalBuildSize += b.FileSize; - } - - ExplicitAssetCount = BuildLayoutHelpers.EnumerateAssets(layout).Count(); - - using (writer.IndentScope("Summary")) - { - writer.WriteLine($"Addressable Groups: {layout.Groups.Count}"); - writer.WriteLine($"Explicit Assets Addressed: {ExplicitAssetCount}"); - writer.WriteLine($"Total Bundle: {SceneBundleCount + AssetBundleCount} ({SceneBundleCount} Scene Bundles, {AssetBundleCount} Non-Scene Bundles)"); - writer.WriteLine($"Total Build Size: {GetFriendlySize(TotalBuildSize)}"); - writer.WriteLine($"Total MonoScript Size: {GetFriendlySize(MonoScriptSize)}"); - writer.WriteLine($"Total AssetBundle Object Size: {GetFriendlySize(BundleOverheadSize)}"); - } - } - } -} +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build.Layout +{ + class BuildLayoutPrinter + { + static public string GetFriendlySize(ulong byteSize) + { + string[] sizes = {"B", "KB", "MB", "GB", "TB"}; + int order = 0; + ulong prevOrderRemainder = 0; + while (byteSize >= 1024 && order < sizes.Length - 1) + { + order++; + prevOrderRemainder = byteSize % 1024; + byteSize = byteSize / 1024; + } + + double byteSizeFloat = (double)byteSize + (double)prevOrderRemainder / 1024; + + string result = String.Format("{0:0.##}{1}", byteSizeFloat, sizes[order]); + return result; + } + + class TabWriter + { + public StreamWriter Writer; + private int Indentation; + + public TabWriter(StreamWriter writer) + { + Writer = writer; + } + + class TabWriterIdentScope : IDisposable + { + TabWriter m_Writer; + + public TabWriterIdentScope(TabWriter writer) + { + m_Writer = writer; + writer.Indentation++; + } + + public void Dispose() + { + m_Writer.Indentation--; + } + } + + public IDisposable IndentScope(string text = null) + { + if (text != null) + WriteLine(text); + return new TabWriterIdentScope(this); + } + + public void WriteLine(string line) + { + Writer.WriteLine(new String('\t', Indentation) + line); + } + } + + class AttrBuilder + { + List> m_Items = new List>(); + + public void Add(string k, string v) + { + m_Items.Add(new Tuple(k, v)); + } + + public void AddSize(string k, ulong size) + { + m_Items.Add(new Tuple(k, GetFriendlySize(size))); + } + + public override string ToString() + { + return "(" + string.Join(", ", m_Items.Select(x => $"{x.Item1}: {x.Item2}")) + ")"; + } + } + + + static void PrintAsset(TabWriter writer, BuildLayout.ExplicitAsset asset, int fileIndex) + { + AttrBuilder attr = new AttrBuilder(); + attr.AddSize("Total Size", asset.SerializedSize + asset.StreamedSize); + attr.AddSize("Size from Objects", asset.SerializedSize); + attr.AddSize("Size from Streamed Data", asset.StreamedSize); + attr.Add("File Index", fileIndex.ToString()); + attr.Add("Addressable Name", asset.AddressableName); + using (writer.IndentScope($"{asset.AssetPath} {attr}")) + { + if (asset.ExternallyReferencedAssets.Count > 0) + { + writer.WriteLine("External References: " + string.Join(", ", asset.ExternallyReferencedAssets.Select(x => x.AssetPath))); + } + + if (asset.InternalReferencedOtherAssets.Count > 0) + { + writer.WriteLine("Internal References: " + string.Join(", ", asset.InternalReferencedOtherAssets.Select(x => x.AssetPath))); + } + } + } + + static void PrintDataFromOtherAsset(TabWriter writer, BuildLayout.DataFromOtherAsset asset) + { + AttrBuilder attr = new AttrBuilder(); + attr.AddSize("Size", asset.SerializedSize + asset.StreamedSize); + attr.AddSize("Size from Objects", asset.SerializedSize); + attr.AddSize("Size from Streamed Data", asset.StreamedSize); + attr.Add("Object Count", asset.ObjectCount.ToString()); + using (writer.IndentScope($"{asset.AssetPath} {attr}")) + { + writer.WriteLine($"Referencing Assets: {string.Join(", ", asset.ReferencingAssets.Select(x => x.AssetPath))}"); + } + } + + static void PrintFile(TabWriter writer, BuildLayout.File file, int i) + { + AttrBuilder attr = new AttrBuilder(); + if (file.PreloadInfoSize > 0) + attr.AddSize("PreloadInfoSize", (ulong)file.PreloadInfoSize); + + attr.Add("MonoScripts", file.MonoScriptCount.ToString()); + attr.AddSize("MonoScript Size", file.MonoScriptSize); + + using (writer.IndentScope($"File {i} {attr}")) + { + foreach (BuildLayout.SubFile sf in file.SubFiles) + { + AttrBuilder attr2 = new AttrBuilder(); + attr2.AddSize("Size", sf.Size); + writer.WriteLine($"{sf.Name} {attr2}"); + } + + using (writer.IndentScope($"Data From Other Assets ({file.OtherAssets.Count})")) + { + foreach (BuildLayout.DataFromOtherAsset otherData in file.OtherAssets) + { + PrintDataFromOtherAsset(writer, otherData); + } + } + } + } + + static void PrintArchive(TabWriter writer, BuildLayout.Bundle archive) + { + AttrBuilder attr = new AttrBuilder(); + attr.AddSize("Size", archive.FileSize); + attr.Add("Compression", archive.Compression); + + ulong bundleSize = archive.Files.First(x => x.BundleObjectInfo != null).BundleObjectInfo.Size; + attr.AddSize("Asset Bundle Object Size", bundleSize); + + using (writer.IndentScope($"Archive {archive.Name} {attr}")) + { + if (archive.Dependencies != null) + writer.WriteLine("Bundle Dependencies: " + string.Join(", ", archive.Dependencies.Select(x => x.Name))); + + if (archive.ExpandedDependencies != null) + writer.WriteLine("Expanded Bundle Dependencies: " + string.Join(", ", archive.ExpandedDependencies.Select(x => x.Name))); + + using (writer.IndentScope($"Explicit Assets")) + { + for (int i = 0; i < archive.Files.Count; i++) + { + BuildLayout.File f = archive.Files[i]; + foreach (BuildLayout.ExplicitAsset asset in f.Assets) + { + PrintAsset(writer, asset, i); + } + } + } + + using (writer.IndentScope($"Files:")) + { + for (int i = 0; i < archive.Files.Count; i++) + PrintFile(writer, archive.Files[i], i); + } + } + } + + static void PrintSchema(TabWriter writer, BuildLayout.SchemaData sd) + { + string text = sd.Type; + if (sd.KvpDetails.Count > 0) + { + AttrBuilder attr = new AttrBuilder(); + sd.KvpDetails.ForEach(x => attr.Add(x.Item1, x.Item2)); + text += " " + attr; + } + + writer.WriteLine(text); + } + + static void PrintGroup(TabWriter writer, BuildLayout.Group grp) + { + int explicitAssetCount = grp.Bundles.Sum(x => x.Files.Sum(y => y.Assets.Count)); + AttrBuilder attr = new AttrBuilder(); + attr.Add("Bundles", grp.Bundles.Count.ToString()); + attr.AddSize("Total Size", (ulong)grp.Bundles.Sum(x => (long)x.FileSize)); + attr.Add("Explicit Asset Count", explicitAssetCount.ToString()); + + using (writer.IndentScope($"Group {grp.Name} {attr}")) + { + using (writer.IndentScope("Schemas")) + grp.Schemas.ForEach(x => PrintSchema(writer, x)); + + foreach (BuildLayout.Bundle archive in grp.Bundles) + PrintArchive(writer, archive); + } + } + + internal static void WriteBundleLayout(Stream stream, BuildLayout layout) + { + using (StreamWriter sw = new StreamWriter(stream)) + { + TabWriter writer = new TabWriter(sw); + + writer.WriteLine("WARNING! The formatting in this file may change in future package versions."); + writer.WriteLine($"Unity Version: {layout.UnityVersion}"); + if (!string.IsNullOrEmpty(layout.PackageVersion)) + writer.WriteLine(layout.PackageVersion); + + WriteSummary(writer, layout); + writer.WriteLine(""); + + + foreach (BuildLayout.Group grp in layout.Groups) + { + PrintGroup(writer, grp); + } + + using (writer.IndentScope("BuiltIn Bundles")) + foreach (BuildLayout.Bundle b in layout.BuiltInBundles) + PrintArchive(writer, b); + } + } + + static void WriteSummary(TabWriter writer, BuildLayout layout) + { + int ExplicitAssetCount = 0; + int SceneBundleCount = 0; + int AssetBundleCount = 0; + ulong TotalBuildSize = 0; + ulong MonoScriptSize = 0; + ulong BundleOverheadSize = 0; + + foreach (BuildLayout.File f in BuildLayoutHelpers.EnumerateFiles(layout)) + { + BundleOverheadSize += f.BundleObjectInfo != null ? f.BundleObjectInfo.Size : 0; + MonoScriptSize += f.MonoScriptSize; + } + + foreach (BuildLayout.Bundle b in BuildLayoutHelpers.EnumerateBundles(layout)) + { + bool sceneBundle = BuildLayoutHelpers.EnumerateAssets(b).FirstOrDefault(x => x.AssetPath.EndsWith(".unity", StringComparison.OrdinalIgnoreCase)) != null; + SceneBundleCount += sceneBundle ? 1 : 0; + AssetBundleCount += sceneBundle ? 0 : 1; + TotalBuildSize += b.FileSize; + } + + ExplicitAssetCount = BuildLayoutHelpers.EnumerateAssets(layout).Count(); + + using (writer.IndentScope("Summary")) + { + writer.WriteLine($"Addressable Groups: {layout.Groups.Count}"); + writer.WriteLine($"Explicit Assets Addressed: {ExplicitAssetCount}"); + writer.WriteLine($"Total Bundle: {SceneBundleCount + AssetBundleCount} ({SceneBundleCount} Scene Bundles, {AssetBundleCount} Non-Scene Bundles)"); + writer.WriteLine($"Total Build Size: {GetFriendlySize(TotalBuildSize)}"); + writer.WriteLine($"Total MonoScript Size: {GetFriendlySize(MonoScriptSize)}"); + writer.WriteLine($"Total AssetBundle Object Size: {GetFriendlySize(BundleOverheadSize)}"); + } + } + } +} diff --git a/Editor/Build/Layout/BuildLayoutPrinter.cs.meta b/Editor/Build/Layout/BuildLayoutPrinter.cs.meta index 67f43de7..cf55e754 100644 --- a/Editor/Build/Layout/BuildLayoutPrinter.cs.meta +++ b/Editor/Build/Layout/BuildLayoutPrinter.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 859e5046b2060774898d8e87f4e78761 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 859e5046b2060774898d8e87f4e78761 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/Layout/BuildLayoutSummary.cs b/Editor/Build/Layout/BuildLayoutSummary.cs index 88d84a98..1f7c5860 100644 --- a/Editor/Build/Layout/BuildLayoutSummary.cs +++ b/Editor/Build/Layout/BuildLayoutSummary.cs @@ -1,210 +1,210 @@ -using System.Collections.Generic; - -namespace UnityEditor.AddressableAssets.Build.Layout -{ - /// - /// Data store for summary data about build content - /// - public struct AssetSummary - { - /// - /// Type of Asset - /// - public AssetType AssetType; - - /// - /// Number of Objects build of the defined AssetType - /// - public int Count; - - /// - /// Total size of combined Objects - /// - public ulong SizeInBytes; - - internal void Append(AssetSummary other) - { - Count += other.Count; - SizeInBytes += other.SizeInBytes; - } - } - - /// - /// Data store for summary data about Bundle content - /// - public struct BundleSummary - { - /// - /// Number of bundles built - /// - public int Count; - - /// - /// Size in bytes of bundles uncompressed - /// - public ulong TotalUncompressedSize; - - /// - /// Size in bytes of bundled compressed - /// - public ulong TotalCompressedSize; - } - - /// - /// Data store for Addressables build - /// - public class BuildLayoutSummary - { - /// - /// Summary of bundles - /// - public BundleSummary BundleSummary = new BundleSummary(); - - /// - /// Summary for AssetTypes used - /// - public List AssetSummaries = new List(); - - /// - /// The total number of assets in a build, including implicit assets - /// - internal int TotalAssetCount = 0; - - /// - /// The total number of explicitly added Addressable assets that were included in a build - /// - internal int ExplicitAssetCount = 0; - - /// - /// The total number of implicitly added assets that were included in a build - /// - internal int ImplicitAssetCount = 0; - - /// - /// Generates a summary of the content used in a BuildLayout - /// - /// BuildLayout to get a summary for - /// Summary of the BuildLayout layout - public static BuildLayoutSummary GetSummary(BuildLayout layout) - { - BuildLayoutSummary summary = new BuildLayoutSummary(); - Dictionary sizes = new Dictionary(); - foreach (var group in layout.Groups) - { - foreach (var bundle in group.Bundles) - { - summary.BundleSummary.TotalCompressedSize += bundle.FileSize; - summary.BundleSummary.TotalUncompressedSize += bundle.UncompressedFileSize; - summary.BundleSummary.Count++; - - foreach (var file in bundle.Files) - { - summary.TotalAssetCount += file.Assets.Count + file.OtherAssets.Count; - summary.ExplicitAssetCount += file.Assets.Count; - summary.ImplicitAssetCount += file.OtherAssets.Count; - - foreach (var asset in file.Assets) - AppendObjectsToSummary(asset.MainAssetType, asset.SerializedSize + asset.StreamedSize, asset.Objects, summary.AssetSummaries); - foreach (var asset in file.OtherAssets) - AppendObjectsToSummary(asset.MainAssetType, asset.SerializedSize + asset.StreamedSize, asset.Objects, summary.AssetSummaries); - } - } - } - - return summary; - } - - /// - /// Generates a summary of the content used in a BuildLayout, minus the asset type data. - /// - /// - /// - - internal static BuildLayoutSummary GetSummaryWithoutAssetTypes(BuildLayout layout) - { - BuildLayoutSummary summary = new BuildLayoutSummary(); - foreach (var group in layout.Groups) - { - foreach (var bundle in group.Bundles) - { - summary.BundleSummary.TotalCompressedSize += bundle.FileSize; - summary.BundleSummary.TotalUncompressedSize += bundle.UncompressedFileSize; - summary.BundleSummary.Count++; - - foreach (var file in bundle.Files) - { - summary.TotalAssetCount += file.Assets.Count + file.OtherAssets.Count; - summary.ExplicitAssetCount += file.Assets.Count; - summary.ImplicitAssetCount += file.OtherAssets.Count; - } - } - } - return summary; - } - - private static void AppendObjectsToSummary(AssetType mainAssetType, ulong overallSize, List subObjects, List assetSummariesOut) - { - // for Scene Assets take the accumulation of Objects for overall Scene size - if (mainAssetType == AssetType.Scene) - AddObjectToSummary(AssetType.Scene, overallSize, assetSummariesOut); - - // for prefabs accumulate general objects like GameObject and Transform as Prefab - else if (mainAssetType == AssetType.Prefab || mainAssetType == AssetType.Model) - { - ulong serializedSize = 0; - ulong streamedSize = 0; - ulong size = 0; - - foreach (var objectData in subObjects) - { - if (objectData.AssetType == AssetType.Other || - objectData.AssetType == AssetType.GameObject || - objectData.AssetType == AssetType.Component || - objectData.AssetType == AssetType.MonoBehaviour ) - { - serializedSize += objectData.SerializedSize; - streamedSize += objectData.StreamedSize; - } - else - { - AddObjectToSummary(objectData.AssetType, objectData.SerializedSize + objectData.StreamedSize, assetSummariesOut); - } - } - - size = serializedSize + streamedSize; - if (size > 0) - AddObjectToSummary(AssetType.Prefab, size, assetSummariesOut); - } - else - { - foreach (BuildLayout.ObjectData objectData in subObjects) - { - AddObjectToSummary(objectData.AssetType, objectData.SerializedSize + objectData.StreamedSize, assetSummariesOut); - } - } - } - - private static void AddObjectToSummary(AssetType assetType, ulong size, List assetSummaries) - { - AssetSummary summary = new AssetSummary() - { - AssetType = assetType, - Count = 1, - SizeInBytes = size - }; - - for(int i=0; i + /// Data store for summary data about build content + /// + public struct AssetSummary + { + /// + /// Type of Asset + /// + public AssetType AssetType; + + /// + /// Number of Objects build of the defined AssetType + /// + public int Count; + + /// + /// Total size of combined Objects + /// + public ulong SizeInBytes; + + internal void Append(AssetSummary other) + { + Count += other.Count; + SizeInBytes += other.SizeInBytes; + } + } + + /// + /// Data store for summary data about Bundle content + /// + public struct BundleSummary + { + /// + /// Number of bundles built + /// + public int Count; + + /// + /// Size in bytes of bundles uncompressed + /// + public ulong TotalUncompressedSize; + + /// + /// Size in bytes of bundled compressed + /// + public ulong TotalCompressedSize; + } + + /// + /// Data store for Addressables build + /// + public class BuildLayoutSummary + { + /// + /// Summary of bundles + /// + public BundleSummary BundleSummary = new BundleSummary(); + + /// + /// Summary for AssetTypes used + /// + public List AssetSummaries = new List(); + + /// + /// The total number of assets in a build, including implicit assets + /// + internal int TotalAssetCount = 0; + + /// + /// The total number of explicitly added Addressable assets that were included in a build + /// + internal int ExplicitAssetCount = 0; + + /// + /// The total number of implicitly added assets that were included in a build + /// + internal int ImplicitAssetCount = 0; + + /// + /// Generates a summary of the content used in a BuildLayout + /// + /// BuildLayout to get a summary for + /// Summary of the BuildLayout layout + public static BuildLayoutSummary GetSummary(BuildLayout layout) + { + BuildLayoutSummary summary = new BuildLayoutSummary(); + Dictionary sizes = new Dictionary(); + foreach (var group in layout.Groups) + { + foreach (var bundle in group.Bundles) + { + summary.BundleSummary.TotalCompressedSize += bundle.FileSize; + summary.BundleSummary.TotalUncompressedSize += bundle.UncompressedFileSize; + summary.BundleSummary.Count++; + + foreach (var file in bundle.Files) + { + summary.TotalAssetCount += file.Assets.Count + file.OtherAssets.Count; + summary.ExplicitAssetCount += file.Assets.Count; + summary.ImplicitAssetCount += file.OtherAssets.Count; + + foreach (var asset in file.Assets) + AppendObjectsToSummary(asset.MainAssetType, asset.SerializedSize + asset.StreamedSize, asset.Objects, summary.AssetSummaries); + foreach (var asset in file.OtherAssets) + AppendObjectsToSummary(asset.MainAssetType, asset.SerializedSize + asset.StreamedSize, asset.Objects, summary.AssetSummaries); + } + } + } + + return summary; + } + + /// + /// Generates a summary of the content used in a BuildLayout, minus the asset type data. + /// + /// + /// + + internal static BuildLayoutSummary GetSummaryWithoutAssetTypes(BuildLayout layout) + { + BuildLayoutSummary summary = new BuildLayoutSummary(); + foreach (var group in layout.Groups) + { + foreach (var bundle in group.Bundles) + { + summary.BundleSummary.TotalCompressedSize += bundle.FileSize; + summary.BundleSummary.TotalUncompressedSize += bundle.UncompressedFileSize; + summary.BundleSummary.Count++; + + foreach (var file in bundle.Files) + { + summary.TotalAssetCount += file.Assets.Count + file.OtherAssets.Count; + summary.ExplicitAssetCount += file.Assets.Count; + summary.ImplicitAssetCount += file.OtherAssets.Count; + } + } + } + return summary; + } + + private static void AppendObjectsToSummary(AssetType mainAssetType, ulong overallSize, List subObjects, List assetSummariesOut) + { + // for Scene Assets take the accumulation of Objects for overall Scene size + if (mainAssetType == AssetType.Scene) + AddObjectToSummary(AssetType.Scene, overallSize, assetSummariesOut); + + // for prefabs accumulate general objects like GameObject and Transform as Prefab + else if (mainAssetType == AssetType.Prefab || mainAssetType == AssetType.Model) + { + ulong serializedSize = 0; + ulong streamedSize = 0; + ulong size = 0; + + foreach (var objectData in subObjects) + { + if (objectData.AssetType == AssetType.Other || + objectData.AssetType == AssetType.GameObject || + objectData.AssetType == AssetType.Component || + objectData.AssetType == AssetType.MonoBehaviour ) + { + serializedSize += objectData.SerializedSize; + streamedSize += objectData.StreamedSize; + } + else + { + AddObjectToSummary(objectData.AssetType, objectData.SerializedSize + objectData.StreamedSize, assetSummariesOut); + } + } + + size = serializedSize + streamedSize; + if (size > 0) + AddObjectToSummary(AssetType.Prefab, size, assetSummariesOut); + } + else + { + foreach (BuildLayout.ObjectData objectData in subObjects) + { + AddObjectToSummary(objectData.AssetType, objectData.SerializedSize + objectData.StreamedSize, assetSummariesOut); + } + } + } + + private static void AddObjectToSummary(AssetType assetType, ulong size, List assetSummaries) + { + AssetSummary summary = new AssetSummary() + { + AssetType = assetType, + Count = 1, + SizeInBytes = size + }; + + for(int i=0; i - /// This can be used to create a LinkXml for your build. This will ensure that the desired runtime types are packed into the build. - /// - [Obsolete("UnityEditor.AddressableAssets.Build.LinkXmlGenerator is obsolete. Use UnityEditor.Build.Pipeline.Utilities.LinkXmlGenerator instead.")] - public class LinkXmlGenerator : UnityEditor.Build.Pipeline.Utilities.LinkXmlGenerator - { -#pragma warning disable CA1061 // Do not hide base class methods - /// - public new void AddTypes(params Type[] types) - { - base.AddTypes(types); - } - - /// - public new void AddTypes(IEnumerable types) - { - base.AddTypes(types); - } - - /// - public new void SetTypeConversion(Type a, Type b) - { - base.SetTypeConversion(a, b); - } - - /// - public new void Save(string path) - { - base.Save(path); - } -#pragma warning restore CA1061 // Do not hide base class methods - } -} +using System; +using System.Collections.Generic; + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// This can be used to create a LinkXml for your build. This will ensure that the desired runtime types are packed into the build. + /// + [Obsolete("UnityEditor.AddressableAssets.Build.LinkXmlGenerator is obsolete. Use UnityEditor.Build.Pipeline.Utilities.LinkXmlGenerator instead.")] + public class LinkXmlGenerator : UnityEditor.Build.Pipeline.Utilities.LinkXmlGenerator + { +#pragma warning disable CA1061 // Do not hide base class methods + /// + public new void AddTypes(params Type[] types) + { + base.AddTypes(types); + } + + /// + public new void AddTypes(IEnumerable types) + { + base.AddTypes(types); + } + + /// + public new void SetTypeConversion(Type a, Type b) + { + base.SetTypeConversion(a, b); + } + + /// + public new void Save(string path) + { + base.Save(path); + } +#pragma warning restore CA1061 // Do not hide base class methods + } +} diff --git a/Editor/Build/LinkXMLGenerator.cs.meta b/Editor/Build/LinkXMLGenerator.cs.meta index c33aa75b..536e719e 100644 --- a/Editor/Build/LinkXMLGenerator.cs.meta +++ b/Editor/Build/LinkXMLGenerator.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: c7613ad25e9a1794eb580050f86f4889 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: c7613ad25e9a1794eb580050f86f4889 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/MonoScriptBundleNaming.cs b/Editor/Build/MonoScriptBundleNaming.cs index bfab04f9..5f4b4d74 100644 --- a/Editor/Build/MonoScriptBundleNaming.cs +++ b/Editor/Build/MonoScriptBundleNaming.cs @@ -1,28 +1,28 @@ -namespace UnityEditor.AddressableAssets.Build -{ - /// - /// Naming conventions for the monoscript bundle name prefix. - /// - public enum MonoScriptBundleNaming - { - /// - /// No special prefix will be added to the monscript bundle name. - /// - Disabled, - - /// - /// Set the monoscript bundle name prefix to the hash of the project name. - /// - ProjectName, - - /// - /// Set the monoscript bundle name prefix to the guid of the default group. - /// - DefaultGroupGuid, - - /// - /// Set the monoscript bundle name prefix to the user specified value. - /// - Custom - } -} +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// Naming conventions for the monoscript bundle name prefix. + /// + public enum MonoScriptBundleNaming + { + /// + /// No special prefix will be added to the monscript bundle name. + /// + Disabled, + + /// + /// Set the monoscript bundle name prefix to the hash of the project name. + /// + ProjectName, + + /// + /// Set the monoscript bundle name prefix to the guid of the default group. + /// + DefaultGroupGuid, + + /// + /// Set the monoscript bundle name prefix to the user specified value. + /// + Custom + } +} diff --git a/Editor/Build/MonoScriptBundleNaming.cs.meta b/Editor/Build/MonoScriptBundleNaming.cs.meta index 2a6766b2..ff2da755 100644 --- a/Editor/Build/MonoScriptBundleNaming.cs.meta +++ b/Editor/Build/MonoScriptBundleNaming.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 74f5fbf77d99c4e45bf6421e5cf0e4cc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 74f5fbf77d99c4e45bf6421e5cf0e4cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs b/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs index 5bfdb88d..71ccfdb8 100644 --- a/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs +++ b/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs @@ -1,248 +1,248 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEditor; -using UnityEditor.AddressableAssets.Build; -using UnityEditor.AddressableAssets.Build.BuildPipelineTasks; -using UnityEditor.AddressableAssets.Build.DataBuilders; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.AddressableAssets.Settings.GroupSchemas; -using UnityEditor.Build.Pipeline; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.AddressableAssets.ResourceLocators; -using UnityEngine.ResourceManagement.ResourceProviders; -using UnityEngine.ResourceManagement.Util; -using static UnityEditor.AddressableAssets.Build.ContentUpdateScript; - -/// -/// RevertUnchangedAssetsToPreviousAssetState uses the asset state from the previous build to determine if any assets -/// need to use their previous settings or use the newly build data. -/// -public class RevertUnchangedAssetsToPreviousAssetState -{ - internal struct AssetEntryRevertOperation - { - public CachedAssetState PreviousAssetState; - public AddressableAssetEntry AssetEntry; - public ContentCatalogDataEntry BundleCatalogEntry; - public string CurrentBuildPath; - public string PreviousBuildPath; - } - - /// - /// Reverts asset entries to their previous state if not modified by the new build. - /// - /// The new build data. - /// The cached build data. - /// Returns the success ReturnCode if the content update succeeds. - public static ReturnCode Run(IAddressableAssetsBuildContext aaBuildContext, ContentUpdateContext updateContext) - { - var aaContext = aaBuildContext as AddressableAssetsBuildContext; - var groups = aaContext.Settings.groups.Where(group => group != null && group.HasSchema()); - if (updateContext.ContentState.cachedBundles == null) - UnityEngine.Debug.LogWarning( - $"ContentUpdateContext does not contain previous asset bundle info, remote static bundles that are updated will not be cacheable. If this is needed, rebuild the shipped application state with the current version of addressables to update the addressables_content_state.bin file. The updated addressables_content_state.bin file can be used to create the content update."); - - foreach (var assetGroup in groups) - { - List operations = DetermineRequiredAssetEntryUpdates(assetGroup, updateContext); - if (operations != null && operations.Count > 0) - ApplyAssetEntryUpdates(operations, updateContext); - } - - var defaultContentUpdateSchema = aaContext.Settings.DefaultGroup.GetSchema(); - if (defaultContentUpdateSchema == null) - { - Debug.LogWarning($"Default group {aaContext.Settings.DefaultGroup.Name} does not contain a {nameof(ContentUpdateGroupSchema)}, so we're unable to determine if " + - $"the built in shader bundle and monoscript bundles need to be reverting to their previous paths. We will not revert the paths for these bundles in the catalog, " + - $"if that is not the desired behavior, please add a {nameof(ContentUpdateGroupSchema)} to the Default group and set the Prevent Updates toggle to the correct setting."); - } - else if (defaultContentUpdateSchema.StaticContent) - { - // cannot detect individual shader usage, so just assume that the shaders haven't changed, and just indeterminisn. - if (!RevertBundleByNameContains("_unitybuiltinshaders", updateContext, aaContext)) - return ReturnCode.Error; - // Scripts could have been added and fail, or removed and load fine, not enough information to know - if (!RevertBundleByNameContains("_monoscripts", updateContext, aaContext)) - return ReturnCode.Error; - } - - return ReturnCode.Success; - } - - internal static bool RevertBundleByNameContains(string containingString, ContentUpdateContext updateContext, AddressableAssetsBuildContext aaContext) - { - CachedBundleState previousBundleCache = null; - foreach (CachedBundleState cachedBundle in updateContext.ContentState.cachedBundles) - { - var options = cachedBundle.data as AssetBundleRequestOptions; - if (options != null && AddressableAssetUtility.StringContains(options.BundleName, containingString, StringComparison.Ordinal)) - { - previousBundleCache = cachedBundle; - break; - } - } - - ContentCatalogDataEntry currentLocation = null; - // find current location with it - foreach (ContentCatalogDataEntry catalogEntry in aaContext.locations) - { - if (catalogEntry.Provider == "UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider") - { - var options = catalogEntry.Data as AssetBundleRequestOptions; - if (options != null && AddressableAssetUtility.StringContains(options.BundleName, containingString, StringComparison.Ordinal)) - { - currentLocation = catalogEntry; - break; - } - } - } - - if (previousBundleCache == null && currentLocation == null) - return true; // bundle were not used in either build - if (previousBundleCache == null) - { - UnityEngine.Debug.LogError($"Matching cached update state for {currentLocation.InternalId} failed. Content not found in original build."); - return false; // bundle was in update build, but not original - } - - if (currentLocation == null) - return true; // bundle not in update build but was in original is ok - - currentLocation.InternalId = previousBundleCache.bundleFileId; - var currentOptions = currentLocation.Data as AssetBundleRequestOptions; - var prevOptions = previousBundleCache.data as AssetBundleRequestOptions; - currentOptions.Crc = prevOptions.Crc; - currentOptions.Hash = prevOptions.Hash; - currentOptions.BundleSize = prevOptions.BundleSize; - currentOptions.BundleName = prevOptions.BundleName; - return true; - } - - internal static List DetermineRequiredAssetEntryUpdates(AddressableAssetGroup group, ContentUpdateScript.ContentUpdateContext contentUpdateContext) - { - if (!group.HasSchema()) - return new List(); - - bool groupIsStaticContentGroup = group.HasSchema() && group.GetSchema().StaticContent; - List operations = new List(); - - List allEntries = new List(); - group.GatherAllAssets(allEntries, true, true, false); - foreach (AddressableAssetEntry entry in allEntries) - { - if (entry.IsFolder) - continue; - GUID guid = new GUID(entry.guid); - if (!contentUpdateContext.WriteData.AssetToFiles.ContainsKey(guid)) - continue; - - string file = contentUpdateContext.WriteData.AssetToFiles[guid][0]; - string fullInternalBundleName = contentUpdateContext.WriteData.FileToBundle[file]; - string finalBundleWritePath = contentUpdateContext.BundleToInternalBundleIdMap[fullInternalBundleName]; - - //Ensure we can get the catalog entry for the bundle we're looking to replace - if (!contentUpdateContext.IdToCatalogDataEntryMap.TryGetValue(finalBundleWritePath, out ContentCatalogDataEntry catalogBundleEntry)) - continue; - - //If new entries are added post initial build this will ensure that those new entries have their bundleFileId for SaveContentState - entry.BundleFileId = catalogBundleEntry.InternalId; - - //If we have no cached state no reason to proceed. This is new to the build. - if (!contentUpdateContext.GuidToPreviousAssetStateMap.TryGetValue(entry.guid, out CachedAssetState previousAssetState)) - continue; - - //If the parent group is different we don't want to revert it to its previous state - if (entry.parentGroup.Guid != previousAssetState.groupGuid) - continue; - - var hashChanged = AssetDatabase.GetAssetDependencyHash(entry.AssetPath) != previousAssetState.asset.hash; - //If the asset hash has changed and the group is not a static content update group we don't want to revert it to its previous state - if (hashChanged && !groupIsStaticContentGroup) - continue; - - //If the previous asset state has the same bundle file id as the current build we don't want to revert it to its previous state - if (!hashChanged && catalogBundleEntry.InternalId == previousAssetState.bundleFileId) - continue; - - var schema = group.GetSchema(); - string loadPath = schema.LoadPath.GetValue(group.Settings); - string buildPath = schema.BuildPath.GetValue(group.Settings); - - //Need to check and make sure our cached version exists - if (string.IsNullOrEmpty(previousAssetState.bundleFileId)) - { - //Logging this as an error because a CachedAssetState without a set bundleFileId is indicative of a significant issue with the build script. - Addressables.LogError($"CachedAssetState found for {entry.AssetPath} but the bundleFileId was never set on the previous build."); - continue; - } - - string previousBundlePath = BundleIdToBuildPath(previousAssetState.bundleFileId, loadPath, buildPath); - if (!File.Exists(previousBundlePath) || hashChanged && groupIsStaticContentGroup) - { - //Logging this as a warning because users may choose to delete their bundles on disk which will trigger this state. - Addressables.LogWarning($"CachedAssetState found for {entry.AssetPath} but the previous bundle at {previousBundlePath} cannot be found. " + - $"This will not affect loading the bundle in previously built players, but loading the missing bundle in Play Mode using the play mode script " + - $"\"Use Existing Build (requires built groups)\" will fail. This most often occurs because you are running a content update on a build where you " + - $"made changes to a group marked with \"Prevent Updates\""); - } - - string builtBundlePath = BundleIdToBuildPath(contentUpdateContext.BundleToInternalBundleIdMap[fullInternalBundleName], loadPath, buildPath); - - AssetEntryRevertOperation operation = new AssetEntryRevertOperation() - { - BundleCatalogEntry = catalogBundleEntry, - AssetEntry = entry, - CurrentBuildPath = builtBundlePath, - PreviousAssetState = previousAssetState, - PreviousBuildPath = previousBundlePath - }; - - operations.Add(operation); - } - - return operations; - } - - internal static string BundleIdToBuildPath(string bundleId, string rootLoadPath, string rootBuildPath) - { - if (bundleId == null) - return null; - bool replaceBackSlashes = rootLoadPath.Contains('/') && !ResourceManagerConfig.ShouldPathUseWebRequest(rootLoadPath); - string path = replaceBackSlashes ? bundleId.Replace('\\', '/') : bundleId; - return path.Replace(rootLoadPath, rootBuildPath); - } - - private static bool IsPreviouslyRevertedDependency(string bundleFileId, ContentUpdateContext contentUpdateContext) - { - foreach (CachedAssetState state in contentUpdateContext.PreviousAssetStateCarryOver) - { - if (state.bundleFileId == bundleFileId) - return true; - } - - return false; - } - - internal static void ApplyAssetEntryUpdates(List operations, ContentUpdateContext contentUpdateContext) - { - UnityEngine.Assertions.Assert.IsNotNull(contentUpdateContext.ContentState.cachedBundles, "CachedBundles is null, cachedBundles requires to apply update."); - foreach (AssetEntryRevertOperation operation in operations) - { - //Check that we can replace the entry in the file registry - if (contentUpdateContext.Registry.ReplaceBundleEntry(Path.GetFileNameWithoutExtension(operation.PreviousBuildPath), operation.PreviousAssetState.bundleFileId)) - { - File.Delete(operation.CurrentBuildPath); - - //sync the internal ids of the catalog entry and asset entry to the cached state - operation.BundleCatalogEntry.InternalId = operation.AssetEntry.BundleFileId = operation.PreviousAssetState.bundleFileId; - var bundleState = contentUpdateContext.ContentState.cachedBundles.FirstOrDefault(s => s.bundleFileId == operation.PreviousAssetState.bundleFileId); - UnityEngine.Assertions.Assert.IsNotNull(bundleState, "Could not find cached bundle state for " + operation.AssetEntry.BundleFileId); - UnityEngine.Assertions.Assert.IsNotNull(bundleState.data, "Could not find cached bundle load data for " + operation.AssetEntry.BundleFileId); - operation.BundleCatalogEntry.Data = bundleState.data; - } - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEditor.AddressableAssets.Build; +using UnityEditor.AddressableAssets.Build.BuildPipelineTasks; +using UnityEditor.AddressableAssets.Build.DataBuilders; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEditor.Build.Pipeline; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.ResourceManagement.Util; +using static UnityEditor.AddressableAssets.Build.ContentUpdateScript; + +/// +/// RevertUnchangedAssetsToPreviousAssetState uses the asset state from the previous build to determine if any assets +/// need to use their previous settings or use the newly build data. +/// +public class RevertUnchangedAssetsToPreviousAssetState +{ + internal struct AssetEntryRevertOperation + { + public CachedAssetState PreviousAssetState; + public AddressableAssetEntry AssetEntry; + public ContentCatalogDataEntry BundleCatalogEntry; + public string CurrentBuildPath; + public string PreviousBuildPath; + } + + /// + /// Reverts asset entries to their previous state if not modified by the new build. + /// + /// The new build data. + /// The cached build data. + /// Returns the success ReturnCode if the content update succeeds. + public static ReturnCode Run(IAddressableAssetsBuildContext aaBuildContext, ContentUpdateContext updateContext) + { + var aaContext = aaBuildContext as AddressableAssetsBuildContext; + var groups = aaContext.Settings.groups.Where(group => group != null && group.HasSchema()); + if (updateContext.ContentState.cachedBundles == null) + UnityEngine.Debug.LogWarning( + $"ContentUpdateContext does not contain previous asset bundle info, remote static bundles that are updated will not be cacheable. If this is needed, rebuild the shipped application state with the current version of addressables to update the addressables_content_state.bin file. The updated addressables_content_state.bin file can be used to create the content update."); + + foreach (var assetGroup in groups) + { + List operations = DetermineRequiredAssetEntryUpdates(assetGroup, updateContext); + if (operations != null && operations.Count > 0) + ApplyAssetEntryUpdates(operations, updateContext); + } + + var defaultContentUpdateSchema = aaContext.Settings.DefaultGroup.GetSchema(); + if (defaultContentUpdateSchema == null) + { + Debug.LogWarning($"Default group {aaContext.Settings.DefaultGroup.Name} does not contain a {nameof(ContentUpdateGroupSchema)}, so we're unable to determine if " + + $"the built in shader bundle and monoscript bundles need to be reverting to their previous paths. We will not revert the paths for these bundles in the catalog, " + + $"if that is not the desired behavior, please add a {nameof(ContentUpdateGroupSchema)} to the Default group and set the Prevent Updates toggle to the correct setting."); + } + else if (defaultContentUpdateSchema.StaticContent) + { + // cannot detect individual shader usage, so just assume that the shaders haven't changed, and just indeterminisn. + if (!RevertBundleByNameContains("_unitybuiltinshaders", updateContext, aaContext)) + return ReturnCode.Error; + // Scripts could have been added and fail, or removed and load fine, not enough information to know + if (!RevertBundleByNameContains("_monoscripts", updateContext, aaContext)) + return ReturnCode.Error; + } + + return ReturnCode.Success; + } + + internal static bool RevertBundleByNameContains(string containingString, ContentUpdateContext updateContext, AddressableAssetsBuildContext aaContext) + { + CachedBundleState previousBundleCache = null; + foreach (CachedBundleState cachedBundle in updateContext.ContentState.cachedBundles) + { + var options = cachedBundle.data as AssetBundleRequestOptions; + if (options != null && AddressableAssetUtility.StringContains(options.BundleName, containingString, StringComparison.Ordinal)) + { + previousBundleCache = cachedBundle; + break; + } + } + + ContentCatalogDataEntry currentLocation = null; + // find current location with it + foreach (ContentCatalogDataEntry catalogEntry in aaContext.locations) + { + if (catalogEntry.Provider == "UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider") + { + var options = catalogEntry.Data as AssetBundleRequestOptions; + if (options != null && AddressableAssetUtility.StringContains(options.BundleName, containingString, StringComparison.Ordinal)) + { + currentLocation = catalogEntry; + break; + } + } + } + + if (previousBundleCache == null && currentLocation == null) + return true; // bundle were not used in either build + if (previousBundleCache == null) + { + UnityEngine.Debug.LogError($"Matching cached update state for {currentLocation.InternalId} failed. Content not found in original build."); + return false; // bundle was in update build, but not original + } + + if (currentLocation == null) + return true; // bundle not in update build but was in original is ok + + currentLocation.InternalId = previousBundleCache.bundleFileId; + var currentOptions = currentLocation.Data as AssetBundleRequestOptions; + var prevOptions = previousBundleCache.data as AssetBundleRequestOptions; + currentOptions.Crc = prevOptions.Crc; + currentOptions.Hash = prevOptions.Hash; + currentOptions.BundleSize = prevOptions.BundleSize; + currentOptions.BundleName = prevOptions.BundleName; + return true; + } + + internal static List DetermineRequiredAssetEntryUpdates(AddressableAssetGroup group, ContentUpdateScript.ContentUpdateContext contentUpdateContext) + { + if (!group.HasSchema()) + return new List(); + + bool groupIsStaticContentGroup = group.HasSchema() && group.GetSchema().StaticContent; + List operations = new List(); + + List allEntries = new List(); + group.GatherAllAssets(allEntries, true, true, false); + foreach (AddressableAssetEntry entry in allEntries) + { + if (entry.IsFolder) + continue; + GUID guid = new GUID(entry.guid); + if (!contentUpdateContext.WriteData.AssetToFiles.ContainsKey(guid)) + continue; + + string file = contentUpdateContext.WriteData.AssetToFiles[guid][0]; + string fullInternalBundleName = contentUpdateContext.WriteData.FileToBundle[file]; + string finalBundleWritePath = contentUpdateContext.BundleToInternalBundleIdMap[fullInternalBundleName]; + + //Ensure we can get the catalog entry for the bundle we're looking to replace + if (!contentUpdateContext.IdToCatalogDataEntryMap.TryGetValue(finalBundleWritePath, out ContentCatalogDataEntry catalogBundleEntry)) + continue; + + //If new entries are added post initial build this will ensure that those new entries have their bundleFileId for SaveContentState + entry.BundleFileId = catalogBundleEntry.InternalId; + + //If we have no cached state no reason to proceed. This is new to the build. + if (!contentUpdateContext.GuidToPreviousAssetStateMap.TryGetValue(entry.guid, out CachedAssetState previousAssetState)) + continue; + + //If the parent group is different we don't want to revert it to its previous state + if (entry.parentGroup.Guid != previousAssetState.groupGuid) + continue; + + var hashChanged = AssetDatabase.GetAssetDependencyHash(entry.AssetPath) != previousAssetState.asset.hash; + //If the asset hash has changed and the group is not a static content update group we don't want to revert it to its previous state + if (hashChanged && !groupIsStaticContentGroup) + continue; + + //If the previous asset state has the same bundle file id as the current build we don't want to revert it to its previous state + if (!hashChanged && catalogBundleEntry.InternalId == previousAssetState.bundleFileId) + continue; + + var schema = group.GetSchema(); + string loadPath = schema.LoadPath.GetValue(group.Settings); + string buildPath = schema.BuildPath.GetValue(group.Settings); + + //Need to check and make sure our cached version exists + if (string.IsNullOrEmpty(previousAssetState.bundleFileId)) + { + //Logging this as an error because a CachedAssetState without a set bundleFileId is indicative of a significant issue with the build script. + Addressables.LogError($"CachedAssetState found for {entry.AssetPath} but the bundleFileId was never set on the previous build."); + continue; + } + + string previousBundlePath = BundleIdToBuildPath(previousAssetState.bundleFileId, loadPath, buildPath); + if (!File.Exists(previousBundlePath) || hashChanged && groupIsStaticContentGroup) + { + //Logging this as a warning because users may choose to delete their bundles on disk which will trigger this state. + Addressables.LogWarning($"CachedAssetState found for {entry.AssetPath} but the previous bundle at {previousBundlePath} cannot be found. " + + $"This will not affect loading the bundle in previously built players, but loading the missing bundle in Play Mode using the play mode script " + + $"\"Use Existing Build (requires built groups)\" will fail. This most often occurs because you are running a content update on a build where you " + + $"made changes to a group marked with \"Prevent Updates\""); + } + + string builtBundlePath = BundleIdToBuildPath(contentUpdateContext.BundleToInternalBundleIdMap[fullInternalBundleName], loadPath, buildPath); + + AssetEntryRevertOperation operation = new AssetEntryRevertOperation() + { + BundleCatalogEntry = catalogBundleEntry, + AssetEntry = entry, + CurrentBuildPath = builtBundlePath, + PreviousAssetState = previousAssetState, + PreviousBuildPath = previousBundlePath + }; + + operations.Add(operation); + } + + return operations; + } + + internal static string BundleIdToBuildPath(string bundleId, string rootLoadPath, string rootBuildPath) + { + if (bundleId == null) + return null; + bool replaceBackSlashes = rootLoadPath.Contains('/') && !ResourceManagerConfig.ShouldPathUseWebRequest(rootLoadPath); + string path = replaceBackSlashes ? bundleId.Replace('\\', '/') : bundleId; + return path.Replace(rootLoadPath, rootBuildPath); + } + + private static bool IsPreviouslyRevertedDependency(string bundleFileId, ContentUpdateContext contentUpdateContext) + { + foreach (CachedAssetState state in contentUpdateContext.PreviousAssetStateCarryOver) + { + if (state.bundleFileId == bundleFileId) + return true; + } + + return false; + } + + internal static void ApplyAssetEntryUpdates(List operations, ContentUpdateContext contentUpdateContext) + { + UnityEngine.Assertions.Assert.IsNotNull(contentUpdateContext.ContentState.cachedBundles, "CachedBundles is null, cachedBundles requires to apply update."); + foreach (AssetEntryRevertOperation operation in operations) + { + //Check that we can replace the entry in the file registry + if (contentUpdateContext.Registry.ReplaceBundleEntry(Path.GetFileNameWithoutExtension(operation.PreviousBuildPath), operation.PreviousAssetState.bundleFileId)) + { + File.Delete(operation.CurrentBuildPath); + + //sync the internal ids of the catalog entry and asset entry to the cached state + operation.BundleCatalogEntry.InternalId = operation.AssetEntry.BundleFileId = operation.PreviousAssetState.bundleFileId; + var bundleState = contentUpdateContext.ContentState.cachedBundles.FirstOrDefault(s => s.bundleFileId == operation.PreviousAssetState.bundleFileId); + UnityEngine.Assertions.Assert.IsNotNull(bundleState, "Could not find cached bundle state for " + operation.AssetEntry.BundleFileId); + UnityEngine.Assertions.Assert.IsNotNull(bundleState.data, "Could not find cached bundle load data for " + operation.AssetEntry.BundleFileId); + operation.BundleCatalogEntry.Data = bundleState.data; + } + } + } +} diff --git a/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs.meta b/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs.meta index b8592418..b711ae2b 100644 --- a/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs.meta +++ b/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 00f6abb2299813b4881f1f2b0f6640b1 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 00f6abb2299813b4881f1f2b0f6640b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/SceneManagerState.cs b/Editor/Build/SceneManagerState.cs index 73bbd73b..78a741c5 100644 --- a/Editor/Build/SceneManagerState.cs +++ b/Editor/Build/SceneManagerState.cs @@ -1,179 +1,179 @@ -using System; -using System.Collections.Generic; -using System.IO; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.SceneManagement; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.Serialization; - -namespace UnityEditor.AddressableAssets.Build -{ - /// - /// Serializable object that can be used to save and restore the state of the editor scene manager. - /// - [Serializable] - public class SceneManagerState - { - [Serializable] - internal class SceneState - { - [FormerlySerializedAs("m_isActive")] - [SerializeField] - internal bool isActive; - - [FormerlySerializedAs("m_isLoaded")] - [SerializeField] - internal bool isLoaded; - - [FormerlySerializedAs("m_path")] - [SerializeField] - internal string path; - - internal SceneState() - { - } - - internal SceneState(SceneSetup s) - { - isActive = s.isActive; - isLoaded = s.isLoaded; - path = s.path; - } - - internal SceneSetup ToSceneSetup() - { - var ss = new SceneSetup(); - ss.isActive = isActive; - ss.isLoaded = isLoaded; - ss.path = path; - return ss; - } - } - - [Serializable] - internal class EbsSceneState - { - [FormerlySerializedAs("m_guid")] - [SerializeField] - internal string guid; - - [FormerlySerializedAs("m_enabled")] - [SerializeField] - internal bool enabled; - - internal EbsSceneState() - { - } - - internal EbsSceneState(EditorBuildSettingsScene s) - { - guid = s.guid.ToString(); - enabled = s.enabled; - } - - internal EditorBuildSettingsScene GetBuildSettingsScene() - { - return new EditorBuildSettingsScene(new GUID(guid), enabled); - } - } - - [SerializeField] - internal SceneState[] openSceneState; - - [SerializeField] - internal EbsSceneState[] editorBuildSettingsSceneState; - - static SceneManagerState Create(SceneSetup[] scenes) - { - var scenesList = new List(); - var state = new SceneManagerState(); - foreach (var s in scenes) - scenesList.Add(new SceneState(s)); - state.openSceneState = scenesList.ToArray(); - var edbss = new List(); - foreach (var s in BuiltinSceneCache.scenes) - edbss.Add(new EbsSceneState(s)); - state.editorBuildSettingsSceneState = edbss.ToArray(); - return state; - } - - internal SceneSetup[] GetSceneSetups() - { - var setups = new List(); - foreach (var s in openSceneState) - setups.Add(s.ToSceneSetup()); - return setups.ToArray(); - } - - EditorBuildSettingsScene[] GetEditorBuildSettingScenes() - { - var scenes = new List(); - foreach (var s in editorBuildSettingsSceneState) - scenes.Add(s.GetBuildSettingsScene()); - return scenes.ToArray(); - } - - static string s_DefaultPath = Addressables.LibraryPath + "SceneManagerState.json"; - - /// - /// Record the state of the EditorSceneManager and save to a JSON file. - /// - /// The path to save the recorded state. - public static void Record(string path = "") - { - if (string.IsNullOrEmpty(path)) - path = s_DefaultPath; - - try - { - var dir = Path.GetDirectoryName(path); - if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) - Directory.CreateDirectory(dir); - File.WriteAllText(path, JsonUtility.ToJson(Create(EditorSceneManager.GetSceneManagerSetup()))); - } - catch (Exception ex) - { - Debug.LogException(ex); - } - } - - /// - /// Adds a set of scenes to the scene list for use in editor play mode. - /// - /// The scenes to add to the editor scenes list. - public static void AddScenesForPlayMode(List playModeScenes) - { - if (playModeScenes != null) - { - List newScenesList = new List(); - newScenesList.AddRange(BuiltinSceneCache.scenes); - newScenesList.AddRange(playModeScenes); - BuiltinSceneCache.scenes = newScenesList.ToArray(); - } - } - - /// - /// Restore the state of the EditorSceneManager. - /// - /// The path to load the state data from. This file is generated by calling SceneManagerState.Record. - /// If true, the recorded active scenes are restored. EditorBuildSettings.scenes are always restored. - public static void Restore(string path = "", bool restoreSceneManagerSetup = false) - { - if (string.IsNullOrEmpty(path)) - path = s_DefaultPath; - - try - { - var state = JsonUtility.FromJson(File.ReadAllText(path)); - if (restoreSceneManagerSetup) - EditorSceneManager.RestoreSceneManagerSetup(state.GetSceneSetups()); - BuiltinSceneCache.scenes = state.GetEditorBuildSettingScenes(); - } - catch (Exception ex) - { - Debug.LogException(ex); - } - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.Serialization; + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// Serializable object that can be used to save and restore the state of the editor scene manager. + /// + [Serializable] + public class SceneManagerState + { + [Serializable] + internal class SceneState + { + [FormerlySerializedAs("m_isActive")] + [SerializeField] + internal bool isActive; + + [FormerlySerializedAs("m_isLoaded")] + [SerializeField] + internal bool isLoaded; + + [FormerlySerializedAs("m_path")] + [SerializeField] + internal string path; + + internal SceneState() + { + } + + internal SceneState(SceneSetup s) + { + isActive = s.isActive; + isLoaded = s.isLoaded; + path = s.path; + } + + internal SceneSetup ToSceneSetup() + { + var ss = new SceneSetup(); + ss.isActive = isActive; + ss.isLoaded = isLoaded; + ss.path = path; + return ss; + } + } + + [Serializable] + internal class EbsSceneState + { + [FormerlySerializedAs("m_guid")] + [SerializeField] + internal string guid; + + [FormerlySerializedAs("m_enabled")] + [SerializeField] + internal bool enabled; + + internal EbsSceneState() + { + } + + internal EbsSceneState(EditorBuildSettingsScene s) + { + guid = s.guid.ToString(); + enabled = s.enabled; + } + + internal EditorBuildSettingsScene GetBuildSettingsScene() + { + return new EditorBuildSettingsScene(new GUID(guid), enabled); + } + } + + [SerializeField] + internal SceneState[] openSceneState; + + [SerializeField] + internal EbsSceneState[] editorBuildSettingsSceneState; + + static SceneManagerState Create(SceneSetup[] scenes) + { + var scenesList = new List(); + var state = new SceneManagerState(); + foreach (var s in scenes) + scenesList.Add(new SceneState(s)); + state.openSceneState = scenesList.ToArray(); + var edbss = new List(); + foreach (var s in BuiltinSceneCache.scenes) + edbss.Add(new EbsSceneState(s)); + state.editorBuildSettingsSceneState = edbss.ToArray(); + return state; + } + + internal SceneSetup[] GetSceneSetups() + { + var setups = new List(); + foreach (var s in openSceneState) + setups.Add(s.ToSceneSetup()); + return setups.ToArray(); + } + + EditorBuildSettingsScene[] GetEditorBuildSettingScenes() + { + var scenes = new List(); + foreach (var s in editorBuildSettingsSceneState) + scenes.Add(s.GetBuildSettingsScene()); + return scenes.ToArray(); + } + + static string s_DefaultPath = Addressables.LibraryPath + "SceneManagerState.json"; + + /// + /// Record the state of the EditorSceneManager and save to a JSON file. + /// + /// The path to save the recorded state. + public static void Record(string path = "") + { + if (string.IsNullOrEmpty(path)) + path = s_DefaultPath; + + try + { + var dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) + Directory.CreateDirectory(dir); + File.WriteAllText(path, JsonUtility.ToJson(Create(EditorSceneManager.GetSceneManagerSetup()))); + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + + /// + /// Adds a set of scenes to the scene list for use in editor play mode. + /// + /// The scenes to add to the editor scenes list. + public static void AddScenesForPlayMode(List playModeScenes) + { + if (playModeScenes != null) + { + List newScenesList = new List(); + newScenesList.AddRange(BuiltinSceneCache.scenes); + newScenesList.AddRange(playModeScenes); + BuiltinSceneCache.scenes = newScenesList.ToArray(); + } + } + + /// + /// Restore the state of the EditorSceneManager. + /// + /// The path to load the state data from. This file is generated by calling SceneManagerState.Record. + /// If true, the recorded active scenes are restored. EditorBuildSettings.scenes are always restored. + public static void Restore(string path = "", bool restoreSceneManagerSetup = false) + { + if (string.IsNullOrEmpty(path)) + path = s_DefaultPath; + + try + { + var state = JsonUtility.FromJson(File.ReadAllText(path)); + if (restoreSceneManagerSetup) + EditorSceneManager.RestoreSceneManagerSetup(state.GetSceneSetups()); + BuiltinSceneCache.scenes = state.GetEditorBuildSettingScenes(); + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + } +} diff --git a/Editor/Build/SceneManagerState.cs.meta b/Editor/Build/SceneManagerState.cs.meta index 96ec7fee..26f8d19d 100644 --- a/Editor/Build/SceneManagerState.cs.meta +++ b/Editor/Build/SceneManagerState.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: e32f647f6eec5dd458031b2ccab2880b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: e32f647f6eec5dd458031b2ccab2880b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Build/ShaderBundleNaming.cs b/Editor/Build/ShaderBundleNaming.cs index 88a25577..23cd9f5d 100644 --- a/Editor/Build/ShaderBundleNaming.cs +++ b/Editor/Build/ShaderBundleNaming.cs @@ -1,27 +1,27 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace UnityEditor.AddressableAssets.Build -{ - /// - /// Naming conventions for the built-in shader bundle name prefix. - /// - public enum ShaderBundleNaming - { - /// - /// Set the built-in shader bundle name prefix to the hash of the project name. - /// - ProjectName, - - /// - /// Set the built-in shader bundle name prefix to the guid of the default group. - /// - DefaultGroupGuid, - - /// - /// Set the built-in shader bundle name prefix to the user specified value. - /// - Custom - } -} +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// Naming conventions for the built-in shader bundle name prefix. + /// + public enum ShaderBundleNaming + { + /// + /// Set the built-in shader bundle name prefix to the hash of the project name. + /// + ProjectName, + + /// + /// Set the built-in shader bundle name prefix to the guid of the default group. + /// + DefaultGroupGuid, + + /// + /// Set the built-in shader bundle name prefix to the user specified value. + /// + Custom + } +} diff --git a/Editor/Build/ShaderBundleNaming.cs.meta b/Editor/Build/ShaderBundleNaming.cs.meta index a8e86c2c..b7829dc1 100644 --- a/Editor/Build/ShaderBundleNaming.cs.meta +++ b/Editor/Build/ShaderBundleNaming.cs.meta @@ -1,11 +1,11 @@ -fileFormatVersion: 2 -guid: 35ddb9e112b0424479043537f5479a5b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 35ddb9e112b0424479043537f5479a5b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer.meta b/Editor/BuildReportVisualizer.meta index d910ca82..6e977964 100644 --- a/Editor/BuildReportVisualizer.meta +++ b/Editor/BuildReportVisualizer.meta @@ -1,8 +1,8 @@ -fileFormatVersion: 2 -guid: c50baa6dc4a739842acba729ee9998a5 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: c50baa6dc4a739842acba729ee9998a5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources.meta b/Editor/BuildReportVisualizer/BuildReport Resources.meta index 0a4e9daa..5f678821 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources.meta @@ -1,8 +1,8 @@ -fileFormatVersion: 2 -guid: 65c82791d288eae4b8814a70bce6c8d2 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 65c82791d288eae4b8814a70bce6c8d2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons.meta index 593d1169..92df5ebf 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons.meta @@ -1,8 +1,8 @@ -fileFormatVersion: 2 -guid: e8172907ebad1ec48b261c4e12a371a3 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: e8172907ebad1ec48b261c4e12a371a3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon.png.meta index 75b0e33d..fcaba107 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon.png.meta @@ -1,158 +1,158 @@ -fileFormatVersion: 2 -guid: 3b40c3dceab2ff14cb0e00e989fd8b27 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Windows Store Apps - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: CloudRendering - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 3b40c3dceab2ff14cb0e00e989fd8b27 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: CloudRendering + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@2x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@2x.png.meta index 049bd332..a8b79a5d 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@2x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@2x.png.meta @@ -1,158 +1,158 @@ -fileFormatVersion: 2 -guid: 0127c38a607d9474c820c7f5044c18b4 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Windows Store Apps - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: CloudRendering - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 0127c38a607d9474c820c7f5044c18b4 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: CloudRendering + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@3x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@3x.png.meta index b8699ef2..e42aad9b 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@3x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@3x.png.meta @@ -1,158 +1,158 @@ -fileFormatVersion: 2 -guid: 66c2b738157840b43a4f923dc575193b -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Windows Store Apps - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: CloudRendering - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 66c2b738157840b43a4f923dc575193b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: CloudRendering + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon.png.meta index 552be3b8..f4471431 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 970a95875c9b7474ba926b947e8cc477 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 970a95875c9b7474ba926b947e8cc477 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon@2x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon@2x.png.meta index 550eff4f..b2b76c20 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon@2x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon@2x.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 7421e9434772c1542ac5a39c1a9accc5 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 7421e9434772c1542ac5a39c1a9accc5 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon.png.meta index 6a21f6d2..cb60d551 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 1ca1e1e405efb114fa23798a8d0c4c56 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 1ca1e1e405efb114fa23798a8d0c4c56 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon@2x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon@2x.png.meta index abb1d95a..5cbbb316 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon@2x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon@2x.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 566514eeee40fbb4095bb20d9ca5ef1b -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 566514eeee40fbb4095bb20d9ca5ef1b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon.png.meta index 65fab606..25115057 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 351af98fa765ba1498bcad1e9100d610 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 351af98fa765ba1498bcad1e9100d610 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon@2x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon@2x.png.meta index 80c7224f..6b52356b 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon@2x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon@2x.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 69eef738ab4fa5d4c82e3f424ea1a5cd -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 69eef738ab4fa5d4c82e3f424ea1a5cd +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon.png.meta index 4562300f..a240e65f 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon.png.meta @@ -1,158 +1,158 @@ -fileFormatVersion: 2 -guid: af91525c769cf6847bb9b9e32c74db73 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Windows Store Apps - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: CloudRendering - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: af91525c769cf6847bb9b9e32c74db73 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: CloudRendering + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon@2x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon@2x.png.meta index 0280c6b1..4efc7eba 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon@2x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon@2x.png.meta @@ -1,158 +1,158 @@ -fileFormatVersion: 2 -guid: 21df0a1c085254641905e0eb1dca9806 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Windows Store Apps - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: CloudRendering - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 21df0a1c085254641905e0eb1dca9806 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: CloudRendering + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneOSXIcon.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneOSXIcon.png.meta index 35d7f1af..3cb0267b 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneOSXIcon.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneOSXIcon.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: a8a8a51840bce43499129ca737ca10a7 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: a8a8a51840bce43499129ca737ca10a7 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon.png.meta index 2ea56362..77536e19 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 5a5529cb00c9319488699e8367ff0f96 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 5a5529cb00c9319488699e8367ff0f96 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon@2x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon@2x.png.meta index 13a012f3..0d9ac441 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon@2x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon@2x.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 3beb0fb679dee7f4ca526692b1702fc4 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 3beb0fb679dee7f4ca526692b1702fc4 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon.png.meta index fa87c930..92b34747 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: ece4fc36f044b2544aa5ce4f5cd12422 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: ece4fc36f044b2544aa5ce4f5cd12422 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon@2x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon@2x.png.meta index d232c71e..72f6fb41 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon@2x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon@2x.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: a4691412a8ea49a4796116d3d5f289cc -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: a4691412a8ea49a4796116d3d5f289cc +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon.png.meta index 9866e35a..16678232 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 49850dfe65879f949bd15bb7738b7bdf -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 49850dfe65879f949bd15bb7738b7bdf +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon@2x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon@2x.png.meta index 9880149c..5487bb5a 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon@2x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon@2x.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 764d4b52473c57c43a471351bb59abe1 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 764d4b52473c57c43a471351bb59abe1 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon.png.meta index e22c87e3..e95dfc88 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 596c9ec38e3138046aff034674a6887c -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 596c9ec38e3138046aff034674a6887c +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon@2x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon@2x.png.meta index cf8ae514..e7f38427 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon@2x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon@2x.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 770340dbd8f200e45b2bb9e820baa15e -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 770340dbd8f200e45b2bb9e820baa15e +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon.png.meta index 507e22e8..6ec47b3b 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 8a5c9b2d5cfd7b94caca42edabdf243f -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 8a5c9b2d5cfd7b94caca42edabdf243f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon@2x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon@2x.png.meta index 2c712722..16a8c3da 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon@2x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon@2x.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 59549f72de25b4c46b48c01b3e64ec90 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 59549f72de25b4c46b48c01b3e64ec90 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon.png.meta index f251cc67..14f2e5a6 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 3fd787210f08d364186b9df36062df04 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 3fd787210f08d364186b9df36062df04 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon@2x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon@2x.png.meta index a4b9451f..0dc88127 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon@2x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon@2x.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 7f9793fab7c5a2d49a99acdc614bf45d -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 1 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 7f9793fab7c5a2d49a99acdc614bf45d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 1 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward.png.meta index 1c3e2f35..756621ed 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 5252304aa623387469db31285ab55959 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 5252304aa623387469db31285ab55959 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward@2x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward@2x.png.meta index 888e2800..20209231 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward@2x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward@2x.png.meta @@ -1,134 +1,134 @@ -fileFormatVersion: 2 -guid: 741fd6a7eb857a74b939184269d01239 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: 741fd6a7eb857a74b939184269d01239 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_icon dropdown@2x.png.meta b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_icon dropdown@2x.png.meta index d5f887b8..15addb54 100644 --- a/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_icon dropdown@2x.png.meta +++ b/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_icon dropdown@2x.png.meta @@ -1,99 +1,99 @@ -fileFormatVersion: 2 -guid: fd53d86c6d81efc45bd1caf873084af4 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 1 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMasterTextureLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 0 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - spritePackingTag: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: fd53d86c6d81efc45bd1caf873084af4 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/BuildReportVisualizer/BuildReportListView.cs b/Editor/BuildReportVisualizer/BuildReportListView.cs index 69614ec4..4e5dff70 100644 --- a/Editor/BuildReportVisualizer/BuildReportListView.cs +++ b/Editor/BuildReportVisualizer/BuildReportListView.cs @@ -1,272 +1,272 @@ -#if UNITY_2022_2_OR_NEWER -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UnityEditor; -using UnityEditor.AddressableAssets.Build.Layout; -using UnityEditor.AddressableAssets.Settings; -using UnityEditor.Build.Reporting; -using UnityEditor.UIElements; -using UnityEngine; -using UnityEngine.UIElements; - -namespace UnityEditor.AddressableAssets.BuildReportVisualizer -{ - [Serializable] - class BuildReportListView : IAddressableView - { - BuildReportWindow m_Window; - ListView m_ListView; - - VisualTreeAsset m_ReportListItemTreeAsset; - - [SerializeField] - List m_BuildReportItems = new List(); - - static Dictionary s_PlatformIconClasses = new Dictionary(); - - [Serializable] - internal class BuildReportListItem - { - public int Id { get; } - public string FilePath { get; } - public BuildLayout Layout { get; set; } - - public BuildReportListItem(int id, string filePath, BuildLayout layout) - { - Id = id; - FilePath = filePath; - Layout = layout; - } - } - - public BuildReportListView(BuildReportWindow window, VisualTreeAsset reportListItemTreeAsset) - { - m_Window = window; - m_ReportListItemTreeAsset = reportListItemTreeAsset; - } - - public void CreateGUI(VisualElement rootVisualElement) - { - m_BuildReportItems.Clear(); - - for (int i = 0; i < ProjectConfigData.BuildReportFilePaths.Count; i++) - { - BuildLayout layout = null; - string path = ProjectConfigData.BuildReportFilePaths[i]; - if (File.Exists(path)) - { - layout = BuildLayout.Open(path); - } - - m_BuildReportItems.Insert(0, new BuildReportListItem(i, path, layout)); - } - - - UQueryBuilder listQuery = rootVisualElement.Query(name: BuildReportUtility.ReportsList); - m_ListView = listQuery.First(); - - m_ListView.makeItem = () => - { - var item = m_ReportListItemTreeAsset.Clone(); - item.Q(BuildReportUtility.ReportsListItemContainerLefthandElements).style.marginTop = new StyleLength(new Length(2f, LengthUnit.Pixel)); - item.Q(BuildReportUtility.ReportsListItemContainerRighthandElements).style.marginTop = new StyleLength(new Length(2f, LengthUnit.Pixel)); - item.style.unityTextAlign = TextAnchor.MiddleCenter; - return item; - }; - m_ListView.bindItem = (e, i) => CreateItem(e, i); - m_ListView.itemsSource = m_BuildReportItems; - m_ListView.selectionChanged -= items => OnItemSelected(items); - m_ListView.selectionChanged += items => OnItemSelected(items); - } - - static BuildLayout LoadLayout(string filePath) - { - if (!File.Exists(filePath)) - return null; - try - { - string json = System.IO.File.ReadAllText(filePath); - BuildLayout layout = JsonUtility.FromJson(json); - return layout; - } - catch (Exception e) - { - Debug.Log($"Failed to read BuildReport from {filePath}, with Exception: {e}"); - throw; - } - } - - void CreateItem(VisualElement element, int index) - { - BuildReportListItem reportListItem = m_BuildReportItems[index]; - var buildStatusImage = element.Q(BuildReportUtility.ReportsListItemBuildStatus); - var buildPlatformImage = element.Q(BuildReportUtility.ReportsListItemBuildPlatform); - var buildTimeStampLabel = element.Q