From 4d70c64d211e8e8617fca9a4fe392987938f6c6f Mon Sep 17 00:00:00 2001 From: Minepatcher Date: Wed, 29 Oct 2025 17:02:46 -0600 Subject: [PATCH] Update ModSDK to latest version & fix CoreLib.Resources Update: - ModSDK for version 1.1.2.6 Fix: - Missing Properties for ModResourceLocator.cs --- .idea/.idea.CoreLib-main/.idea/encodings.xml | 4 + .../.idea.CoreLib-main/.idea/indexLayout.xml | 8 + .../.idea/projectSettingsUpdater.xml | 8 + .idea/.idea.CoreLib-main/.idea/vcs.xml | 6 + .idea/.idea.CoreLib-main/.idea/workspace.xml | 6283 +++++++++++++++++ .idea/.name | 1 - .idea/indexLayout.xml | 8 + .idea/projectSettingsUpdater.xml | 8 + .idea/workspace.xml | 69 +- .../CoreLib.Editor/Editor/RenderingFix.cs | 2 +- .../Addressables/ModResourceLocator.cs | 4 +- .../Resources/Rendering/EditorKit RP.asset | 36 +- Assets/DefaultVolumeProfile.asset | 15 + Assets/DefaultVolumeProfile.asset.meta | 8 + Assets/ModSDK/EditorAssemblies.zip | Bin 54683 -> 54710 bytes .../ModSDK}/Resources.meta | 2 +- .../ModSDK/Resources}/Shaders.meta | 2 +- .../ModSDK}/Resources/Textures.meta | 2 +- Assets/Test.unity | 444 -- ...niversalRenderPipelineGlobalSettings.asset | 430 +- Packages/com.unity.addressables/CHANGELOG.md | 1424 ++++ .../com.unity.addressables/CHANGELOG.md.meta | 7 + .../Editor.meta} | 2 +- .../AddressableAssetSettingsDefaultObject.cs | 181 + ...ressableAssetSettingsDefaultObject.cs.meta | 11 + .../Editor/AddressableEditorInitialization.cs | 66 + .../AddressableEditorInitialization.cs.meta | 11 + .../Editor/AssemblyInfo.cs | 10 + .../Editor/AssemblyInfo.cs.meta | 11 + .../com.unity.addressables/Editor/Build.meta | 8 + .../Editor/Build/AddressableAnalytics.cs | 687 ++ .../Editor/Build/AddressableAnalytics.cs.meta | 11 + .../Build/AddressableAssetSettingsLocator.cs | 350 + .../AddressableAssetSettingsLocator.cs.meta | 11 + .../Build/AddressablesBuildScriptHooks.cs | 74 + .../AddressablesBuildScriptHooks.cs.meta | 11 + .../Build/AddressablesDataBuilderInput.cs | 117 + .../AddressablesDataBuilderInput.cs.meta | 11 + .../Editor/Build/AddressablesDataBuilders.cs | 143 + .../Build/AddressablesDataBuilders.cs.meta | 11 + .../Build/AddressablesPlayerBuildProcessor.cs | 187 + .../AddressablesPlayerBuildProcessor.cs.meta | 11 + .../Editor/Build/AnalyzeRules.meta | 8 + .../Build/AnalyzeRules/AnalyzeResultData.cs | 89 + .../AnalyzeRules/AnalyzeResultData.cs.meta | 11 + .../Editor/Build/AnalyzeRules/AnalyzeRule.cs | 126 + .../Build/AnalyzeRules/AnalyzeRule.cs.meta | 11 + .../Build/AnalyzeRules/AnalyzeSystem.cs | 217 + .../Build/AnalyzeRules/AnalyzeSystem.cs.meta | 11 + .../Build/AnalyzeRules/BuildBundleLayout.cs | 139 + .../AnalyzeRules/BuildBundleLayout.cs.meta | 11 + .../Build/AnalyzeRules/BundleRuleBase.cs | 691 ++ .../Build/AnalyzeRules/BundleRuleBase.cs.meta | 11 + .../CheckBundleDupeDependencies.cs | 329 + .../CheckBundleDupeDependencies.cs.meta | 11 + .../CheckResourcesDupeDependencies.cs | 62 + .../CheckResourcesDupeDependencies.cs.meta | 11 + .../CheckSceneDupeDependencies.cs | 68 + .../CheckSceneDupeDependencies.cs.meta | 11 + .../Editor/Build/BuildPipelineTasks.meta | 8 + .../AddHashToBundleNameTask.cs | 107 + .../AddHashToBundleNameTask.cs.meta | 11 + .../BuildLayoutGenerationTask.cs | 1330 ++++ .../BuildLayoutGenerationTask.cs.meta | 11 + .../BuildPipelineTasks/ExtractDataTask.cs | 76 + .../ExtractDataTask.cs.meta | 11 + .../GenerateLocationListsTask.cs | 370 + .../GenerateLocationListsTask.cs.meta | 11 + .../Editor/Build/BuildUtility.cs | 109 + .../Editor/Build/BuildUtility.cs.meta | 11 + .../Editor/Build/BuiltInBundleNaming.cs | 27 + .../Editor/Build/BuiltInBundleNaming.cs.meta | 11 + .../Editor/Build/CcdBuildEvents.cs | 1011 +++ .../Editor/Build/CcdBuildEvents.cs.meta | 11 + .../Editor/Build/ContentUpdateScript.cs | 1083 +++ .../Editor/Build/ContentUpdateScript.cs.meta | 11 + .../Editor/Build/DataBuilderInterfaces.cs | 67 + .../Build/DataBuilderInterfaces.cs.meta | 11 + .../Editor/Build/DataBuilders.meta | 8 + .../AddressableAssetsBuildContext.cs | 99 + .../AddressableAssetsBuildContext.cs.meta | 11 + .../AddressableAssetsBundleBuildParameters.cs | 97 + ...essableAssetsBundleBuildParameters.cs.meta | 11 + .../DataBuilders/BuildLayoutParameters.cs | 81 + .../BuildLayoutParameters.cs.meta | 3 + .../Build/DataBuilders/BuildScriptBase.cs | 420 ++ .../DataBuilders/BuildScriptBase.cs.meta | 11 + .../Build/DataBuilders/BuildScriptFastMode.cs | 65 + .../DataBuilders/BuildScriptFastMode.cs.meta | 11 + .../DataBuilders/BuildScriptPackedMode.cs | 1618 +++++ .../BuildScriptPackedMode.cs.meta | 11 + .../DataBuilders/BuildScriptPackedPlayMode.cs | 94 + .../BuildScriptPackedPlayMode.cs.meta | 11 + .../Editor/Build/DirectoryUtility.cs | 88 + .../Editor/Build/DirectoryUtility.cs.meta | 11 + .../Build/FastModeInitializationOperation.cs | 120 + .../FastModeInitializationOperation.cs.meta | 11 + .../Editor/Build/FileRegistry.cs | 80 + .../Editor/Build/FileRegistry.cs.meta | 11 + .../Editor/Build/Layout.meta | 8 + .../Editor/Build/Layout/BuildLayout.cs | 1395 ++++ .../Editor/Build/Layout/BuildLayout.cs.meta | 11 + .../Editor/Build/Layout/BuildLayoutEnums.cs | 274 + .../Build/Layout/BuildLayoutEnums.cs.meta | 11 + .../Editor/Build/Layout/BuildLayoutHelpers.cs | 153 + .../Build/Layout/BuildLayoutHelpers.cs.meta | 11 + .../Editor/Build/Layout/BuildLayoutPrinter.cs | 283 + .../Build/Layout/BuildLayoutPrinter.cs.meta | 11 + .../Editor/Build/Layout/BuildLayoutSummary.cs | 210 + .../Build/Layout/BuildLayoutSummary.cs.meta | 11 + .../Editor/Build/MonoScriptBundleNaming.cs | 23 + .../Build/MonoScriptBundleNaming.cs.meta | 11 + ...vertUnchangedAssetsToPreviousAssetState.cs | 248 + ...nchangedAssetsToPreviousAssetState.cs.meta | 11 + .../Editor/Build/SceneManagerState.cs | 179 + .../Editor/Build/SceneManagerState.cs.meta | 11 + .../Editor/Build/SharedBundleSettings.cs | 18 + .../Editor/Build/SharedBundleSettings.cs.meta | 11 + .../Editor/BuildReportVisualizer.meta | 8 + .../BuildReport Resources.meta | 8 + .../BuildReport Resources/Icons.meta | 8 + .../Icons/Button_LeftPanel_DarkTheme.png | Bin 0 -> 221 bytes .../Icons/Button_LeftPanel_DarkTheme.png.meta | 158 + .../Icons/Button_LeftPanel_DarkTheme@2x.png | Bin 0 -> 294 bytes .../Button_LeftPanel_DarkTheme@2x.png.meta | 158 + .../Icons/Button_LeftPanel_LightTheme.png | Bin 0 -> 216 bytes .../Button_LeftPanel_LightTheme.png.meta | 158 + .../Icons/Button_LeftPanel_LightTheme@2x.png | Bin 0 -> 275 bytes .../Button_LeftPanel_LightTheme@2x.png.meta | 158 + .../Icons/Button_RightPanel_DarkTheme.png | Bin 0 -> 222 bytes .../Button_RightPanel_DarkTheme.png.meta | 158 + .../Icons/Button_RightPanel_DarkTheme@2x.png | Bin 0 -> 290 bytes .../Button_RightPanel_DarkTheme@2x.png.meta | 158 + .../Icons/Button_RightPanel_LightTheme.png | Bin 0 -> 212 bytes .../Button_RightPanel_LightTheme.png.meta | 158 + .../Icons/Button_RightPanel_LightTheme@2x.png | Bin 0 -> 275 bytes .../Button_RightPanel_LightTheme@2x.png.meta | 158 + .../Icons/FileNoIcon.png | Bin 0 -> 323 bytes .../Icons/FileNoIcon.png.meta | 158 + .../Icons/FileNoIcon@2x.png | Bin 0 -> 416 bytes .../Icons/FileNoIcon@2x.png.meta | 158 + .../Icons/FileNoIcon@3x.png | Bin 0 -> 559 bytes .../Icons/FileNoIcon@3x.png.meta | 158 + .../Icons/PlatformAndroidIcon.png | Bin 0 -> 369 bytes .../Icons/PlatformAndroidIcon.png.meta | 134 + .../Icons/PlatformAndroidIcon@2x.png | Bin 0 -> 860 bytes .../Icons/PlatformAndroidIcon@2x.png.meta | 134 + .../Icons/PlatformLuminIcon.png | Bin 0 -> 492 bytes .../Icons/PlatformLuminIcon.png.meta | 134 + .../Icons/PlatformLuminIcon@2x.png | Bin 0 -> 1062 bytes .../Icons/PlatformLuminIcon@2x.png.meta | 134 + .../Icons/PlatformPS4Icon.png | Bin 0 -> 447 bytes .../Icons/PlatformPS4Icon.png.meta | 134 + .../Icons/PlatformPS4Icon@2x.png | Bin 0 -> 1036 bytes .../Icons/PlatformPS4Icon@2x.png.meta | 134 + .../Icons/PlatformStadiaIcon.png | Bin 0 -> 1426 bytes .../Icons/PlatformStadiaIcon.png.meta | 158 + .../Icons/PlatformStadiaIcon@2x.png | Bin 0 -> 1558 bytes .../Icons/PlatformStadiaIcon@2x.png.meta | 158 + .../Icons/PlatformStandaloneLinux64Icon.png | Bin 0 -> 674 bytes .../PlatformStandaloneLinux64Icon.png.meta | 134 + .../PlatformStandaloneLinux64Icon@2x.png | Bin 0 -> 1676 bytes .../PlatformStandaloneLinux64Icon@2x.png.meta | 134 + .../Icons/PlatformStandaloneOSXIcon.png | Bin 0 -> 396 bytes .../Icons/PlatformStandaloneOSXIcon.png.meta | 134 + .../Icons/PlatformStandaloneOSXIcon@2x.png | Bin 0 -> 983 bytes .../PlatformStandaloneOSXIcon@2x.png.meta | 134 + .../Icons/PlatformStandaloneWindowsIcon.png | Bin 0 -> 454 bytes .../PlatformStandaloneWindowsIcon.png.meta | 134 + .../PlatformStandaloneWindowsIcon@2x.png | Bin 0 -> 974 bytes .../PlatformStandaloneWindowsIcon@2x.png.meta | 134 + .../Icons/PlatformSwitchIcon.png | Bin 0 -> 483 bytes .../Icons/PlatformSwitchIcon.png.meta | 134 + .../Icons/PlatformSwitchIcon@2x.png | Bin 0 -> 876 bytes .../Icons/PlatformSwitchIcon@2x.png.meta | 134 + .../Icons/PlatformWSAPlayerIcon.png | Bin 0 -> 560 bytes .../Icons/PlatformWSAPlayerIcon.png.meta | 134 + .../Icons/PlatformWSAPlayerIcon@2x.png | Bin 0 -> 1182 bytes .../Icons/PlatformWSAPlayerIcon@2x.png.meta | 134 + .../Icons/PlatformWebGLIcon.png | Bin 0 -> 496 bytes .../Icons/PlatformWebGLIcon.png.meta | 134 + .../Icons/PlatformWebGLIcon@2x.png | Bin 0 -> 1338 bytes .../Icons/PlatformWebGLIcon@2x.png.meta | 134 + .../Icons/PlatformXboxOneIcon.png | Bin 0 -> 502 bytes .../Icons/PlatformXboxOneIcon.png.meta | 134 + .../Icons/PlatformXboxOneIcon@2x.png | Bin 0 -> 1189 bytes .../Icons/PlatformXboxOneIcon@2x.png.meta | 134 + .../Icons/PlatformiOSIcon.png | Bin 0 -> 522 bytes .../Icons/PlatformiOSIcon.png.meta | 134 + .../Icons/PlatformiOSIcon@2x.png | Bin 0 -> 1406 bytes .../Icons/PlatformiOSIcon@2x.png.meta | 134 + .../Icons/PlatformtvOSIcon.png | Bin 0 -> 465 bytes .../Icons/PlatformtvOSIcon.png.meta | 134 + .../Icons/PlatformtvOSIcon@2x.png | Bin 0 -> 1169 bytes .../Icons/PlatformtvOSIcon@2x.png.meta | 134 + .../Icons/d_History.Forward.png | Bin 0 -> 260 bytes .../Icons/d_History.Forward.png.meta | 134 + .../Icons/d_History.Forward@2x.png | Bin 0 -> 378 bytes .../Icons/d_History.Forward@2x.png.meta | 134 + .../Icons/d_icon dropdown@2x.png | Bin 0 -> 282 bytes .../Icons/d_icon dropdown@2x.png.meta | 99 + .../BuildReportListView.cs | 281 + .../BuildReportListView.cs.meta | 11 + .../BuildReportWindow.cs | 380 + .../BuildReportWindow.cs.meta | 17 + .../BuildReportVisualizer/ContentView.meta | 8 + .../ContentView/AssetsContentView.cs | 487 ++ .../ContentView/AssetsContentView.cs.meta | 11 + .../ContentView/BundlesContentView.cs | 479 ++ .../ContentView/BundlesContentView.cs.meta | 11 + .../ContentView/ContentView.cs | 352 + .../ContentView/ContentView.cs.meta | 11 + .../ContentView/DetailsView.cs | 87 + .../ContentView/DetailsView.cs.meta | 11 + .../DuplicatedAssetsContentView.cs | 299 + .../DuplicatedAssetsContentView.cs.meta | 11 + .../ContentView/GroupsContentView.cs | 475 ++ .../ContentView/GroupsContentView.cs.meta | 11 + .../ContentView/LabelsContentView.cs | 394 ++ .../ContentView/LabelsContentView.cs.meta | 11 + .../BuildReportVisualizer/DetailsPanel.meta | 8 + .../DetailsPanel/DetailsContentView.cs | 556 ++ .../DetailsPanel/DetailsContentView.cs.meta | 11 + .../DetailsPanel/DetailsContents.cs | 25 + .../DetailsPanel/DetailsContents.cs.meta | 11 + .../DetailsPanel/DetailsSummaryView.cs | 187 + .../DetailsPanel/DetailsSummaryView.cs.meta | 11 + .../DetailsPanel/DetailsUtility.cs | 45 + .../DetailsPanel/DetailsUtility.cs.meta | 11 + .../BuildReportVisualizer/IAddressableView.cs | 9 + .../IAddressableView.cs.meta | 11 + .../IBuildReportConsumer.cs | 10 + .../IBuildReportConsumer.cs.meta | 11 + .../MainPanelSummaryTab.cs | 154 + .../MainPanelSummaryTab.cs.meta | 11 + .../BuildReportVisualizer/MainToolbar.cs | 89 + .../BuildReportVisualizer/MainToolbar.cs.meta | 11 + .../ToggleTextExpansionButton.cs | 29 + .../ToggleTextExpansionButton.cs.meta | 11 + .../UIToolKitAssets.meta | 8 + .../UIToolKitAssets/StyleSheets.meta | 8 + .../StyleSheets/DetailsPanelSummary.uss | 52 + .../StyleSheets/DetailsPanelSummary.uss.meta | 11 + .../StyleSheets/DetailsViewDark.uss | 3 + .../StyleSheets/DetailsViewDark.uss.meta | 3 + .../StyleSheets/DetailsViewLight.uss | 3 + .../StyleSheets/DetailsViewLight.uss.meta | 3 + .../StyleSheets/DrillableListItemStyle.uss | 57 + .../DrillableListItemStyle.uss.meta | 11 + .../StyleSheets/MainToolbarButtons.uss | 26 + .../StyleSheets/MainToolbarButtons.uss.meta | 11 + .../StyleSheets/MainToolbarButtonsDark.uss | 13 + .../MainToolbarButtonsDark.uss.meta | 11 + .../StyleSheets/MainToolbarButtonsLight.uss | 11 + .../MainToolbarButtonsLight.uss.meta | 11 + .../StyleSheets/ReportListItem.uss | 85 + .../StyleSheets/ReportListItem.uss.meta | 11 + .../StyleSheets/SummaryTab.uss | 61 + .../StyleSheets/SummaryTab.uss.meta | 11 + .../StyleSheets/SummaryTabCardDark.uss | 3 + .../StyleSheets/SummaryTabCardDark.uss.meta | 11 + .../StyleSheets/SummaryTabCardLight.uss | 3 + .../StyleSheets/SummaryTabCardLight.uss.meta | 11 + .../StyleSheets/SummaryTabDark.uss | 3 + .../StyleSheets/SummaryTabDark.uss.meta | 11 + .../StyleSheets/SummaryTabLight.uss | 3 + .../StyleSheets/SummaryTabLight.uss.meta | 11 + .../StyleSheets/TreeViewItem.uss | 56 + .../StyleSheets/TreeViewItem.uss.meta | 11 + .../StyleSheets/TreeViewNavigableItem.uss | 21 + .../TreeViewNavigableItem.uss.meta | 11 + .../UIToolKitAssets/UXML.meta | 8 + .../UXML/BuildReportWindow.uxml | 24 + .../UXML/BuildReportWindow.uxml.meta | 10 + .../UIToolKitAssets/UXML/ContentTab.uxml | 13 + .../UIToolKitAssets/UXML/ContentTab.uxml.meta | 10 + .../UIToolKitAssets/UXML/DetailsPanel.uxml | 22 + .../UXML/DetailsPanel.uxml.meta | 10 + .../UXML/DetailsPanelSummaryAsset.uxml | 4 + .../UXML/DetailsPanelSummaryAsset.uxml.meta | 10 + .../UXML/DetailsPanelSummaryBundle.uxml | 4 + .../UXML/DetailsPanelSummaryBundle.uxml.meta | 10 + .../DetailsPanelSummaryNavigableBundle.uxml | 13 + ...tailsPanelSummaryNavigableBundle.uxml.meta | 10 + .../DetailsPanelSummaryNavigableItem.uxml | 9 + ...DetailsPanelSummaryNavigableItem.uxml.meta | 10 + .../UXML/DrillableListViewItem.uxml | 8 + .../UXML/DrillableListViewItem.uxml.meta | 10 + .../UIToolKitAssets/UXML/MainPanel.uxml | 13 + .../UIToolKitAssets/UXML/MainPanel.uxml.meta | 10 + .../UIToolKitAssets/UXML/MainToolbar.uxml | 17 + .../UXML/MainToolbar.uxml.meta | 10 + .../UIToolKitAssets/UXML/PotentialIssues.uxml | 14 + .../UXML/PotentialIssues.uxml.meta | 10 + .../UIToolKitAssets/UXML/ReportsListItem.uxml | 13 + .../UXML/ReportsListItem.uxml.meta | 10 + .../UXML/ReportsListPanel.uxml | 3 + .../UXML/ReportsListPanel.uxml.meta | 10 + .../UIToolKitAssets/UXML/SummaryTab.uxml | 3 + .../UIToolKitAssets/UXML/SummaryTab.uxml.meta | 10 + .../UIToolKitAssets/UXML/TreeViewItem.uxml | 7 + .../UXML/TreeViewItem.uxml.meta | 10 + .../UXML/TreeViewNavigableItem.uxml | 8 + .../UXML/TreeViewNavigableItem.uxml.meta | 10 + .../Editor/BuildReportVisualizer/Utility.meta | 8 + .../Utility/BuildReportHelperConsumer.cs | 209 + .../Utility/BuildReportHelperConsumer.cs.meta | 11 + .../Utility/BuildReportUtility.cs | 475 ++ .../Utility/BuildReportUtility.cs.meta | 11 + .../Utility/DetailsListItem.cs | 36 + .../Utility/DetailsListItem.cs.meta | 11 + .../Utility/DetailsStack.cs | 33 + .../Utility/DetailsStack.cs.meta | 11 + .../Utility/DetailsSummaryBuilder.cs | 134 + .../Utility/DetailsSummaryBuilder.cs.meta | 11 + .../Utility/SummaryRowBuilder.cs | 147 + .../Utility/SummaryRowBuilder.cs.meta | 11 + .../Utility/TreeBuilder.cs | 72 + .../Utility/TreeBuilder.cs.meta | 11 + .../Editor/Diagnostics.meta | 8 + .../Diagnostics/AddressableIconNames.cs | 18 + .../Diagnostics/AddressableIconNames.cs.meta | 11 + .../Editor/Diagnostics/Profiler.meta | 8 + ...ddressablesProfilerDetailsDataInspector.cs | 416 ++ ...sablesProfilerDetailsDataInspector.cs.meta | 3 + .../AddressablesProfilerDetailsTreeView.cs | 197 + ...ddressablesProfilerDetailsTreeView.cs.meta | 3 + .../AddressablesProfilerDetailsView.cs | 711 ++ .../AddressablesProfilerDetailsView.cs.meta | 11 + .../Profiler/AddressablesProfilerModule.cs | 30 + .../AddressablesProfilerModule.cs.meta | 11 + .../AddressablesProfilerViewController.cs | 52 + ...AddressablesProfilerViewController.cs.meta | 11 + .../Profiler/BuildLayoutsManager.cs | 216 + .../Profiler/BuildLayoutsManager.cs.meta | 3 + .../Profiler/ContentDataListView.cs | 101 + .../Profiler/ContentDataListView.cs.meta | 3 + .../Profiler/ContentDataTreeView.cs | 186 + .../Profiler/ContentDataTreeView.cs.meta | 3 + .../Diagnostics/Profiler/ContentSearch.cs | 338 + .../Profiler/ContentSearch.cs.meta | 3 + .../Profiler/EditorFrameDataStore.cs | 26 + .../Profiler/EditorFrameDataStore.cs.meta | 3 + .../Diagnostics/Profiler/FrameDataViewRef.cs | 24 + .../Profiler/FrameDataViewRef.cs.meta | 3 + .../Diagnostics/Profiler/GUIElements.meta | 8 + .../Profiler/GUIElements/AssetLabel.cs | 134 + .../Profiler/GUIElements/AssetLabel.cs.meta | 11 + .../Profiler/HelpDisplayManager.cs | 141 + .../Profiler/HelpDisplayManager.cs.meta | 3 + .../Diagnostics/Profiler/IFrameDataStore.cs | 13 + .../Profiler/IFrameDataStore.cs.meta | 3 + .../ProfilerDetailsTreeViewItemData.cs | 388 + .../ProfilerDetailsTreeViewItemData.cs.meta | 11 + .../Profiler/ProfilerGUIUtilities.cs | 299 + .../Profiler/ProfilerGUIUtilities.cs.meta | 3 + .../Diagnostics/Profiler/ProfilerStrings.cs | 23 + .../Profiler/ProfilerStrings.cs.meta | 3 + .../Diagnostics/Profiler/ProfilerTemplates.cs | 42 + .../Profiler/ProfilerTemplates.cs.meta | 11 + .../Editor/Diagnostics/Profiler/UXML.meta | 8 + .../Diagnostics/Profiler/UXML/HelpDisplay.cs | 36 + .../Profiler/UXML/HelpDisplay.cs.meta | 11 + .../Profiler/UXML/HelpDisplay.uxml | 15 + .../Profiler/UXML/HelpDisplay.uxml.meta | 10 + .../Profiler/UXML/InspectorPane.cs | 33 + .../Profiler/UXML/InspectorPane.cs.meta | 11 + .../Profiler/UXML/InspectorPane.uxml | 60 + .../Profiler/UXML/InspectorPane.uxml.meta | 10 + .../Profiler/UXML/MissingReport.cs | 32 + .../Profiler/UXML/MissingReport.cs.meta | 11 + .../Profiler/UXML/MissingReport.uxml | 14 + .../Profiler/UXML/MissingReport.uxml.meta | 10 + .../Profiler/UXML/TreeColumnNames.cs | 14 + .../Profiler/UXML/TreeColumnNames.cs.meta | 3 + .../Diagnostics/Profiler/UXML/TreeViewPane.cs | 20 + .../Profiler/UXML/TreeViewPane.cs.meta | 11 + .../Profiler/UXML/TreeViewPane.uxml | 30 + .../Profiler/UXML/TreeViewPane.uxml.meta | 10 + .../Profiler/UXML/Unsupported.uxml | 10 + .../Profiler/UXML/Unsupported.uxml.meta | 10 + .../Diagnostics/Profiler/UXML/stylesheet.uss | 68 + .../Profiler/UXML/stylesheet.uss.meta | 11 + .../com.unity.addressables/Editor/GUI.meta | 8 + .../GUI/AddressableAssetEntryTreeViewState.cs | 21 + ...AddressableAssetEntryTreeViewState.cs.meta | 3 + .../GUI/AddressableAssetGroupInspector.cs | 317 + .../AddressableAssetGroupInspector.cs.meta | 11 + .../AddressableAssetGroupTemplateInspector.cs | 467 ++ ...essableAssetGroupTemplateInspector.cs.meta | 11 + .../AddressableAssetSettingsGroupHeader.cs | 119 + ...ddressableAssetSettingsGroupHeader.cs.meta | 3 + .../GUI/AddressableAssetSettingsInspector.cs | 1040 +++ .../AddressableAssetSettingsInspector.cs.meta | 11 + .../AddressableAssetsSettingsGroupEditor.cs | 937 +++ ...dressableAssetsSettingsGroupEditor.cs.meta | 11 + ...sableAssetsSettingsGroupEditorBuildMenu.cs | 229 + ...AssetsSettingsGroupEditorBuildMenu.cs.meta | 11 + .../AddressableAssetsSettingsGroupTreeView.cs | 2058 ++++++ ...essableAssetsSettingsGroupTreeView.cs.meta | 11 + ...AddressableAssetsSettingsLabelMaskPopup.cs | 330 + ...ssableAssetsSettingsLabelMaskPopup.cs.meta | 11 + .../Editor/GUI/AddressableAssetsWindow.cs | 180 + .../GUI/AddressableAssetsWindow.cs.meta | 11 + .../GUI/AddressableReadOnlyAttribute.cs | 22 + .../GUI/AddressableReadOnlyAttribute.cs.meta | 11 + .../Editor/GUI/AddressablesGUIUtility.cs | 211 + .../Editor/GUI/AddressablesGUIUtility.cs.meta | 11 + .../Editor/GUI/AnalyzeRuleGUI.cs | 124 + .../Editor/GUI/AnalyzeRuleGUI.cs.meta | 11 + .../Editor/GUI/AnalyzeWindow.cs | 81 + .../Editor/GUI/AnalyzeWindow.cs.meta | 11 + .../Editor/GUI/AssetInspectorGUI.cs | 585 ++ .../Editor/GUI/AssetInspectorGUI.cs.meta | 11 + .../GUI/AssetInspectorGUIGroupsPopup.cs | 343 + .../GUI/AssetInspectorGUIGroupsPopup.cs.meta | 11 + .../Editor/GUI/AssetLabelReferenceDrawer.cs | 36 + .../GUI/AssetLabelReferenceDrawer.cs.meta | 11 + .../Editor/GUI/AssetPublishEditor.cs | 94 + .../Editor/GUI/AssetPublishEditor.cs.meta | 11 + .../Editor/GUI/AssetReferenceDrawer.cs | 1217 ++++ .../Editor/GUI/AssetReferenceDrawer.cs.meta | 11 + .../GUI/AssetSettingsAnalyzeTreeView.cs | 533 ++ .../GUI/AssetSettingsAnalyzeTreeView.cs.meta | 11 + .../Editor/GUI/BuildProfileSettingsEditor.cs | 150 + .../GUI/BuildProfileSettingsEditor.cs.meta | 11 + .../GUI/CacheInitializationDataDrawer.cs | 102 + .../GUI/CacheInitializationDataDrawer.cs.meta | 11 + .../Editor/GUI/ContentUpdatePreviewWindow.cs | 343 + .../GUI/ContentUpdatePreviewWindow.cs.meta | 11 + .../Editor/GUI/GUIElements.meta | 8 + .../GUI/GUIElements/DocumentationButton.cs | 106 + .../GUIElements/DocumentationButton.cs.meta | 11 + .../Editor/GUI/GUIElements/GUIUtility.cs | 54 + .../Editor/GUI/GUIElements/GUIUtility.cs.meta | 3 + .../Editor/GUI/GUIElements/LabeledLabel.cs | 82 + .../GUI/GUIElements/LabeledLabel.cs.meta | 11 + .../Editor/GUI/GUIElements/Ribbon.cs | 249 + .../Editor/GUI/GUIElements/Ribbon.cs.meta | 11 + .../Editor/GUI/GUIElements/RibbonButton.cs | 100 + .../GUI/GUIElements/RibbonButton.cs.meta | 11 + .../GUI/GUIElements/SearchStringFilters.cs | 243 + .../GUIElements/SearchStringFilters.cs.meta | 11 + .../Editor/GUI/GUIElements/StyleSheets.meta | 8 + .../GUI/GUIElements/StyleSheets/Ribbon.uss | 64 + .../GUIElements/StyleSheets/Ribbon.uss.meta | 11 + .../GUIElements/StyleSheets/Ribbon_dark.uss | 72 + .../StyleSheets/Ribbon_dark.uss.meta | 11 + .../GUIElements/StyleSheets/Ribbon_light.uss | 53 + .../StyleSheets/Ribbon_light.uss.meta | 11 + .../Editor/GUI/GUIElements/UXML.meta | 8 + .../Editor/GUI/GUIElements/UXML/Ribbon.uxml | 9 + .../GUI/GUIElements/UXML/Ribbon.uxml.meta | 10 + .../GUI/GUIElements/VisualElementsWrapper.cs | 29 + .../GUIElements/VisualElementsWrapper.cs.meta | 11 + .../Editor/GUI/LabelWindow.cs | 272 + .../Editor/GUI/LabelWindow.cs.meta | 11 + .../GUI/ProfileDataSourceDropdownWindow.cs | 692 ++ .../ProfileDataSourceDropdownWindow.cs.meta | 11 + .../Editor/GUI/ProfileTreeView.cs | 292 + .../Editor/GUI/ProfileTreeView.cs.meta | 3 + .../Editor/GUI/ProfileValueReferenceDrawer.cs | 81 + .../GUI/ProfileValueReferenceDrawer.cs.meta | 11 + .../Editor/GUI/ProfileWindow.cs | 820 +++ .../Editor/GUI/ProfileWindow.cs.meta | 11 + .../Editor/GUI/SerializedTypeDrawer.cs | 95 + .../Editor/GUI/SerializedTypeDrawer.cs.meta | 11 + .../Editor/GUI/UpgradeNotifications.cs | 83 + .../Editor/GUI/UpgradeNotifications.cs.meta | 3 + .../com.unity.addressables/Editor/Icons.meta | 8 + .../Icons/AddressableAssetsIconY1756Basic.png | Bin 0 -> 1499 bytes .../AddressableAssetsIconY1756Basic.png.meta | 86 + .../Icons/AddressableAssetsIconY1756Scene.png | Bin 0 -> 1617 bytes .../AddressableAssetsIconY1756Scene.png.meta | 86 + .../Editor/Icons/white_help@2x.png | Bin 0 -> 841 bytes .../Editor/Icons/white_help@2x.png.meta | 124 + .../Editor/Settings.meta | 8 + .../Settings/AddressableAssetBuildSettings.cs | 84 + .../AddressableAssetBuildSettings.cs.meta | 11 + .../Editor/Settings/AddressableAssetEntry.cs | 802 +++ .../Settings/AddressableAssetEntry.cs.meta | 11 + .../Editor/Settings/AddressableAssetGroup.cs | 754 ++ .../Settings/AddressableAssetGroup.cs.meta | 11 + .../Settings/AddressableAssetGroupSchema.cs | 188 + .../AddressableAssetGroupSchema.cs.meta | 11 + .../AddressableAssetGroupSchemaSet.cs | 256 + .../AddressableAssetGroupSchemaSet.cs.meta | 11 + .../AddressableAssetGroupSchemaTemplate.cs | 72 + ...ddressableAssetGroupSchemaTemplate.cs.meta | 11 + .../Settings/AddressableAssetGroupTemplate.cs | 291 + .../AddressableAssetGroupTemplate.cs.meta | 11 + .../AddressableAssetGroupTemplateInterface.cs | 18 + ...essableAssetGroupTemplateInterface.cs.meta | 11 + .../Settings/AddressableAssetPostProcessor.cs | 22 + .../AddressableAssetPostProcessor.cs.meta | 11 + .../AddressableAssetProfileSettings.cs | 966 +++ .../AddressableAssetProfileSettings.cs.meta | 11 + .../Settings/AddressableAssetSettings.cs | 3327 +++++++++ .../Settings/AddressableAssetSettings.cs.meta | 11 + .../Settings/AddressableAssetUtility.cs | 758 ++ .../Settings/AddressableAssetUtility.cs.meta | 11 + .../Settings/AddressableScenesManager.cs | 93 + .../Settings/AddressableScenesManager.cs.meta | 11 + .../Settings/AddressablesFileEnumeration.cs | 248 + .../AddressablesFileEnumeration.cs.meta | 11 + .../Settings/AssetReferenceDrawerUtilities.cs | 574 ++ .../AssetReferenceDrawerUtilities.cs.meta | 3 + .../BinaryCatalogInitializationSettings.cs | 44 + ...inaryCatalogInitializationSettings.cs.meta | 2 + .../Editor/Settings/BuiltinSceneCache.cs | 132 + .../Editor/Settings/BuiltinSceneCache.cs.meta | 11 + .../Settings/CacheInitializationSettings.cs | 48 + .../CacheInitializationSettings.cs.meta | 11 + .../Editor/Settings/CcdFolder.cs | 84 + .../Editor/Settings/CcdFolder.cs.meta | 11 + .../Editor/Settings/GlobalInitialization.cs | 34 + .../Settings/GlobalInitialization.cs.meta | 11 + .../Editor/Settings/GroupSchemas.meta | 8 + .../AddressableAssetGroupSortSettings.cs | 100 + .../AddressableAssetGroupSortSettings.cs.meta | 2 + .../GroupSchemas/BundledAssetGroupSchema.cs | 1931 +++++ .../BundledAssetGroupSchema.cs.meta | 11 + .../GroupSchemas/ContentUpdateGroupSchema.cs | 77 + .../ContentUpdateGroupSchema.cs.meta | 11 + .../GroupSchemas/PlayerDataGroupSchema.cs | 110 + .../PlayerDataGroupSchema.cs.meta | 11 + .../Editor/Settings/KeyDataStore.cs | 238 + .../Editor/Settings/KeyDataStore.cs.meta | 11 + .../Editor/Settings/LabelTable.cs | 296 + .../Editor/Settings/LabelTable.cs.meta | 11 + .../Editor/Settings/OrgData.cs | 38 + .../Editor/Settings/OrgData.cs.meta | 11 + .../Editor/Settings/Preferences.cs | 126 + .../Editor/Settings/Preferences.cs.meta | 11 + .../Settings/ProfileDataSourceSettings.cs | 543 ++ .../ProfileDataSourceSettings.cs.meta | 11 + .../Editor/Settings/ProfileGroupType.cs | 220 + .../Editor/Settings/ProfileGroupType.cs.meta | 11 + .../Editor/Settings/ProfileValueReference.cs | 207 + .../Settings/ProfileValueReference.cs.meta | 11 + .../Editor/Settings/ProjectConfigData.cs | 412 ++ .../Editor/Settings/ProjectConfigData.cs.meta | 11 + .../Editor/Unity.Addressables.Editor.asmdef | 39 + .../Unity.Addressables.Editor.asmdef.meta | 7 + Packages/com.unity.addressables/LICENSE.md | 5 + .../com.unity.addressables/LICENSE.md.meta | 7 + Packages/com.unity.addressables/Runtime.meta | 8 + .../Runtime/Addressables.cs | 2271 ++++++ .../Runtime/Addressables.cs.meta | 11 + .../Runtime/AddressablesImpl.cs | 1481 ++++ .../Runtime/AddressablesImpl.cs.meta | 11 + .../Runtime/AssemblyInfo.cs | 12 + .../Runtime/AssemblyInfo.cs.meta | 11 + .../Runtime/AssetLabelReference.cs | 53 + .../Runtime/AssetLabelReference.cs.meta | 11 + .../Runtime/AssetReference.cs | 939 +++ .../Runtime/AssetReference.cs.meta | 13 + .../Runtime/AssetReferenceUIRestriction.cs | 95 + .../AssetReferenceUIRestriction.cs.meta | 11 + .../Runtime/IKeyEvaluator.cs | 23 + .../Runtime/IKeyEvaluator.cs.meta | 11 + .../Runtime/Initialization.meta | 8 + .../AddressablesRuntimeProperties.cs | 239 + .../AddressablesRuntimeProperties.cs.meta | 11 + .../Initialization/CacheInitialization.cs | 185 + .../CacheInitialization.cs.meta | 11 + .../Initialization/CheckCatalogsOperation.cs | 123 + .../CheckCatalogsOperation.cs.meta | 11 + .../CleanBundleCacheOperation.cs | 210 + .../CleanBundleCacheOperation.cs.meta | 11 + .../InitializationObjectsOperation.cs | 127 + .../InitializationObjectsOperation.cs.meta | 11 + .../Initialization/InitializationOperation.cs | 328 + .../InitializationOperation.cs.meta | 11 + .../Initialization/PackedPlayModeBuildLogs.cs | 51 + .../PackedPlayModeBuildLogs.cs.meta | 11 + .../ResourceManagerRuntimeData.cs | 164 + .../ResourceManagerRuntimeData.cs.meta | 13 + .../Initialization/UpdateCatalogsOperation.cs | 129 + .../UpdateCatalogsOperation.cs.meta | 11 + .../Runtime/ResourceLocators.meta | 8 + .../ResourceLocators/CcdManagedData.cs | 75 + .../ResourceLocators/CcdManagedData.cs.meta | 11 + .../ResourceLocators/ContentCatalogData.cs | 1361 ++++ .../ContentCatalogData.cs.meta | 11 + .../DynamicResourceLocators.cs | 88 + .../DynamicResourceLocators.cs.meta | 11 + .../ResourceLocators/IResourceLocator.cs | 39 + .../ResourceLocators/IResourceLocator.cs.meta | 11 + .../ResourceLocators/ResourceLocationData.cs | 118 + .../ResourceLocationData.cs.meta | 13 + .../ResourceLocators/ResourceLocationMap.cs | 182 + .../ResourceLocationMap.cs.meta | 13 + .../Runtime/ResourceManager.meta | 8 + .../Runtime/ResourceManager/AssemblyInfo.cs | 12 + .../ResourceManager/AssemblyInfo.cs.meta | 11 + .../ResourceManager/AsyncOperations.meta | 8 + .../AsyncOperations/AsyncOperationBase.cs | 591 ++ .../AsyncOperationBase.cs.meta | 13 + .../AsyncOperations/AsyncOperationHandle.cs | 615 ++ .../AsyncOperationHandle.cs.meta | 11 + .../AsyncOperations/AsyncOperationStatus.cs | 28 + .../AsyncOperationStatus.cs.meta | 11 + .../AsyncOperations/ChainOperation.cs | 258 + .../AsyncOperations/ChainOperation.cs.meta | 11 + .../AsyncOperations/DownloadStatus.cs | 33 + .../AsyncOperations/DownloadStatus.cs.meta | 11 + .../GetDownloadSizeOperation.cs | 69 + .../GetDownloadSizeOperation.cs.meta | 2 + .../AsyncOperations/GroupOperation.cs | 234 + .../AsyncOperations/GroupOperation.cs.meta | 11 + .../AsyncOperations/ProviderOperation.cs | 302 + .../AsyncOperations/ProviderOperation.cs.meta | 11 + .../UnityWebRequestOperation.cs | 22 + .../UnityWebRequestOperation.cs.meta | 11 + .../Runtime/ResourceManager/CcdManager.cs | 32 + .../ResourceManager/CcdManager.cs.meta | 11 + .../Runtime/ResourceManager/Diagnostics.meta | 8 + .../Diagnostics/Profiling.meta | 8 + .../Diagnostics/Profiling/EngineEmitter.cs | 39 + .../Profiling/EngineEmitter.cs.meta | 3 + .../Diagnostics/Profiling/FrameDataStructs.cs | 73 + .../Profiling/FrameDataStructs.cs.meta | 3 + .../Diagnostics/Profiling/IProfilerEmitter.cs | 12 + .../Profiling/IProfilerEmitter.cs.meta | 3 + .../Profiling/ProfilerFrameData.cs | 97 + .../Profiling/ProfilerFrameData.cs.meta | 3 + .../Diagnostics/Profiling/ProfilerRuntime.cs | 298 + .../Profiling/ProfilerRuntime.cs.meta | 11 + .../ResourceManager/ResourceLocations.meta | 8 + .../ResourceLocations/ILocationSizeData.cs | 20 + .../ILocationSizeData.cs.meta | 11 + .../ResourceLocations/IResourceLocation.cs | 90 + .../IResourceLocation.cs.meta | 13 + .../ResourceLocations/ResourceLocationBase.cs | 169 + .../ResourceLocationBase.cs.meta | 13 + .../ResourceManager/ResourceManager.cs | 1134 +++ .../ResourceManager/ResourceManager.cs.meta | 13 + .../ResourceManager/ResourceProviders.meta | 8 + .../ResourceProviders/AssetBundleProvider.cs | 1043 +++ .../AssetBundleProvider.cs.meta | 11 + .../AssetDatabaseProvider.cs | 130 + .../AssetDatabaseProvider.cs.meta | 13 + .../ResourceProviders/AtlasSpriteProvider.cs | 38 + .../AtlasSpriteProvider.cs.meta | 11 + .../ResourceProviders/BinaryAssetProvider.cs | 26 + .../BinaryAssetProvider.cs.meta | 11 + .../BinaryCatalogInitializationData.cs | 94 + .../BinaryCatalogInitializationData.cs.meta | 2 + .../ResourceProviders/BinaryDataProvider.cs | 203 + .../BinaryDataProvider.cs.meta | 11 + .../ResourceProviders/BundledAssetProvider.cs | 263 + .../BundledAssetProvider.cs.meta | 12 + .../ResourceProviders/IInstanceProvider.cs | 137 + .../IInstanceProvider.cs.meta | 13 + .../ResourceProviders/IResourceProvider.cs | 195 + .../IResourceProvider.cs.meta | 13 + .../ResourceProviders/ISceneProvider.cs | 147 + .../ResourceProviders/ISceneProvider.cs.meta | 11 + .../ResourceProviders/IUpdateReceiver.cs | 14 + .../ResourceProviders/IUpdateReceiver.cs.meta | 11 + .../ResourceProviders/InstanceProvider.cs | 62 + .../InstanceProvider.cs.meta | 12 + .../ResourceProviders/JSONAssetProvider.cs | 23 + .../JSONAssetProvider.cs.meta | 11 + .../ResourceProviders/ResourceProviderBase.cs | 165 + .../ResourceProviderBase.cs.meta | 13 + .../ResourceProviders/SceneProvider.cs | 329 + .../ResourceProviders/SceneProvider.cs.meta | 11 + .../ResourceProviders/Simulation.meta | 8 + .../Simulation/VirtualAssetBundle.cs | 613 ++ .../Simulation/VirtualAssetBundle.cs.meta | 13 + .../Simulation/VirtualAssetBundleProvider.cs | 199 + .../VirtualAssetBundleProvider.cs.meta | 13 + .../VirtualAssetBundleRuntimeData.cs | 70 + .../VirtualAssetBundleRuntimeData.cs.meta | 13 + .../Simulation/VirtualBundledAssetProvider.cs | 88 + .../VirtualBundledAssetProvider.cs.meta | 13 + .../ResourceProviders/TextDataProvider.cs | 212 + .../TextDataProvider.cs.meta | 11 + .../ResourceProviders/WebRequestQueue.cs | 177 + .../ResourceProviders/WebRequestQueue.cs.meta | 11 + .../Unity.ResourceManager.asmdef | 27 + .../Unity.ResourceManager.asmdef.meta | 7 + .../Runtime/ResourceManager/Util.meta | 8 + .../Util/BinaryStorageBuffer.cs | 1155 +++ .../Util/BinaryStorageBuffer.cs.meta | 11 + .../Util/ComponentSingleton.cs | 126 + .../Util/ComponentSingleton.cs.meta | 11 + .../Util/DelayedActionManager.cs | 201 + .../Util/DelayedActionManager.cs.meta | 11 + .../ResourceManager/Util/DelegateList.cs | 121 + .../ResourceManager/Util/DelegateList.cs.meta | 11 + .../ResourceManager/Util/Exceptions.cs | 201 + .../ResourceManager/Util/Exceptions.cs.meta | 11 + .../ResourceManager/Util/ListWithEvents.cs | 104 + .../Util/ListWithEvents.cs.meta | 11 + .../Util/MonoBehaviourCallbackHooks.cs | 36 + .../Util/MonoBehaviourCallbackHooks.cs.meta | 11 + .../Util/OperationCacheKeys.cs | 167 + .../Util/OperationCacheKeys.cs.meta | 11 + .../ResourceManager/Util/PlatformUtilities.cs | 10 + .../Util/PlatformUtilities.cs.meta | 11 + .../Util/ResourceManagerConfig.cs | 764 ++ .../Util/ResourceManagerConfig.cs.meta | 11 + .../Util/UnityWebRequestUtilities.cs | 221 + .../Util/UnityWebRequestUtilities.cs.meta | 11 + .../Runtime/ResourceProviders.meta | 8 + .../ContentCatalogProvider.cs | 526 ++ .../ContentCatalogProvider.cs.meta | 11 + .../Runtime/Services.meta | 8 + .../Services/PlatformMappingService.cs | 155 + .../Services/PlatformMappingService.cs.meta | 11 + .../Runtime/Unity.Addressables.asmdef | 22 + .../Runtime/Unity.Addressables.asmdef.meta | 7 + .../Runtime/Utility.meta | 8 + .../Utility/AssetReferenceUtilities.cs | 177 + .../Utility/AssetReferenceUtilities.cs.meta | 3 + .../Runtime/Utility/SerializationUtilities.cs | 212 + .../Utility/SerializationUtilities.cs.meta | 11 + Packages/com.unity.addressables/Tests.meta | 8 + .../com.unity.addressables/Tests/Editor.meta | 8 + .../Tests/Editor/AddressableAnalyticsTests.cs | 374 + .../Editor/AddressableAnalyticsTests.cs.meta | 11 + .../Editor/AddressableAssetEntryTests.cs | 894 +++ .../Editor/AddressableAssetEntryTests.cs.meta | 11 + .../AddressableAssetEntryTreeViewTests.cs | 358 + ...AddressableAssetEntryTreeViewTests.cs.meta | 11 + .../AddressableAssetFolderSubfolderTests.cs | 272 + ...dressableAssetFolderSubfolderTests.cs.meta | 11 + .../Editor/AddressableAssetReferenceTests.cs | 307 + .../AddressableAssetReferenceTests.cs.meta | 11 + .../AddressableAssetSettingsLocatorTests.cs | 439 ++ ...dressableAssetSettingsLocatorTests.cs.meta | 11 + .../Editor/AddressableAssetSettingsTests.cs | 1614 +++++ .../AddressableAssetSettingsTests.cs.meta | 11 + .../Tests/Editor/AddressableAssetTestBase.cs | 223 + .../Editor/AddressableAssetTestBase.cs.meta | 11 + .../Editor/AddressableAssetUtilityTests.cs | 506 ++ .../AddressableAssetUtilityTests.cs.meta | 11 + ...essableAssetsBundleBuildParametersTests.cs | 108 + ...leAssetsBundleBuildParametersTests.cs.meta | 11 + .../Editor/AddressableAssetsWindowTests.cs | 260 + .../AddressableAssetsWindowTests.cs.meta | 11 + .../Tests/Editor/AnalyzeRules.meta | 8 + .../AnalyzeRules/AnalyzeRuleBaseTests.cs | 141 + .../AnalyzeRules/AnalyzeRuleBaseTests.cs.meta | 11 + .../CheckBundleDupeDependencyTests.cs | 331 + .../CheckBundleDupeDependencyTests.cs.meta | 11 + .../CheckResourcesDupeDependenciesTests.cs | 113 + ...heckResourcesDupeDependenciesTests.cs.meta | 11 + .../CheckSceneDupeDependenciesTests.cs | 207 + .../CheckSceneDupeDependenciesTests.cs.meta | 11 + .../Tests/Editor/AssetGroupTests.cs | 189 + .../Tests/Editor/AssetGroupTests.cs.meta | 11 + .../Tests/Editor/AssetReferenceDrawerTests.cs | 1606 +++++ .../Editor/AssetReferenceDrawerTests.cs.meta | 11 + .../Tests/Editor/BinaryStorageBufferTests.cs | 609 ++ .../Editor/BinaryStorageBufferTests.cs.meta | 11 + .../Tests/Editor/Build.meta | 8 + .../Build/AddHashToBundleNameTaskTests.cs | 81 + .../AddHashToBundleNameTaskTests.cs.meta | 11 + .../Build/AddressableBuildTaskTestBase.cs | 54 + .../AddressableBuildTaskTestBase.cs.meta | 11 + .../AddressablesPlayerBuildProcessorTests.cs | 144 + ...ressablesPlayerBuildProcessorTests.cs.meta | 11 + .../Build/BuildLayoutGenerationTaskTests.cs | 772 ++ .../BuildLayoutGenerationTaskTests.cs.meta | 11 + .../Tests/Editor/Build/BuildMenuTests.cs | 156 + .../Tests/Editor/Build/BuildMenuTests.cs.meta | 3 + .../Editor/Build/BuildScriptFastTests.cs | 22 + .../Editor/Build/BuildScriptFastTests.cs.meta | 11 + .../BuildScriptPackedIntegrationTests.cs | 127 + .../BuildScriptPackedIntegrationTests.cs.meta | 11 + .../Build/BuildScriptPackedPlayTests.cs | 86 + .../Build/BuildScriptPackedPlayTests.cs.meta | 11 + .../Editor/Build/BuildScriptPackedTests.cs | 898 +++ .../Build/BuildScriptPackedTests.cs.meta | 11 + .../Tests/Editor/Build/BuildScriptTests.cs | 697 ++ .../Editor/Build/BuildScriptTests.cs.meta | 11 + .../Editor/Build/DataBuilderInputTests.cs | 52 + .../Build/DataBuilderInputTests.cs.meta | 11 + .../Build/GenerateLocationListsTaskTests.cs | 315 + .../GenerateLocationListsTaskTests.cs.meta | 11 + .../Editor/Build/VerifyPublicBuildScripts.cs | 104 + .../Build/VerifyPublicBuildScripts.cs.meta | 11 + .../Tests/Editor/BuildReportVisualizer.meta | 8 + .../BuildReportListViewTests.cs | 22 + .../BuildReportListViewTests.cs.meta | 3 + .../Tests/Editor/BuildReportWindowTests.cs | 119 + .../Editor/BuildReportWindowTests.cs.meta | 11 + .../Tests/Editor/BuiltinSceneCacheTests.cs | 107 + .../Editor/BuiltinSceneCacheTests.cs.meta | 11 + .../Tests/Editor/ComponentSingletonTests.cs | 116 + .../Editor/ComponentSingletonTests.cs.meta | 11 + .../Tests/Editor/ContentCatalogTests.cs | 503 ++ .../Tests/Editor/ContentCatalogTests.cs.meta | 11 + .../Tests/Editor/ContentUpdateTests.cs | 1390 ++++ .../Tests/Editor/ContentUpdateTests.cs.meta | 11 + .../Tests/Editor/CustomTestSchema.cs | 11 + .../Tests/Editor/CustomTestSchema.cs.meta | 11 + .../Tests/Editor/CustomTestSchemaSubClass.cs | 10 + .../Editor/CustomTestSchemaSubClass.cs.meta | 11 + .../Tests/Editor/Diagnostics.meta | 8 + .../Editor/Diagnostics/BuildLayoutTests.cs | 648 ++ .../Diagnostics/BuildLayoutTests.cs.meta | 3 + .../Tests/Editor/Diagnostics/Profiler.meta | 8 + .../AddressablesProfilerDetailsViewTests.cs | 254 + ...dressablesProfilerDetailsViewTests.cs.meta | 3 + .../Profiler/BuildLayoutBuilder.cs | 114 + .../Profiler/BuildLayoutBuilder.cs.meta | 3 + .../Profiler/ProfilerEventBuilder.cs | 244 + .../Profiler/ProfilerEventBuilder.cs.meta | 3 + .../Diagnostics/Profiler/TestProfiler.cs | 124 + .../Diagnostics/Profiler/TestProfiler.cs.meta | 3 + .../Tests/Editor/Diagnostics/ProfilerTests.cs | 24 + .../Editor/Diagnostics/ProfilerTests.cs.meta | 11 + .../Tests/Editor/DocExampleCode.meta | 8 + .../DocExampleCode/AddExceptionHandler.cs | 29 + .../AddExceptionHandler.cs.meta | 11 + .../DocExampleCode/AsynchronousLoading.cs | 48 + .../AsynchronousLoading.cs.meta | 11 + .../Tests/Editor/DocExampleCode/BatchBuild.cs | 65 + .../Editor/DocExampleCode/BatchBuild.cs.meta | 11 + .../Editor/DocExampleCode/BuildLauncher.cs | 128 + .../DocExampleCode/BuildLauncher.cs.meta | 11 + .../DocExampleCode/CustomBuildScript.cs | 31 + .../DocExampleCode/CustomBuildScript.cs.meta | 11 + .../DocExampleCode/CustomDataBuilder.cs | 32 + .../DocExampleCode/CustomDataBuilder.cs.meta | 11 + .../DocExampleCode/DeclaringReferences.cs | 85 + .../DeclaringReferences.cs.meta | 11 + .../DocExampleCode/DisableBuildWarnings.cs | 18 + .../DisableBuildWarnings.cs.meta | 11 + .../Editor/DocExampleCode/DownloadError.cs | 47 + .../DocExampleCode/DownloadError.cs.meta | 11 + .../Editor/DocExampleCode/IDTransformer.cs | 38 + .../DocExampleCode/IDTransformer.cs.meta | 11 + .../Editor/DocExampleCode/InstantiateAsset.cs | 37 + .../DocExampleCode/InstantiateAsset.cs.meta | 11 + .../DocExampleCode/InstantiateReference.cs | 27 + .../InstantiateReference.cs.meta | 11 + .../Editor/DocExampleCode/LoadLocation.cs | 100 + .../DocExampleCode/LoadLocation.cs.meta | 11 + .../Editor/DocExampleCode/LoadMultiple.cs | 55 + .../DocExampleCode/LoadMultiple.cs.meta | 11 + .../Editor/DocExampleCode/LoadReference.cs | 42 + .../DocExampleCode/LoadReference.cs.meta | 11 + .../Tests/Editor/DocExampleCode/LoadScene.cs | 28 + .../Editor/DocExampleCode/LoadScene.cs.meta | 11 + .../Tests/Editor/DocExampleCode/LoadSingle.cs | 34 + .../Editor/DocExampleCode/LoadSingle.cs.meta | 11 + .../DocExampleCode/LoadSynchronously.cs | 36 + .../DocExampleCode/LoadSynchronously.cs.meta | 11 + .../Editor/DocExampleCode/LoadWithAddress.cs | 45 + .../DocExampleCode/LoadWithAddress.cs.meta | 11 + .../Editor/DocExampleCode/LoadWithEvent.cs | 41 + .../DocExampleCode/LoadWithEvent.cs.meta | 11 + .../DocExampleCode/LoadWithIEnumerator.cs | 41 + .../LoadWithIEnumerator.cs.meta | 11 + .../Editor/DocExampleCode/LoadWithLabels.cs | 58 + .../DocExampleCode/LoadWithLabels.cs.meta | 11 + .../DocExampleCode/LoadWithReference.cs | 42 + .../DocExampleCode/LoadWithReference.cs.meta | 11 + .../Editor/DocExampleCode/LoadWithTask.cs | 87 + .../DocExampleCode/LoadWithTask.cs.meta | 11 + .../DocExampleCode/MiscellaneousTopics.cs | 183 + .../MiscellaneousTopics.cs.meta | 11 + .../Tests/Editor/DocExampleCode/MyRule.cs | 42 + .../Editor/DocExampleCode/MyRule.cs.meta | 11 + .../DocExampleCode/OperationHandleTypes.cs | 32 + .../OperationHandleTypes.cs.meta | 11 + .../Tests/Editor/DocExampleCode/Preload.cs | 18 + .../Editor/DocExampleCode/Preload.cs.meta | 11 + .../DocExampleCode/PreloadWithProgress.cs | 56 + .../PreloadWithProgress.cs.meta | 11 + .../DocExampleCode/PrintBucketInformation.cs | 27 + .../PrintBucketInformation.cs.meta | 11 + .../Tests/Editor/DocExampleCode/Readme.txt | 17 + .../Editor/DocExampleCode/Readme.txt.meta | 7 + .../DocExampleCode/ScriptReference.meta | 8 + .../ScriptReference/ContentBuiltCheck.cs | 42 + .../ScriptReference/ContentBuiltCheck.cs.meta | 11 + .../UsingAddResourceLocator.cs | 54 + .../UsingAddResourceLocator.cs.meta | 11 + .../UsingAssetRefSpriteValidateAsset.cs | 18 + .../UsingAssetRefSpriteValidateAsset.cs.meta | 11 + .../ScriptReference/UsingBuildPath.cs | 24 + .../ScriptReference/UsingBuildPath.cs.meta | 11 + .../UsingCheckForCatalogUpdates.cs | 33 + .../UsingCheckForCatalogUpdates.cs.meta | 11 + .../ScriptReference/UsingCleanBundleCache.cs | 60 + .../UsingCleanBundleCache.cs.meta | 11 + .../UsingClearDependencyCacheAsync.cs | 15 + .../UsingClearDependencyCacheAsync.cs.meta | 11 + .../UsingClearResourceLocators.cs | 15 + .../UsingClearResourceLocators.cs.meta | 11 + ...eateCatalogLocationWithHashDependencies.cs | 15 + ...atalogLocationWithHashDependencies.cs.meta | 11 + .../ScriptReference/UsingCreateGroup.cs | 18 + .../ScriptReference/UsingCreateGroup.cs.meta | 11 + ...ngDefaultSchemaSettingsBuildTargetGroup.cs | 21 + ...aultSchemaSettingsBuildTargetGroup.cs.meta | 11 + .../UsingDownloadDependencies.cs | 15 + .../UsingDownloadDependencies.cs.meta | 11 + .../UsingDownloadDependenciesAsync.cs | 15 + .../UsingDownloadDependenciesAsync.cs.meta | 11 + .../ScriptReference/UsingGetDownloadSize.cs | 16 + .../UsingGetDownloadSize.cs.meta | 11 + .../UsingGetDownloadSizeAsync.cs | 15 + .../UsingGetDownloadSizeAsync.cs.meta | 11 + .../ScriptReference/UsingGetLocatorInfo.cs | 77 + .../UsingGetLocatorInfo.cs.meta | 11 + .../UsingInitializationOperation.cs | 14 + .../UsingInitializationOperation.cs.meta | 11 + .../ScriptReference/UsingInitialize.cs | 17 + .../ScriptReference/UsingInitialize.cs.meta | 11 + .../ScriptReference/UsingInitializeAsync.cs | 86 + .../UsingInitializeAsync.cs.meta | 11 + .../ScriptReference/UsingInstanceProvider.cs | 66 + .../UsingInstanceProvider.cs.meta | 11 + .../ScriptReference/UsingInstantiate.cs | 15 + .../ScriptReference/UsingInstantiate.cs.meta | 11 + .../ScriptReference/UsingInstantiateAsync.cs | 170 + .../UsingInstantiateAsync.cs.meta | 11 + .../UsingInternalIdTransformFunc.cs | 61 + .../UsingInternalIdTransformFunc.cs.meta | 11 + .../ScriptReference/UsingLoadAsset.cs | 15 + .../ScriptReference/UsingLoadAsset.cs.meta | 11 + .../ScriptReference/UsingLoadAssetAsync.cs | 119 + .../UsingLoadAssetAsync.cs.meta | 11 + .../ScriptReference/UsingLoadAssets.cs | 15 + .../ScriptReference/UsingLoadAssets.cs.meta | 11 + .../ScriptReference/UsingLoadAssetsAsync.cs | 15 + .../UsingLoadAssetsAsync.cs.meta | 11 + .../UsingLoadContentCatalog.cs | 15 + .../UsingLoadContentCatalog.cs.meta | 11 + .../UsingLoadContentCatalogAsync.cs | 15 + .../UsingLoadContentCatalogAsync.cs.meta | 11 + .../UsingLoadResourceLocations.cs | 15 + .../UsingLoadResourceLocations.cs.meta | 11 + .../UsingLoadResourceLocationsAsync.cs | 15 + .../UsingLoadResourceLocationsAsync.cs.meta | 11 + .../ScriptReference/UsingLoadScene.cs | 15 + .../ScriptReference/UsingLoadScene.cs.meta | 11 + .../ScriptReference/UsingLoadSceneAsync.cs | 15 + .../UsingLoadSceneAsync.cs.meta | 11 + .../ScriptReference/UsingLog.cs | 20 + .../ScriptReference/UsingLog.cs.meta | 11 + .../ScriptReference/UsingLogError.cs | 17 + .../ScriptReference/UsingLogError.cs.meta | 11 + .../ScriptReference/UsingLogErrorFormat.cs | 18 + .../UsingLogErrorFormat.cs.meta | 11 + .../ScriptReference/UsingLogException.cs | 48 + .../ScriptReference/UsingLogException.cs.meta | 11 + .../ScriptReference/UsingLogFormat.cs | 19 + .../ScriptReference/UsingLogFormat.cs.meta | 11 + .../ScriptReference/UsingLogWarning.cs | 16 + .../ScriptReference/UsingLogWarning.cs.meta | 11 + .../ScriptReference/UsingLogWarningFormat.cs | 18 + .../UsingLogWarningFormat.cs.meta | 11 + .../UsingPlayerBuildDataPath.cs | 58 + .../UsingPlayerBuildDataPath.cs.meta | 11 + .../ScriptReference/UsingProfileSetValue.cs | 22 + .../UsingProfileSetValue.cs.meta | 11 + .../ScriptReference/UsingRelease.cs | 15 + .../ScriptReference/UsingRelease.cs.meta | 11 + .../ScriptReference/UsingReleaseInstance.cs | 15 + .../UsingReleaseInstance.cs.meta | 11 + .../UsingRemoveResourceLocator.cs | 15 + .../UsingRemoveResourceLocator.cs.meta | 11 + .../ScriptReference/UsingResolveInternalId.cs | 15 + .../UsingResolveInternalId.cs.meta | 11 + .../ScriptReference/UsingResourceLocators.cs | 15 + .../UsingResourceLocators.cs.meta | 11 + .../ScriptReference/UsingResourceManager.cs | 15 + .../UsingResourceManager.cs.meta | 11 + .../ScriptReference/UsingRuntimePath.cs | 15 + .../ScriptReference/UsingRuntimePath.cs.meta | 11 + .../UsingStreamingAssetsSubFolder.cs | 21 + .../UsingStreamingAssetsSubFolder.cs.meta | 11 + .../ScriptReference/UsingUnloadSceneAsync.cs | 79 + .../UsingUnloadSceneAsync.cs.meta | 11 + .../UsingWebRequestOverride.cs | 32 + .../UsingWebRequestOverride.cs.meta | 11 + .../Tests/Editor/DocExampleCode/TestStub.cs | 15 + .../Editor/DocExampleCode/TestStub.cs.meta | 11 + ...ssables.DocExampleCode.Editor.Tests.asmdef | 56 + ...es.DocExampleCode.Editor.Tests.asmdef.meta | 7 + .../DocExampleCode/WebRequestOverride.cs | 35 + .../DocExampleCode/WebRequestOverride.cs.meta | 11 + .../Tests/Editor/DomainReloadTests.cs | 61 + .../Tests/Editor/DomainReloadTests.cs.meta | 11 + .../EditorAddressablesAssetsTestFixture.cs | 108 + ...ditorAddressablesAssetsTestFixture.cs.meta | 11 + .../EditorPlatformMappingServiceTests.cs | 21 + .../EditorPlatformMappingServiceTests.cs.meta | 11 + .../Tests/Editor/Expected.meta | 8 + .../Expected/~GroupEditorTests_Group.unity | 47 + .../~GroupEditorTests_Group.unity.meta | 2 +- ...nTests_AddressableAssetSettings.ccd2.unity | 138 + ...s_AddressableAssetSettings.ccd2.unity.meta | 7 + ...nTests_AddressableAssetSettings.ccd3.unity | 140 + ...s_AddressableAssetSettings.ccd3.unity.meta | 7 + ...zationTests_AddressableAssetSettings.unity | 131 + ...nTests_AddressableAssetSettings.unity.meta | 7 + ...sts_AddressableAssetSettings_62.ccd2.unity | 138 + ...ddressableAssetSettings_62.ccd2.unity.meta | 7 + ...sts_AddressableAssetSettings_62.ccd3.unity | 140 + ...ddressableAssetSettings_62.ccd3.unity.meta | 7 + ...ionTests_AddressableAssetSettings_62.unity | 131 + ...sts_AddressableAssetSettings_62.unity.meta | 7 + .../Expected/~SerializationTests_Group.unity | 47 + .../~SerializationTests_Group.unity.meta | 7 + .../~SerializationTests_GroupTemplate.unity | 81 + ...erializationTests_GroupTemplate.unity.meta | 7 + ...~SerializationTests_GroupTemplate_62.unity | 81 + ...alizationTests_GroupTemplate_62.unity.meta | 7 + .../~SerializationTests_Group_62.unity | 47 + .../~SerializationTests_Group_62.unity.meta | 7 + ...ationTests_ProfileDataSourceSettings.unity | 51 + ...Tests_ProfileDataSourceSettings.unity.meta | 7 + ...onTests_ProfileDataSourceSettings_62.unity | 51 + ...ts_ProfileDataSourceSettings_62.unity.meta | 7 + .../Tests/Editor/Fixtures.meta | 8 + .../Tests/Editor/Fixtures/InitFixture.cs | 20 + .../Tests/Editor/Fixtures/InitFixture.cs.meta | 2 + .../Tests/Editor/Fixtures/InitFixture1.asset | 14 + .../Editor/Fixtures/InitFixture1.asset.meta | 8 + .../Tests/Editor/Fixtures/InitFixture2.asset | 19 + .../Editor/Fixtures/InitFixture2.asset.meta | 8 + .../Tests/Editor/Fixtures/buildlayout1.json | 2 + .../Editor/Fixtures/buildlayout1.json.meta | 7 + .../Tests/Editor/GUI.meta | 8 + ...ddressableAssetSettingsGroupEditorTests.cs | 632 ++ ...sableAssetSettingsGroupEditorTests.cs.meta | 3 + .../Tests/Editor/GUI/FastIconLoading.cs | 147 + .../Tests/Editor/GUI/FastIconLoading.cs.meta | 3 + .../Tests/Editor/GUI/SomeScriptableObject.cs | 9 + .../Editor/GUI/SomeScriptableObject.cs.meta | 3 + .../Editor/GUI/UpgradeNotificationsTests.cs | 126 + .../GUI/UpgradeNotificationsTests.cs.meta | 3 + .../Tests/Editor/GroupSchemaTests.cs | 617 ++ .../Tests/Editor/GroupSchemaTests.cs.meta | 11 + .../Tests/Editor/KeyDataStoreTests.cs | 80 + .../Tests/Editor/KeyDataStoreTests.cs.meta | 11 + .../Tests/Editor/NamespaceTests.cs | 64 + .../Tests/Editor/NamespaceTests.cs.meta | 3 + .../Tests/Editor/OptionalPackages.meta | 8 + .../Tests/Editor/OptionalPackages/Ccd.meta | 8 + .../OptionalPackages/Ccd/CcdBuildMenuTests.cs | 976 +++ .../Ccd/CcdBuildMenuTests.cs.meta | 3 + .../Ccd/CcdManagementServiceSdkMock.cs | 60 + .../Ccd/CcdManagementServiceSdkMock.cs.meta | 11 + .../OptionalPackages/Ccd/CcdNotFoundTests.cs | 29 + .../Ccd/CcdNotFoundTests.cs.meta | 3 + .../OptionalPackages/PlaceholderTests.cs | 22 + .../OptionalPackages/PlaceholderTests.cs.meta | 3 + .../Tests/Editor/OrgDataTests.cs | 37 + .../Tests/Editor/OrgDataTests.cs.meta | 11 + .../Editor/ProfileDataSourceSettingsTests.cs | 97 + .../ProfileDataSourceSettingsTests.cs.meta | 11 + .../Tests/Editor/ProfileGroupTypeTests.cs | 156 + .../Editor/ProfileGroupTypeTests.cs.meta | 11 + .../Tests/Editor/ProfileSettingsTests.cs | 476 ++ .../Tests/Editor/ProfileSettingsTests.cs.meta | 11 + .../Editor/ProfileValueReferenceTests.cs | 164 + .../Editor/ProfileValueReferenceTests.cs.meta | 11 + .../Tests/Editor/ResourceCleanupTests.cs | 39 + .../Tests/Editor/ResourceCleanupTests.cs.meta | 11 + .../Tests/Editor/SearchFiltersTests.cs | 100 + .../Tests/Editor/SearchFiltersTests.cs.meta | 11 + .../Tests/Editor/SerializationTests.cs | 431 ++ .../Tests/Editor/SerializationTests.cs.meta | 11 + .../Tests/Editor/TestObject.cs | 28 + .../Tests/Editor/TestObject.cs.meta | 11 + .../Tests/Editor/TestSubObject.cs | 8 + .../Tests/Editor/TestSubObject.cs.meta | 11 + .../Unity.Addressables.Editor.Tests.asmdef | 60 + ...nity.Addressables.Editor.Tests.asmdef.meta | 7 + .../Tests/Editor/Utility.meta | 8 + .../Utility/AssetReferenceUtilitiesTests.cs | 142 + .../AssetReferenceUtilitiesTests.cs.meta | 3 + .../com.unity.addressables/Tests/Runtime.meta | 8 + ...sableAssetSettingsResourceLocationTests.cs | 162 + ...AssetSettingsResourceLocationTests.cs.meta | 11 + .../Tests/Runtime/AddressablesImplTests.cs | 591 ++ .../Runtime/AddressablesImplTests.cs.meta | 3 + .../Runtime/AddressablesIntegrationTests.cs | 394 ++ .../AddressablesIntegrationTests.cs.meta | 11 + .../AddressablesIntegrationTestsImpl.cs | 3703 ++++++++++ .../AddressablesIntegrationTestsImpl.cs.meta | 11 + .../Tests/Runtime/AddressablesTestFixture.cs | 299 + .../Runtime/AddressablesTestFixture.cs.meta | 11 + .../Runtime/AddressablesTestUtilities.cs | 295 + .../Runtime/AddressablesTestUtilities.cs.meta | 11 + .../Tests/Runtime/AssemblyInfo.cs | 6 + .../Tests/Runtime/AssemblyInfo.cs.meta | 11 + .../Runtime/AssetBundleProviderRetryTests.cs | 100 + .../AssetBundleProviderRetryTests.cs.meta | 11 + .../Tests/Runtime/AssetBundleProviderTests.cs | 350 + .../Runtime/AssetBundleProviderTests.cs.meta | 11 + .../Runtime/AssetReferenceDrawerTests.cs | 177 + .../Runtime/AssetReferenceDrawerTests.cs.meta | 11 + .../Runtime/AssetReferenceTestBehavior.cs | 18 + .../AssetReferenceTestBehavior.cs.meta | 11 + .../Tests/Runtime/AsyncTaskTests.cs | 177 + .../Tests/Runtime/AsyncTaskTests.cs.meta | 11 + .../Tests/Runtime/CleanBundleCacheTests.cs | 384 + .../Runtime/CleanBundleCacheTests.cs.meta | 11 + .../Runtime/DynamicContentUpdateTests.cs | 559 ++ .../Runtime/DynamicContentUpdateTests.cs.meta | 11 + .../Runtime/DynamicResourceLocationTests.cs | 206 + .../DynamicResourceLocationTests.cs.meta | 11 + .../Tests/Runtime/IgnoreFailingLogMessage.cs | 21 + .../Runtime/IgnoreFailingLogMessage.cs.meta | 11 + .../Tests/Runtime/Initialization.meta | 8 + .../AddrRuntimePropertiesTests.cs | 224 + .../AddrRuntimePropertiesTests.cs.meta | 11 + .../FastModeInitializationTests.cs | 59 + .../FastModeInitializationTests.cs.meta | 11 + .../InitializationObjectsAsyncTests.cs | 324 + .../InitializationObjectsAsyncTests.cs.meta | 11 + .../Runtime/ManualPercentCompleteOperation.cs | 44 + .../ManualPercentCompleteOperation.cs.meta | 11 + .../Tests/Runtime/NamespaceTests.cs | 108 + .../Tests/Runtime/NamespaceTests.cs.meta | 3 + .../Runtime/ObjectReferenceMonoBehaviour.cs | 11 + .../ObjectReferenceMonoBehaviour.cs.meta | 11 + .../Tests/Runtime/OptionalPackages.meta | 8 + .../Tests/Runtime/OptionalPackages/Ccd.meta | 8 + .../OptionalPackages/Ccd/CcdManagerTests.cs | 256 + .../Ccd/CcdManagerTests.cs.meta | 3 + .../Tests/Runtime/ResourceManager.meta | 8 + .../Runtime/ResourceManager/Operations.meta | 8 + .../Operations/AsyncOperationHandleTests.cs | 332 + .../AsyncOperationHandleTests.cs.meta | 11 + .../Operations/BaseOperationBehaviorTests.cs | 436 ++ .../BaseOperationBehaviorTests.cs.meta | 11 + .../Operations/ChainOperationTests.cs | 46 + .../Operations/ChainOperationTests.cs.meta | 11 + .../Operations/ProviderOperationTests.cs | 569 ++ .../Operations/ProviderOperationTests.cs.meta | 11 + .../ResourceManager/OperationsCacheTests.cs | 170 + .../OperationsCacheTests.cs.meta | 3 + .../ResourceManagerBaseTests.cs | 249 + .../ResourceManagerBaseTests.cs.meta | 11 + .../ResourceManagerFastModeTests.cs | 27 + .../ResourceManagerFastModeTests.cs.meta | 11 + .../ResourceManagerPackedModeTests.cs | 9 + .../ResourceManagerPackedModeTests.cs.meta | 11 + .../ResourceManager/ResourceManagerTests.cs | 453 ++ .../ResourceManagerTests.cs.meta | 11 + .../ResourceManagerUtilityTests.cs | 221 + .../ResourceManagerUtilityTests.cs.meta | 11 + .../Runtime/ResourceManager/TestUtil.meta | 8 + .../ResourceManager/TestUtil/MockProvider.cs | 64 + .../TestUtil/MockProvider.cs.meta | 11 + .../Unity.ResourceManager.Tests.asmdef | 25 + .../Unity.ResourceManager.Tests.asmdef.meta | 7 + .../VirtualAssetBundleProviderTests.cs | 140 + .../VirtualAssetBundleProviderTests.cs.meta | 11 + .../Tests/Runtime/ResourceProviders.meta | 8 + .../ContentCatalogProviderTests.cs | 412 ++ .../ContentCatalogProviderTests.cs.meta | 11 + .../ResourceProviders/TextDataProviderStub.cs | 60 + .../TextDataProviderStub.cs.meta | 3 + .../RuntimePlatformMappingServiceTests.cs | 23 + ...RuntimePlatformMappingServiceTests.cs.meta | 11 + .../Tests/Runtime/SceneTests.cs | 840 +++ .../Tests/Runtime/SceneTests.cs.meta | 11 + .../Runtime/StripDownloadOptionsTests.cs | 62 + .../Runtime/StripDownloadOptionsTests.cs.meta | 2 + .../Tests/Runtime/SyncAddressableTests.cs | 693 ++ .../Runtime/SyncAddressableTests.cs.meta | 11 + .../Runtime/TestBehaviourWithReference.cs | 8 + .../TestBehaviourWithReference.cs.meta | 11 + .../Tests/Runtime/TestObject.cs | 35 + .../Tests/Runtime/TestObject.cs.meta | 11 + .../Tests/Runtime/TestObject2.cs | 16 + .../Tests/Runtime/TestObject2.cs.meta | 11 + .../TestObjectWithSerializableField.cs | 23 + .../TestObjectWithSerializableField.cs.meta | 11 + .../Tests/Runtime/TestReflectionHelpers.cs | 18 + .../Runtime/TestReflectionHelpers.cs.meta | 11 + .../Tests/Runtime/TextDataProviderTests.cs | 77 + .../Runtime/TextDataProviderTests.cs.meta | 3 + .../Unity.Addressables.Runtime.Tests.asmdef | 38 + ...ity.Addressables.Runtime.Tests.asmdef.meta | 7 + Packages/com.unity.addressables/package.json | 74 + .../package.json.meta | 4 +- Packages/com.unity.addressables/readme.md | 1 + .../com.unity.addressables/readme.md.meta | 9 + Packages/com.unity.collections/package.json | 3 +- .../StaticTypeRegistry/TypeHash.cs | 9 + .../Unity.Entities/IComponentData.cs | 1 + .../Unity.Entities/Types/Entity.cs | 1 + .../Unity.Entities/Types/TypeHash.cs | 21 +- .../Unity.Entities/Types/TypeManager.cs | 10 + .../Assets/TestMaterial.mat | 12 +- .../Unity.Scenes.Hybrid.Tests/Test.mat | 12 +- Packages/com.unity.entities/package.json | 3 +- Packages/com.unity.netcode/package.json | 3 +- .../PlayModeTests/HullGeneration/Material.mat | 6 +- .../PhysicsDynamicDebugMaterial.mat | 7 +- .../ECS/Base/Systems/PhysicsWorldBuilder.cs | 4 +- Packages/com.unity.physics/package.json | 3 +- Packages/com.unity.transport/package.json | 3 +- .../Shaders/SpriteAssetUI.shader.meta | 2 +- .../Resources/Shaders/SpriteAtlas.shader.meta | 2 +- .../Textures/AnimationEventMarker.png.meta | 2 +- Packages/dev.pugstorm.sprite/package.json | 17 - Packages/manifest.json | 15 +- Packages/packages-lock.json | 156 +- ProjectSettings/GraphicsSettings.asset | 9 +- ProjectSettings/MultiplayerManager.asset | 7 + .../NetCodeClientAndServerSettings.asset | 2 +- ProjectSettings/NetCodeClientSettings.asset | 2 +- ProjectSettings/NetCodeServerSettings.asset | 2 +- ProjectSettings/ProjectSettings.asset | 67 +- ProjectSettings/ProjectVersion.txt | 4 +- ProjectSettings/QualitySettings.asset | 54 +- ProjectSettings/ShaderGraphSettings.asset | 2 + ProjectSettings/URPProjectSettings.asset | 2 +- 1224 files changed, 128514 insertions(+), 711 deletions(-) create mode 100644 .idea/.idea.CoreLib-main/.idea/encodings.xml create mode 100644 .idea/.idea.CoreLib-main/.idea/indexLayout.xml create mode 100644 .idea/.idea.CoreLib-main/.idea/projectSettingsUpdater.xml create mode 100644 .idea/.idea.CoreLib-main/.idea/vcs.xml create mode 100644 .idea/.idea.CoreLib-main/.idea/workspace.xml delete mode 100644 .idea/.name create mode 100644 .idea/indexLayout.xml create mode 100644 .idea/projectSettingsUpdater.xml create mode 100644 Assets/DefaultVolumeProfile.asset create mode 100644 Assets/DefaultVolumeProfile.asset.meta rename {Packages/dev.pugstorm.sprite => Assets/ModSDK}/Resources.meta (77%) rename {Packages/dev.pugstorm.sprite => Assets/ModSDK/Resources}/Shaders.meta (77%) rename {Packages/dev.pugstorm.sprite => Assets/ModSDK}/Resources/Textures.meta (77%) delete mode 100644 Assets/Test.unity create mode 100644 Packages/com.unity.addressables/CHANGELOG.md create mode 100644 Packages/com.unity.addressables/CHANGELOG.md.meta rename Packages/{dev.pugstorm.sprite/Resources/Shaders.meta => com.unity.addressables/Editor.meta} (77%) create mode 100644 Packages/com.unity.addressables/Editor/AddressableAssetSettingsDefaultObject.cs create mode 100644 Packages/com.unity.addressables/Editor/AddressableAssetSettingsDefaultObject.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/AddressableEditorInitialization.cs create mode 100644 Packages/com.unity.addressables/Editor/AddressableEditorInitialization.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/AssemblyInfo.cs create mode 100644 Packages/com.unity.addressables/Editor/AssemblyInfo.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AddressableAnalytics.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AddressableAnalytics.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AddressableAssetSettingsLocator.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AddressableAssetSettingsLocator.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AddressablesBuildScriptHooks.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AddressablesBuildScriptHooks.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilderInput.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilderInput.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilders.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilders.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AddressablesPlayerBuildProcessor.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AddressablesPlayerBuildProcessor.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeResultData.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeResultData.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeRule.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeRule.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeSystem.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeSystem.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BuildBundleLayout.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BuildBundleLayout.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BundleRuleBase.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BundleRuleBase.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/BuildUtility.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/BuildUtility.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/BuiltInBundleNaming.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/BuiltInBundleNaming.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/CcdBuildEvents.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/CcdBuildEvents.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/ContentUpdateScript.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/ContentUpdateScript.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilderInterfaces.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilderInterfaces.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildLayoutParameters.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildLayoutParameters.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptBase.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptBase.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptFastMode.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptFastMode.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedMode.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedMode.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/DirectoryUtility.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/DirectoryUtility.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/FastModeInitializationOperation.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/FastModeInitializationOperation.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/FileRegistry.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/FileRegistry.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/Layout.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/Layout/BuildLayout.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/Layout/BuildLayout.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutEnums.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutEnums.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutHelpers.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutHelpers.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutPrinter.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutPrinter.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutSummary.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutSummary.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/MonoScriptBundleNaming.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/MonoScriptBundleNaming.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/SceneManagerState.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/SceneManagerState.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Build/SharedBundleSettings.cs create mode 100644 Packages/com.unity.addressables/Editor/Build/SharedBundleSettings.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_DarkTheme.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_DarkTheme.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_DarkTheme@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_DarkTheme@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_LightTheme.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_LightTheme.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_LightTheme@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_LightTheme@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_DarkTheme.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_DarkTheme.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_DarkTheme@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_DarkTheme@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_LightTheme.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_LightTheme.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_LightTheme@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_LightTheme@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@3x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@3x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneLinux64Icon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneLinux64Icon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneLinux64Icon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneLinux64Icon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneOSXIcon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneOSXIcon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneOSXIcon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneOSXIcon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_icon dropdown@2x.png create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_icon dropdown@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReportListView.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReportListView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReportWindow.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReportWindow.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/AssetsContentView.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/AssetsContentView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/BundlesContentView.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/BundlesContentView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/ContentView.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/ContentView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/DetailsView.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/DetailsView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/DuplicatedAssetsContentView.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/DuplicatedAssetsContentView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/GroupsContentView.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/GroupsContentView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/LabelsContentView.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ContentView/LabelsContentView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/DetailsPanel.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/DetailsPanel/DetailsContentView.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/DetailsPanel/DetailsContentView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/DetailsPanel/DetailsContents.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/DetailsPanel/DetailsContents.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/DetailsPanel/DetailsSummaryView.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/DetailsPanel/DetailsSummaryView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/DetailsPanel/DetailsUtility.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/DetailsPanel/DetailsUtility.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/IAddressableView.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/IAddressableView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/IBuildReportConsumer.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/IBuildReportConsumer.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/MainPanelSummaryTab.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/MainPanelSummaryTab.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/MainToolbar.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/MainToolbar.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ToggleTextExpansionButton.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/ToggleTextExpansionButton.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/DetailsPanelSummary.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/DetailsPanelSummary.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/DetailsViewDark.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/DetailsViewDark.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/DetailsViewLight.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/DetailsViewLight.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/DrillableListItemStyle.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/DrillableListItemStyle.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/MainToolbarButtons.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/MainToolbarButtons.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/MainToolbarButtonsDark.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/MainToolbarButtonsDark.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/MainToolbarButtonsLight.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/MainToolbarButtonsLight.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/ReportListItem.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/ReportListItem.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/SummaryTab.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/SummaryTab.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/SummaryTabCardDark.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/SummaryTabCardDark.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/SummaryTabCardLight.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/SummaryTabCardLight.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/SummaryTabDark.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/SummaryTabDark.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/SummaryTabLight.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/SummaryTabLight.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/TreeViewItem.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/TreeViewItem.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/TreeViewNavigableItem.uss create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/StyleSheets/TreeViewNavigableItem.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/BuildReportWindow.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/BuildReportWindow.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/ContentTab.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/ContentTab.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/DetailsPanel.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/DetailsPanel.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/DetailsPanelSummaryAsset.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/DetailsPanelSummaryAsset.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/DetailsPanelSummaryBundle.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/DetailsPanelSummaryBundle.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/DetailsPanelSummaryNavigableBundle.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/DetailsPanelSummaryNavigableBundle.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/DetailsPanelSummaryNavigableItem.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/DetailsPanelSummaryNavigableItem.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/DrillableListViewItem.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/DrillableListViewItem.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/MainPanel.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/MainPanel.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/MainToolbar.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/MainToolbar.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/PotentialIssues.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/PotentialIssues.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/ReportsListItem.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/ReportsListItem.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/ReportsListPanel.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/ReportsListPanel.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/SummaryTab.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/SummaryTab.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/TreeViewItem.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/TreeViewItem.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/TreeViewNavigableItem.uxml create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/UIToolKitAssets/UXML/TreeViewNavigableItem.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/BuildReportHelperConsumer.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/BuildReportHelperConsumer.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/BuildReportUtility.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/BuildReportUtility.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/DetailsListItem.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/DetailsListItem.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/DetailsStack.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/DetailsStack.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/DetailsSummaryBuilder.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/DetailsSummaryBuilder.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/SummaryRowBuilder.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/SummaryRowBuilder.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/TreeBuilder.cs create mode 100644 Packages/com.unity.addressables/Editor/BuildReportVisualizer/Utility/TreeBuilder.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/AddressableIconNames.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/AddressableIconNames.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/AddressablesProfilerDetailsDataInspector.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/AddressablesProfilerDetailsDataInspector.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/AddressablesProfilerDetailsTreeView.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/AddressablesProfilerDetailsTreeView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/AddressablesProfilerDetailsView.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/AddressablesProfilerDetailsView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/AddressablesProfilerModule.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/AddressablesProfilerModule.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/AddressablesProfilerViewController.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/AddressablesProfilerViewController.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/BuildLayoutsManager.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/BuildLayoutsManager.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ContentDataListView.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ContentDataListView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ContentDataTreeView.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ContentDataTreeView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ContentSearch.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ContentSearch.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/EditorFrameDataStore.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/EditorFrameDataStore.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/FrameDataViewRef.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/FrameDataViewRef.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/GUIElements.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/GUIElements/AssetLabel.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/GUIElements/AssetLabel.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/HelpDisplayManager.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/HelpDisplayManager.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/IFrameDataStore.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/IFrameDataStore.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ProfilerDetailsTreeViewItemData.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ProfilerDetailsTreeViewItemData.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ProfilerGUIUtilities.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ProfilerGUIUtilities.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ProfilerStrings.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ProfilerStrings.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ProfilerTemplates.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/ProfilerTemplates.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/HelpDisplay.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/HelpDisplay.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/HelpDisplay.uxml create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/HelpDisplay.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/InspectorPane.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/InspectorPane.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/InspectorPane.uxml create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/InspectorPane.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/MissingReport.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/MissingReport.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/MissingReport.uxml create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/MissingReport.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/TreeColumnNames.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/TreeColumnNames.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/TreeViewPane.cs create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/TreeViewPane.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/TreeViewPane.uxml create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/TreeViewPane.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/Unsupported.uxml create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/Unsupported.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/stylesheet.uss create mode 100644 Packages/com.unity.addressables/Editor/Diagnostics/Profiler/UXML/stylesheet.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetEntryTreeViewState.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetEntryTreeViewState.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetGroupInspector.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetGroupInspector.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetGroupTemplateInspector.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetGroupTemplateInspector.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetSettingsGroupHeader.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetSettingsGroupHeader.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetSettingsInspector.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetSettingsInspector.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetsSettingsGroupEditor.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetsSettingsGroupEditor.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetsSettingsGroupEditorBuildMenu.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetsSettingsGroupEditorBuildMenu.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetsSettingsGroupTreeView.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetsSettingsGroupTreeView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetsSettingsLabelMaskPopup.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetsSettingsLabelMaskPopup.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetsWindow.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableAssetsWindow.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableReadOnlyAttribute.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressableReadOnlyAttribute.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressablesGUIUtility.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AddressablesGUIUtility.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AnalyzeRuleGUI.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AnalyzeRuleGUI.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AnalyzeWindow.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AnalyzeWindow.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AssetInspectorGUI.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AssetInspectorGUI.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AssetInspectorGUIGroupsPopup.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AssetInspectorGUIGroupsPopup.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AssetLabelReferenceDrawer.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AssetLabelReferenceDrawer.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AssetPublishEditor.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AssetPublishEditor.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AssetReferenceDrawer.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AssetReferenceDrawer.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/AssetSettingsAnalyzeTreeView.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/AssetSettingsAnalyzeTreeView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/BuildProfileSettingsEditor.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/BuildProfileSettingsEditor.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/CacheInitializationDataDrawer.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/CacheInitializationDataDrawer.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/ContentUpdatePreviewWindow.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/ContentUpdatePreviewWindow.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/DocumentationButton.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/DocumentationButton.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/GUIUtility.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/GUIUtility.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/LabeledLabel.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/LabeledLabel.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/Ribbon.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/Ribbon.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/RibbonButton.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/RibbonButton.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/SearchStringFilters.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/SearchStringFilters.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/StyleSheets.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/StyleSheets/Ribbon.uss create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/StyleSheets/Ribbon.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/StyleSheets/Ribbon_dark.uss create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/StyleSheets/Ribbon_dark.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/StyleSheets/Ribbon_light.uss create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/StyleSheets/Ribbon_light.uss.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/UXML.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/UXML/Ribbon.uxml create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/UXML/Ribbon.uxml.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/VisualElementsWrapper.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/GUIElements/VisualElementsWrapper.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/LabelWindow.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/LabelWindow.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/ProfileDataSourceDropdownWindow.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/ProfileDataSourceDropdownWindow.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/ProfileTreeView.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/ProfileTreeView.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/ProfileValueReferenceDrawer.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/ProfileValueReferenceDrawer.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/ProfileWindow.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/ProfileWindow.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/SerializedTypeDrawer.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/SerializedTypeDrawer.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/GUI/UpgradeNotifications.cs create mode 100644 Packages/com.unity.addressables/Editor/GUI/UpgradeNotifications.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Icons.meta create mode 100644 Packages/com.unity.addressables/Editor/Icons/AddressableAssetsIconY1756Basic.png create mode 100644 Packages/com.unity.addressables/Editor/Icons/AddressableAssetsIconY1756Basic.png.meta create mode 100644 Packages/com.unity.addressables/Editor/Icons/AddressableAssetsIconY1756Scene.png create mode 100644 Packages/com.unity.addressables/Editor/Icons/AddressableAssetsIconY1756Scene.png.meta create mode 100644 Packages/com.unity.addressables/Editor/Icons/white_help@2x.png create mode 100644 Packages/com.unity.addressables/Editor/Icons/white_help@2x.png.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetBuildSettings.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetBuildSettings.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetEntry.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetEntry.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetGroup.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetGroup.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetGroupSchema.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetGroupSchema.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetGroupSchemaSet.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetGroupSchemaSet.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetGroupSchemaTemplate.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetGroupSchemaTemplate.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetGroupTemplate.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetGroupTemplate.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetGroupTemplateInterface.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetGroupTemplateInterface.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetPostProcessor.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetPostProcessor.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetProfileSettings.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetProfileSettings.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetSettings.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetSettings.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetUtility.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableAssetUtility.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableScenesManager.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressableScenesManager.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressablesFileEnumeration.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AddressablesFileEnumeration.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/AssetReferenceDrawerUtilities.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/AssetReferenceDrawerUtilities.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/BinaryCatalogInitializationSettings.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/BinaryCatalogInitializationSettings.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/BuiltinSceneCache.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/BuiltinSceneCache.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/CacheInitializationSettings.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/CacheInitializationSettings.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/CcdFolder.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/CcdFolder.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/GlobalInitialization.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/GlobalInitialization.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/GroupSchemas.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/GroupSchemas/AddressableAssetGroupSortSettings.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/GroupSchemas/AddressableAssetGroupSortSettings.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/GroupSchemas/BundledAssetGroupSchema.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/GroupSchemas/BundledAssetGroupSchema.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/GroupSchemas/ContentUpdateGroupSchema.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/GroupSchemas/ContentUpdateGroupSchema.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/GroupSchemas/PlayerDataGroupSchema.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/GroupSchemas/PlayerDataGroupSchema.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/KeyDataStore.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/KeyDataStore.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/LabelTable.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/LabelTable.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/OrgData.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/OrgData.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/Preferences.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/Preferences.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/ProfileDataSourceSettings.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/ProfileDataSourceSettings.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/ProfileGroupType.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/ProfileGroupType.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/ProfileValueReference.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/ProfileValueReference.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Settings/ProjectConfigData.cs create mode 100644 Packages/com.unity.addressables/Editor/Settings/ProjectConfigData.cs.meta create mode 100644 Packages/com.unity.addressables/Editor/Unity.Addressables.Editor.asmdef create mode 100644 Packages/com.unity.addressables/Editor/Unity.Addressables.Editor.asmdef.meta create mode 100644 Packages/com.unity.addressables/LICENSE.md create mode 100644 Packages/com.unity.addressables/LICENSE.md.meta create mode 100644 Packages/com.unity.addressables/Runtime.meta create mode 100644 Packages/com.unity.addressables/Runtime/Addressables.cs create mode 100644 Packages/com.unity.addressables/Runtime/Addressables.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/AddressablesImpl.cs create mode 100644 Packages/com.unity.addressables/Runtime/AddressablesImpl.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/AssemblyInfo.cs create mode 100644 Packages/com.unity.addressables/Runtime/AssemblyInfo.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/AssetLabelReference.cs create mode 100644 Packages/com.unity.addressables/Runtime/AssetLabelReference.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/AssetReference.cs create mode 100644 Packages/com.unity.addressables/Runtime/AssetReference.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/AssetReferenceUIRestriction.cs create mode 100644 Packages/com.unity.addressables/Runtime/AssetReferenceUIRestriction.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/IKeyEvaluator.cs create mode 100644 Packages/com.unity.addressables/Runtime/IKeyEvaluator.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/Initialization.meta create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/AddressablesRuntimeProperties.cs create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/AddressablesRuntimeProperties.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/CacheInitialization.cs create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/CacheInitialization.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/CheckCatalogsOperation.cs create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/CheckCatalogsOperation.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/CleanBundleCacheOperation.cs create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/CleanBundleCacheOperation.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/InitializationObjectsOperation.cs create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/InitializationObjectsOperation.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/InitializationOperation.cs create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/InitializationOperation.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/PackedPlayModeBuildLogs.cs create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/PackedPlayModeBuildLogs.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/ResourceManagerRuntimeData.cs create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/ResourceManagerRuntimeData.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/UpdateCatalogsOperation.cs create mode 100644 Packages/com.unity.addressables/Runtime/Initialization/UpdateCatalogsOperation.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceLocators.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceLocators/CcdManagedData.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceLocators/CcdManagedData.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceLocators/ContentCatalogData.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceLocators/ContentCatalogData.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceLocators/DynamicResourceLocators.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceLocators/DynamicResourceLocators.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceLocators/IResourceLocator.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceLocators/IResourceLocator.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceLocators/ResourceLocationData.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceLocators/ResourceLocationData.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceLocators/ResourceLocationMap.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceLocators/ResourceLocationMap.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AssemblyInfo.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AssemblyInfo.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/AsyncOperationBase.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/AsyncOperationBase.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/AsyncOperationHandle.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/AsyncOperationHandle.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/AsyncOperationStatus.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/AsyncOperationStatus.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/ChainOperation.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/ChainOperation.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/DownloadStatus.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/DownloadStatus.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/GetDownloadSizeOperation.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/GetDownloadSizeOperation.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/GroupOperation.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/GroupOperation.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/ProviderOperation.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/ProviderOperation.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/UnityWebRequestOperation.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/AsyncOperations/UnityWebRequestOperation.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/CcdManager.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/CcdManager.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Diagnostics.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Diagnostics/Profiling.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Diagnostics/Profiling/EngineEmitter.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Diagnostics/Profiling/EngineEmitter.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Diagnostics/Profiling/FrameDataStructs.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Diagnostics/Profiling/FrameDataStructs.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Diagnostics/Profiling/IProfilerEmitter.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Diagnostics/Profiling/IProfilerEmitter.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Diagnostics/Profiling/ProfilerFrameData.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Diagnostics/Profiling/ProfilerFrameData.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Diagnostics/Profiling/ProfilerRuntime.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Diagnostics/Profiling/ProfilerRuntime.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceLocations.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceLocations/ILocationSizeData.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceLocations/ILocationSizeData.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceLocations/IResourceLocation.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceLocations/IResourceLocation.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceLocations/ResourceLocationBase.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceLocations/ResourceLocationBase.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceManager.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceManager.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/AssetBundleProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/AssetBundleProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/AssetDatabaseProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/AssetDatabaseProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/AtlasSpriteProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/AtlasSpriteProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/BinaryAssetProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/BinaryAssetProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/BinaryCatalogInitializationData.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/BinaryCatalogInitializationData.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/BinaryDataProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/BinaryDataProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/BundledAssetProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/BundledAssetProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/IInstanceProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/IInstanceProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/IResourceProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/IResourceProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/ISceneProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/ISceneProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/IUpdateReceiver.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/IUpdateReceiver.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/InstanceProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/InstanceProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/JSONAssetProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/JSONAssetProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/ResourceProviderBase.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/ResourceProviderBase.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/SceneProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/SceneProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/Simulation.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/Simulation/VirtualAssetBundle.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/Simulation/VirtualAssetBundle.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/Simulation/VirtualAssetBundleProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/Simulation/VirtualAssetBundleProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/Simulation/VirtualAssetBundleRuntimeData.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/Simulation/VirtualAssetBundleRuntimeData.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/Simulation/VirtualBundledAssetProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/Simulation/VirtualBundledAssetProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/TextDataProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/TextDataProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/WebRequestQueue.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/ResourceProviders/WebRequestQueue.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Unity.ResourceManager.asmdef create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Unity.ResourceManager.asmdef.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/BinaryStorageBuffer.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/BinaryStorageBuffer.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/ComponentSingleton.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/ComponentSingleton.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/DelayedActionManager.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/DelayedActionManager.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/DelegateList.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/DelegateList.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/Exceptions.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/Exceptions.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/ListWithEvents.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/ListWithEvents.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/MonoBehaviourCallbackHooks.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/MonoBehaviourCallbackHooks.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/OperationCacheKeys.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/OperationCacheKeys.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/PlatformUtilities.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/PlatformUtilities.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/ResourceManagerConfig.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/ResourceManagerConfig.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/UnityWebRequestUtilities.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceManager/Util/UnityWebRequestUtilities.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceProviders.meta create mode 100644 Packages/com.unity.addressables/Runtime/ResourceProviders/ContentCatalogProvider.cs create mode 100644 Packages/com.unity.addressables/Runtime/ResourceProviders/ContentCatalogProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/Services.meta create mode 100644 Packages/com.unity.addressables/Runtime/Services/PlatformMappingService.cs create mode 100644 Packages/com.unity.addressables/Runtime/Services/PlatformMappingService.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/Unity.Addressables.asmdef create mode 100644 Packages/com.unity.addressables/Runtime/Unity.Addressables.asmdef.meta create mode 100644 Packages/com.unity.addressables/Runtime/Utility.meta create mode 100644 Packages/com.unity.addressables/Runtime/Utility/AssetReferenceUtilities.cs create mode 100644 Packages/com.unity.addressables/Runtime/Utility/AssetReferenceUtilities.cs.meta create mode 100644 Packages/com.unity.addressables/Runtime/Utility/SerializationUtilities.cs create mode 100644 Packages/com.unity.addressables/Runtime/Utility/SerializationUtilities.cs.meta create mode 100644 Packages/com.unity.addressables/Tests.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAnalyticsTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAnalyticsTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetEntryTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetEntryTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetEntryTreeViewTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetEntryTreeViewTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetFolderSubfolderTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetFolderSubfolderTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetReferenceTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetReferenceTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetSettingsLocatorTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetSettingsLocatorTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetSettingsTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetSettingsTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetTestBase.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetTestBase.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetUtilityTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetUtilityTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetsBundleBuildParametersTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetsBundleBuildParametersTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetsWindowTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AddressableAssetsWindowTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AnalyzeRules.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AnalyzeRules/AnalyzeRuleBaseTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AnalyzeRules/AnalyzeRuleBaseTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AnalyzeRules/CheckBundleDupeDependencyTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AnalyzeRules/CheckBundleDupeDependencyTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AnalyzeRules/CheckResourcesDupeDependenciesTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AnalyzeRules/CheckResourcesDupeDependenciesTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AnalyzeRules/CheckSceneDupeDependenciesTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AnalyzeRules/CheckSceneDupeDependenciesTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AssetGroupTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AssetGroupTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/AssetReferenceDrawerTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/AssetReferenceDrawerTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/BinaryStorageBufferTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/BinaryStorageBufferTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/AddHashToBundleNameTaskTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/AddHashToBundleNameTaskTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/AddressableBuildTaskTestBase.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/AddressableBuildTaskTestBase.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/AddressablesPlayerBuildProcessorTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/AddressablesPlayerBuildProcessorTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildLayoutGenerationTaskTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildLayoutGenerationTaskTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildMenuTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildMenuTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildScriptFastTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildScriptFastTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildScriptPackedIntegrationTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildScriptPackedIntegrationTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildScriptPackedPlayTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildScriptPackedPlayTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildScriptPackedTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildScriptPackedTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildScriptTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/BuildScriptTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/DataBuilderInputTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/DataBuilderInputTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/GenerateLocationListsTaskTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/GenerateLocationListsTaskTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/VerifyPublicBuildScripts.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Build/VerifyPublicBuildScripts.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/BuildReportVisualizer.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/BuildReportVisualizer/BuildReportListViewTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/BuildReportVisualizer/BuildReportListViewTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/BuildReportWindowTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/BuildReportWindowTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/BuiltinSceneCacheTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/BuiltinSceneCacheTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/ComponentSingletonTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/ComponentSingletonTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/ContentCatalogTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/ContentCatalogTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/ContentUpdateTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/ContentUpdateTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/CustomTestSchema.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/CustomTestSchema.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/CustomTestSchemaSubClass.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/CustomTestSchemaSubClass.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics/BuildLayoutTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics/BuildLayoutTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics/Profiler.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics/Profiler/AddressablesProfilerDetailsViewTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics/Profiler/AddressablesProfilerDetailsViewTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics/Profiler/BuildLayoutBuilder.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics/Profiler/BuildLayoutBuilder.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics/Profiler/ProfilerEventBuilder.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics/Profiler/ProfilerEventBuilder.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics/Profiler/TestProfiler.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics/Profiler/TestProfiler.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics/ProfilerTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Diagnostics/ProfilerTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/AddExceptionHandler.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/AddExceptionHandler.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/AsynchronousLoading.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/AsynchronousLoading.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/BatchBuild.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/BatchBuild.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/BuildLauncher.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/BuildLauncher.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/CustomBuildScript.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/CustomBuildScript.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/CustomDataBuilder.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/CustomDataBuilder.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/DeclaringReferences.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/DeclaringReferences.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/DisableBuildWarnings.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/DisableBuildWarnings.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/DownloadError.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/DownloadError.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/IDTransformer.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/IDTransformer.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/InstantiateAsset.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/InstantiateAsset.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/InstantiateReference.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/InstantiateReference.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadLocation.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadLocation.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadMultiple.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadMultiple.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadReference.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadReference.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadScene.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadScene.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadSingle.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadSingle.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadSynchronously.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadSynchronously.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadWithAddress.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadWithAddress.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadWithEvent.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadWithEvent.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadWithIEnumerator.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadWithIEnumerator.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadWithLabels.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadWithLabels.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadWithReference.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadWithReference.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadWithTask.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/LoadWithTask.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/MiscellaneousTopics.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/MiscellaneousTopics.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/MyRule.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/MyRule.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/OperationHandleTypes.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/OperationHandleTypes.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/Preload.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/Preload.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/PreloadWithProgress.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/PreloadWithProgress.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/PrintBucketInformation.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/PrintBucketInformation.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/Readme.txt create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/Readme.txt.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/ContentBuiltCheck.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/ContentBuiltCheck.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingAddResourceLocator.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingAddResourceLocator.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingAssetRefSpriteValidateAsset.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingAssetRefSpriteValidateAsset.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingBuildPath.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingBuildPath.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingCheckForCatalogUpdates.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingCheckForCatalogUpdates.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingCleanBundleCache.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingCleanBundleCache.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingClearDependencyCacheAsync.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingClearDependencyCacheAsync.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingClearResourceLocators.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingClearResourceLocators.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingCreateCatalogLocationWithHashDependencies.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingCreateCatalogLocationWithHashDependencies.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingCreateGroup.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingCreateGroup.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingDefaultSchemaSettingsBuildTargetGroup.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingDefaultSchemaSettingsBuildTargetGroup.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingDownloadDependencies.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingDownloadDependencies.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingDownloadDependenciesAsync.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingDownloadDependenciesAsync.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingGetDownloadSize.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingGetDownloadSize.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingGetDownloadSizeAsync.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingGetDownloadSizeAsync.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingGetLocatorInfo.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingGetLocatorInfo.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInitializationOperation.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInitializationOperation.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInitialize.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInitialize.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInitializeAsync.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInitializeAsync.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInstanceProvider.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInstanceProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInstantiate.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInstantiate.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInstantiateAsync.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInstantiateAsync.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInternalIdTransformFunc.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingInternalIdTransformFunc.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadAsset.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadAsset.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadAssetAsync.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadAssetAsync.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadAssets.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadAssets.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadAssetsAsync.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadAssetsAsync.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadContentCatalog.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadContentCatalog.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadContentCatalogAsync.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadContentCatalogAsync.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadResourceLocations.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadResourceLocations.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadResourceLocationsAsync.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadResourceLocationsAsync.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadScene.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadScene.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadSceneAsync.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLoadSceneAsync.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLog.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLog.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLogError.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLogError.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLogErrorFormat.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLogErrorFormat.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLogException.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLogException.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLogFormat.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLogFormat.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLogWarning.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLogWarning.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLogWarningFormat.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingLogWarningFormat.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingPlayerBuildDataPath.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingPlayerBuildDataPath.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingProfileSetValue.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingProfileSetValue.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingRelease.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingRelease.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingReleaseInstance.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingReleaseInstance.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingRemoveResourceLocator.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingRemoveResourceLocator.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingResolveInternalId.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingResolveInternalId.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingResourceLocators.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingResourceLocators.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingResourceManager.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingResourceManager.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingRuntimePath.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingRuntimePath.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingStreamingAssetsSubFolder.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingStreamingAssetsSubFolder.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingUnloadSceneAsync.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingUnloadSceneAsync.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingWebRequestOverride.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/ScriptReference/UsingWebRequestOverride.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/TestStub.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/TestStub.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/Unity.Addressables.DocExampleCode.Editor.Tests.asmdef create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/Unity.Addressables.DocExampleCode.Editor.Tests.asmdef.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/WebRequestOverride.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DocExampleCode/WebRequestOverride.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/DomainReloadTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/DomainReloadTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/EditorAddressablesAssetsTestFixture.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/EditorAddressablesAssetsTestFixture.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/EditorPlatformMappingServiceTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/EditorPlatformMappingServiceTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~GroupEditorTests_Group.unity rename Assets/Test.unity.meta => Packages/com.unity.addressables/Tests/Editor/Expected/~GroupEditorTests_Group.unity.meta (74%) create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_AddressableAssetSettings.ccd2.unity create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_AddressableAssetSettings.ccd2.unity.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_AddressableAssetSettings.ccd3.unity create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_AddressableAssetSettings.ccd3.unity.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_AddressableAssetSettings.unity create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_AddressableAssetSettings.unity.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_AddressableAssetSettings_62.ccd2.unity create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_AddressableAssetSettings_62.ccd2.unity.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_AddressableAssetSettings_62.ccd3.unity create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_AddressableAssetSettings_62.ccd3.unity.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_AddressableAssetSettings_62.unity create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_AddressableAssetSettings_62.unity.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_Group.unity create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_Group.unity.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_GroupTemplate.unity create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_GroupTemplate.unity.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_GroupTemplate_62.unity create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_GroupTemplate_62.unity.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_Group_62.unity create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_Group_62.unity.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_ProfileDataSourceSettings.unity create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_ProfileDataSourceSettings.unity.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_ProfileDataSourceSettings_62.unity create mode 100644 Packages/com.unity.addressables/Tests/Editor/Expected/~SerializationTests_ProfileDataSourceSettings_62.unity.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Fixtures.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Fixtures/InitFixture.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Fixtures/InitFixture.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Fixtures/InitFixture1.asset create mode 100644 Packages/com.unity.addressables/Tests/Editor/Fixtures/InitFixture1.asset.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Fixtures/InitFixture2.asset create mode 100644 Packages/com.unity.addressables/Tests/Editor/Fixtures/InitFixture2.asset.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Fixtures/buildlayout1.json create mode 100644 Packages/com.unity.addressables/Tests/Editor/Fixtures/buildlayout1.json.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/GUI.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/GUI/AddressableAssetSettingsGroupEditorTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/GUI/AddressableAssetSettingsGroupEditorTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/GUI/FastIconLoading.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/GUI/FastIconLoading.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/GUI/SomeScriptableObject.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/GUI/SomeScriptableObject.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/GUI/UpgradeNotificationsTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/GUI/UpgradeNotificationsTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/GroupSchemaTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/GroupSchemaTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/KeyDataStoreTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/KeyDataStoreTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/NamespaceTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/NamespaceTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/OptionalPackages.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/OptionalPackages/Ccd.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/OptionalPackages/Ccd/CcdBuildMenuTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/OptionalPackages/Ccd/CcdBuildMenuTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/OptionalPackages/Ccd/CcdManagementServiceSdkMock.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/OptionalPackages/Ccd/CcdManagementServiceSdkMock.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/OptionalPackages/Ccd/CcdNotFoundTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/OptionalPackages/Ccd/CcdNotFoundTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/OptionalPackages/PlaceholderTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/OptionalPackages/PlaceholderTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/OrgDataTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/OrgDataTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/ProfileDataSourceSettingsTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/ProfileDataSourceSettingsTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/ProfileGroupTypeTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/ProfileGroupTypeTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/ProfileSettingsTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/ProfileSettingsTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/ProfileValueReferenceTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/ProfileValueReferenceTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/ResourceCleanupTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/ResourceCleanupTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/SearchFiltersTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/SearchFiltersTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/SerializationTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/SerializationTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/TestObject.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/TestObject.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/TestSubObject.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/TestSubObject.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Unity.Addressables.Editor.Tests.asmdef create mode 100644 Packages/com.unity.addressables/Tests/Editor/Unity.Addressables.Editor.Tests.asmdef.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Utility.meta create mode 100644 Packages/com.unity.addressables/Tests/Editor/Utility/AssetReferenceUtilitiesTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Editor/Utility/AssetReferenceUtilitiesTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AddressableAssetSettingsResourceLocationTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AddressableAssetSettingsResourceLocationTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AddressablesImplTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AddressablesImplTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AddressablesIntegrationTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AddressablesIntegrationTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AddressablesIntegrationTestsImpl.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AddressablesIntegrationTestsImpl.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AddressablesTestFixture.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AddressablesTestFixture.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AddressablesTestUtilities.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AddressablesTestUtilities.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AssemblyInfo.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AssemblyInfo.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AssetBundleProviderRetryTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AssetBundleProviderRetryTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AssetBundleProviderTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AssetBundleProviderTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AssetReferenceDrawerTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AssetReferenceDrawerTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AssetReferenceTestBehavior.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AssetReferenceTestBehavior.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AsyncTaskTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/AsyncTaskTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/CleanBundleCacheTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/CleanBundleCacheTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/DynamicContentUpdateTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/DynamicContentUpdateTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/DynamicResourceLocationTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/DynamicResourceLocationTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/IgnoreFailingLogMessage.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/IgnoreFailingLogMessage.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/Initialization.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/Initialization/AddrRuntimePropertiesTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/Initialization/AddrRuntimePropertiesTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/Initialization/FastModeInitializationTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/Initialization/FastModeInitializationTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/InitializationObjectsAsyncTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/InitializationObjectsAsyncTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ManualPercentCompleteOperation.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ManualPercentCompleteOperation.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/NamespaceTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/NamespaceTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ObjectReferenceMonoBehaviour.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ObjectReferenceMonoBehaviour.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/OptionalPackages.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/OptionalPackages/Ccd.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/OptionalPackages/Ccd/CcdManagerTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/OptionalPackages/Ccd/CcdManagerTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/Operations.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/Operations/AsyncOperationHandleTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/Operations/AsyncOperationHandleTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/Operations/BaseOperationBehaviorTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/Operations/BaseOperationBehaviorTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/Operations/ChainOperationTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/Operations/ChainOperationTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/Operations/ProviderOperationTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/Operations/ProviderOperationTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/OperationsCacheTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/OperationsCacheTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/ResourceManagerBaseTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/ResourceManagerBaseTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/ResourceManagerFastModeTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/ResourceManagerFastModeTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/ResourceManagerPackedModeTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/ResourceManagerPackedModeTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/ResourceManagerTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/ResourceManagerTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/ResourceManagerUtilityTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/ResourceManagerUtilityTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/TestUtil.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/TestUtil/MockProvider.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/TestUtil/MockProvider.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/Unity.ResourceManager.Tests.asmdef create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/Unity.ResourceManager.Tests.asmdef.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/VirtualAssetBundleProviderTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceManager/VirtualAssetBundleProviderTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceProviders.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceProviders/ContentCatalogProviderTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceProviders/ContentCatalogProviderTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceProviders/TextDataProviderStub.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/ResourceProviders/TextDataProviderStub.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/RuntimePlatformMappingServiceTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/RuntimePlatformMappingServiceTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/SceneTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/SceneTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/StripDownloadOptionsTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/StripDownloadOptionsTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/SyncAddressableTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/SyncAddressableTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/TestBehaviourWithReference.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/TestBehaviourWithReference.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/TestObject.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/TestObject.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/TestObject2.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/TestObject2.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/TestObjectWithSerializableField.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/TestObjectWithSerializableField.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/TestReflectionHelpers.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/TestReflectionHelpers.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/TextDataProviderTests.cs create mode 100644 Packages/com.unity.addressables/Tests/Runtime/TextDataProviderTests.cs.meta create mode 100644 Packages/com.unity.addressables/Tests/Runtime/Unity.Addressables.Runtime.Tests.asmdef create mode 100644 Packages/com.unity.addressables/Tests/Runtime/Unity.Addressables.Runtime.Tests.asmdef.meta create mode 100644 Packages/com.unity.addressables/package.json rename Packages/{dev.pugstorm.sprite => com.unity.addressables}/package.json.meta (60%) create mode 100644 Packages/com.unity.addressables/readme.md create mode 100644 Packages/com.unity.addressables/readme.md.meta delete mode 100644 Packages/dev.pugstorm.sprite/package.json create mode 100644 ProjectSettings/MultiplayerManager.asset diff --git a/.idea/.idea.CoreLib-main/.idea/encodings.xml b/.idea/.idea.CoreLib-main/.idea/encodings.xml new file mode 100644 index 00000000..df87cf95 --- /dev/null +++ b/.idea/.idea.CoreLib-main/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.CoreLib-main/.idea/indexLayout.xml b/.idea/.idea.CoreLib-main/.idea/indexLayout.xml new file mode 100644 index 00000000..7b08163c --- /dev/null +++ b/.idea/.idea.CoreLib-main/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.CoreLib-main/.idea/projectSettingsUpdater.xml b/.idea/.idea.CoreLib-main/.idea/projectSettingsUpdater.xml new file mode 100644 index 00000000..ef20cb08 --- /dev/null +++ b/.idea/.idea.CoreLib-main/.idea/projectSettingsUpdater.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/.idea/.idea.CoreLib-main/.idea/vcs.xml b/.idea/.idea.CoreLib-main/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/.idea.CoreLib-main/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/.idea.CoreLib-main/.idea/workspace.xml b/.idea/.idea.CoreLib-main/.idea/workspace.xml new file mode 100644 index 00000000..bf1b4919 --- /dev/null +++ b/.idea/.idea.CoreLib-main/.idea/workspace.xml @@ -0,0 +1,6283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1761777921684 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 5fa5207f..00000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -JsonBuild.py \ No newline at end of file diff --git a/.idea/indexLayout.xml b/.idea/indexLayout.xml new file mode 100644 index 00000000..7b08163c --- /dev/null +++ b/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/projectSettingsUpdater.xml b/.idea/projectSettingsUpdater.xml new file mode 100644 index 00000000..ef20cb08 --- /dev/null +++ b/.idea/projectSettingsUpdater.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index aec2ec37..1feb8907 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,43 +2,9 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + \ No newline at end of file diff --git a/Assets/CoreLibPackage/CoreLib.Editor/Editor/RenderingFix.cs b/Assets/CoreLibPackage/CoreLib.Editor/Editor/RenderingFix.cs index e4127d2a..5e3b9693 100644 --- a/Assets/CoreLibPackage/CoreLib.Editor/Editor/RenderingFix.cs +++ b/Assets/CoreLibPackage/CoreLib.Editor/Editor/RenderingFix.cs @@ -15,7 +15,7 @@ public static void FixRendering() Shader spriteShader = Resources.Load("SpriteLit"); Debug.Log("Setting RP asset to EditorKit RP!"); - GraphicsSettings.renderPipelineAsset = rp; + GraphicsSettings.defaultRenderPipeline = rp; string[] materialGUIDS = AssetDatabase.FindAssets("t:material"); string[] materialPaths = materialGUIDS.Select(AssetDatabase.GUIDToAssetPath).ToArray(); diff --git a/Assets/CoreLibPackage/CoreLib.Resources/Scripts/Addressables/ModResourceLocator.cs b/Assets/CoreLibPackage/CoreLib.Resources/Scripts/Addressables/ModResourceLocator.cs index d08494c9..53833728 100644 --- a/Assets/CoreLibPackage/CoreLib.Resources/Scripts/Addressables/ModResourceLocator.cs +++ b/Assets/CoreLibPackage/CoreLib.Resources/Scripts/Addressables/ModResourceLocator.cs @@ -10,7 +10,9 @@ public class ModResourceLocator : IResourceLocator { internal const string PROTOCOL = "mod:"; internal const string NAMESPACE = "CoreLib.ModResources."; - + + public IEnumerable AllLocations { get; } + public bool Locate(object key, Type type, out IList locations) { if (key is string stringKey && stringKey.StartsWith(PROTOCOL)) diff --git a/Assets/CoreLibPackage/CoreLib/Resources/Rendering/EditorKit RP.asset b/Assets/CoreLibPackage/CoreLib/Resources/Rendering/EditorKit RP.asset index e10a9b17..fabd90f5 100644 --- a/Assets/CoreLibPackage/CoreLib/Resources/Rendering/EditorKit RP.asset +++ b/Assets/CoreLibPackage/CoreLib/Resources/Rendering/EditorKit RP.asset @@ -12,8 +12,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} m_Name: EditorKit RP m_EditorClassIdentifier: - k_AssetVersion: 11 - k_AssetPreviousVersion: 11 + k_AssetVersion: 12 + k_AssetPreviousVersion: 12 m_RendererType: 1 m_RendererData: {fileID: 0} m_RendererDataList: @@ -33,6 +33,14 @@ MonoBehaviour: m_EnableLODCrossFade: 1 m_LODCrossFadeDitheringType: 1 m_ShEvalMode: 0 + m_LightProbeSystem: 0 + m_ProbeVolumeMemoryBudget: 1024 + m_ProbeVolumeBlendingMemoryBudget: 256 + m_SupportProbeVolumeGPUStreaming: 0 + m_SupportProbeVolumeDiskStreaming: 0 + m_SupportProbeVolumeScenarios: 0 + m_SupportProbeVolumeScenarioBlending: 0 + m_ProbeVolumeSHBands: 1 m_MainLightRenderingMode: 1 m_MainLightShadowsSupported: 1 m_MainLightShadowmapResolution: 2048 @@ -67,21 +75,30 @@ MonoBehaviour: m_SupportsLightLayers: 0 m_DebugLevel: 0 m_StoreActionsOptimization: 0 - m_EnableRenderGraph: 0 m_UseAdaptivePerformance: 1 m_ColorGradingMode: 0 m_ColorGradingLutSize: 32 + m_AllowPostProcessAlphaOutput: 0 m_UseFastSRGBLinearConversion: 0 m_SupportDataDrivenLensFlare: 1 + m_SupportScreenSpaceLensFlare: 1 + m_GPUResidentDrawerMode: 0 + m_SmallMeshScreenPercentage: 0 + m_GPUResidentDrawerEnableOcclusionCullingInCameras: 0 m_ShadowType: 1 m_LocalShadowsSupported: 0 m_LocalShadowsAtlasResolution: 256 m_MaxPixelLights: 0 m_ShadowAtlasResolution: 256 m_VolumeFrameworkUpdateMode: 0 - m_Textures: - blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} - bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} + m_VolumeProfile: {fileID: 0} + apvScenesData: + obsoleteSceneBounds: + m_Keys: [] + m_Values: [] + obsoleteHasProbeVolumes: + m_Keys: [] + m_Values: m_PrefilteringModeMainLightShadows: 4 m_PrefilteringModeAdditionalLight: 4 m_PrefilteringModeAdditionalLightShadows: 0 @@ -92,6 +109,7 @@ MonoBehaviour: m_PrefilterDebugKeywords: 1 m_PrefilterWriteRenderingLayers: 1 m_PrefilterHDROutput: 1 + m_PrefilterAlphaOutput: 0 m_PrefilterSSAODepthNormals: 1 m_PrefilterSSAOSourceDepthLow: 1 m_PrefilterSSAOSourceDepthMedium: 1 @@ -110,5 +128,11 @@ MonoBehaviour: m_PrefilterSoftShadows: 0 m_PrefilterScreenCoord: 1 m_PrefilterNativeRenderPass: 1 + m_PrefilterUseLegacyLightmaps: 0 + m_PrefilterReflectionProbeBlending: 0 + m_PrefilterReflectionProbeBoxProjection: 0 m_ShaderVariantLogLevel: 0 m_ShadowCascades: 0 + m_Textures: + blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} + bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} diff --git a/Assets/DefaultVolumeProfile.asset b/Assets/DefaultVolumeProfile.asset new file mode 100644 index 00000000..36c3781a --- /dev/null +++ b/Assets/DefaultVolumeProfile.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d7fd9488000d3734a9e00ee676215985, type: 3} + m_Name: DefaultVolumeProfile + m_EditorClassIdentifier: + components: [] diff --git a/Assets/DefaultVolumeProfile.asset.meta b/Assets/DefaultVolumeProfile.asset.meta new file mode 100644 index 00000000..a43a58ea --- /dev/null +++ b/Assets/DefaultVolumeProfile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 42c79ee4c373f94479d14b85fcbe5605 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ModSDK/EditorAssemblies.zip b/Assets/ModSDK/EditorAssemblies.zip index 8039271f7c5ac9e349ff271336fc80926ba1ed29..916650e5228d06fd87dde746a16523f196d4a04b 100644 GIT binary patch literal 54710 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 AP+HQwLlG%S;!vnBdsG_PgK!}4 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 Do{U*e literal 54683 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 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/Packages/com.unity.addressables/CHANGELOG.md.meta b/Packages/com.unity.addressables/CHANGELOG.md.meta new file mode 100644 index 00000000..25f479f7 --- /dev/null +++ b/Packages/com.unity.addressables/CHANGELOG.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6f6c277bb5d2a164e8c95a7f0754c0f6 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/dev.pugstorm.sprite/Resources/Shaders.meta b/Packages/com.unity.addressables/Editor.meta similarity index 77% rename from Packages/dev.pugstorm.sprite/Resources/Shaders.meta rename to Packages/com.unity.addressables/Editor.meta index dea2113d..c8455759 100644 --- a/Packages/dev.pugstorm.sprite/Resources/Shaders.meta +++ b/Packages/com.unity.addressables/Editor.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 75238f336dc3db24dacd0151a3d39b6b +guid: 435c98e736a6f6142a2f3819f4927004 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Packages/com.unity.addressables/Editor/AddressableAssetSettingsDefaultObject.cs b/Packages/com.unity.addressables/Editor/AddressableAssetSettingsDefaultObject.cs new file mode 100644 index 00000000..40047b49 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/AddressableAssetSettingsDefaultObject.cs @@ -0,0 +1,181 @@ +using System; +using UnityEditor.AddressableAssets.Settings; +using UnityEngine; +using UnityEngine.Serialization; + +namespace UnityEditor.AddressableAssets +{ + /// + /// Class used to get and set the default object. + /// + public class AddressableAssetSettingsDefaultObject : ScriptableObject + { + /// + /// Default name for the . + /// + 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 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 object. This will return null during editor startup if or 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 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 object. + public static AddressableAssetSettings GetSettings(bool create) + { + if (Settings == null && create) + Settings = AddressableAssetSettings.Create(kDefaultConfigFolder, kDefaultConfigAssetName, true, true); + return Settings; + } + } +} diff --git a/Packages/com.unity.addressables/Editor/AddressableAssetSettingsDefaultObject.cs.meta b/Packages/com.unity.addressables/Editor/AddressableAssetSettingsDefaultObject.cs.meta new file mode 100644 index 00000000..5151bf0f --- /dev/null +++ b/Packages/com.unity.addressables/Editor/AddressableAssetSettingsDefaultObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3a189bb168d8d90478a09ea08c2f3d72 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/AddressableEditorInitialization.cs b/Packages/com.unity.addressables/Editor/AddressableEditorInitialization.cs new file mode 100644 index 00000000..734fb50f --- /dev/null +++ b/Packages/com.unity.addressables/Editor/AddressableEditorInitialization.cs @@ -0,0 +1,66 @@ +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) + 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/Packages/com.unity.addressables/Editor/AddressableEditorInitialization.cs.meta b/Packages/com.unity.addressables/Editor/AddressableEditorInitialization.cs.meta new file mode 100644 index 00000000..2edb7c52 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/AddressableEditorInitialization.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bf8251aa3d694f2459ee1fbb73cf9123 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/AssemblyInfo.cs b/Packages/com.unity.addressables/Editor/AssemblyInfo.cs new file mode 100644 index 00000000..4f9537a4 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/AssemblyInfo.cs @@ -0,0 +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.Runtime.Tests")] +[assembly: InternalsVisibleTo("PerformanceTests.Editor")] +[assembly: InternalsVisibleTo("Unity.Localization.Editor")] +[assembly: InternalsVisibleTo("Unity.Addressables.Android.Editor")] diff --git a/Packages/com.unity.addressables/Editor/AssemblyInfo.cs.meta b/Packages/com.unity.addressables/Editor/AssemblyInfo.cs.meta new file mode 100644 index 00000000..13c7bb1a --- /dev/null +++ b/Packages/com.unity.addressables/Editor/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 053ca114086a74fd6842a2f9944a47cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build.meta b/Packages/com.unity.addressables/Editor/Build.meta new file mode 100644 index 00000000..4cc0e4b7 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: aa6bb3acc97adbc4ea57cbe5044ea2eb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AddressableAnalytics.cs b/Packages/com.unity.addressables/Editor/Build/AddressableAnalytics.cs new file mode 100644 index 00000000..ff23bfd6 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AddressableAnalytics.cs @@ -0,0 +1,687 @@ +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"; + + private const string packageName = "com.unity.addressables"; + +#if UNITY_2023_1_OR_NEWER + private static PackageManager.PackageInfo s_packageInfo = null; + private static PackageManager.PackageInfo packageInfo + { + get + { + if (s_packageInfo == null) + s_packageInfo = PackageManager.PackageInfo.FindForPackageName(packageName); + return s_packageInfo; + } + } +#endif + +#if UNITY_2023_3_OR_NEWER + [AnalyticInfo(vendorKey: VendorKey, eventName: BuildEvent)] + public class AddressablesBuildEvent : IAnalytic + { + AnalyticsBuildData cachedBuildData; + + public AddressablesBuildEvent(BuildData bd) + { + cachedBuildData = new AnalyticsBuildData(bd); + } + + public bool TryGatherData(out IAnalytic.IData data, out Exception error) + { + data = cachedBuildData; + error = null; + if (data == null) + return false; + return true; + } + } + + [AnalyticInfo(vendorKey: VendorKey, eventName: UsageEvent)] + public class AddressablesUsageEvent : IAnalytic + { + AnalyticsUsageData cachedUsageData; + + public AddressablesUsageEvent(UsageData ud) + { + cachedUsageData = new AnalyticsUsageData(ud); + } + + public bool TryGatherData(out IAnalytic.IData data, out Exception error) + { + data = cachedUsageData; + error = null; + if (data == null) + return false; + return true; + } + } + + [Serializable] + internal class AnalyticsUsageData : IAnalytic.IData + { + public int UsageEventType; + public bool IsUsingCCD; + public int AutoRunRestrictionsOption; + public string package; + public string package_ver; + + public AnalyticsUsageData(UsageData ud) + { + UsageEventType = ud.UsageEventType; + IsUsingCCD = ud.IsUsingCCD; + AutoRunRestrictionsOption = ud.AutoRunRestrictionsOption; + package = packageName; + package_ver = packageInfo?.version; + } + } + + [Serializable] + internal class AnalyticsBuildData : IAnalytic.IData + { + 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; + public string package; + public string package_ver; + + public AnalyticsBuildData(BuildData bd) + { + IsUsingCCD = bd.IsUsingCCD; + IsContentUpdateBuild = bd.IsContentUpdateBuild; + IsPlayModeBuild = bd.IsPlayModeBuild; + BuildScript = bd.BuildScript; + BuildAndRelease = bd.BuildAndRelease; +#if UNITY_2022_2_OR_NEWER + DebugBuildLayoutEnabled = bd.DebugBuildLayoutEnabled; + AutoOpenBuildReportEnabled = bd.AutoOpenBuildReportEnabled; +#endif + NumberOfLabels = bd.NumberOfLabels; + IsIncrementalBuild = bd.IsIncrementalBuild; + NumberOfAssetBundles = bd.NumberOfAssetBundles; + NumberOfAddressableAssets = bd.NumberOfAddressableAssets; + MinNumberOfAddressableAssetsInAGroup = bd.MinNumberOfAddressableAssetsInAGroup; + MaxNumberOfAddressableAssetsInAGroup = bd.MaxNumberOfAddressableAssetsInAGroup; + NumberOfGroups = bd.NumberOfGroups; + TotalBuildTime = bd.TotalBuildTime; + NumberOfGroupsUsingLZ4 = bd.NumberOfGroupsUsingLZ4; + NumberOfGroupsUsingLZMA = bd.NumberOfGroupsUsingLZMA; + NumberOfGroupsUncompressed = bd.NumberOfGroupsUncompressed; + NumberOfGroupsPackedTogether = bd.NumberOfGroupsPackedTogether; + NumberOfGroupsPackedTogetherByLabel = bd.NumberOfGroupsPackedTogetherByLabel; + NumberOfGroupsPackedSeparately = bd.NumberOfGroupsPackedSeparately; + NumberOfGroupsUsingBuiltIn = bd.NumberOfGroupsUsingBuiltIn; + NumberOfGroupsUsingEditorHosted = bd.NumberOfGroupsUsingEditorHosted; + NumberOfGroupsUsingRemoteCustomPaths = bd.NumberOfGroupsUsingRemoteCustomPaths; + NumberOfGroupsUsingLocalCustomPaths = bd.NumberOfGroupsUsingLocalCustomPaths; + NumberOfGroupsUsingCCD = bd.NumberOfGroupsUsingCCD; + NumberOfAssetsInRemoteCustomPaths = bd.NumberOfAssetsInRemoteCustomPaths; + NumberOfAssetsInLocalCustomPaths = bd.NumberOfAssetsInLocalCustomPaths; + NumberOfAssetsInBuiltInPaths = bd.NumberOfAssetsInBuiltInPaths; + NumberOfAssetsInEditorHostedPaths = bd.NumberOfAssetsInEditorHostedPaths; + NumberOfAssetsInCCDPaths = bd.NumberOfAssetsInCCDPaths; + BuildTarget = bd.BuildTarget; + ErrorCode = bd.ErrorCode; + package = packageName; + package_ver = packageInfo?.version; + } + } +#endif + + [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, + // Formerly: Virtual mode - 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; + 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.GetValueOrDefault(groupTypes[selected].GroupTypePrefix, PathType.Custom); + + 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, + DebugBuildLayoutEnabled = ProjectConfigData.GenerateBuildLayout, + AutoOpenBuildReportEnabled = ProjectConfigData.AutoOpenAddressablesReport && ProjectConfigData.GenerateBuildLayout, + NumberOfLabels = currentSettings.labelTable.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 UNITY_2023_1_OR_NEWER + // Cannot post analytics events from contexts that don't have access to the package version + if (packageInfo == null) + return; +#endif + + BuildData data = GenerateBuildData(builderInput, result, buildType); +#if UNITY_2023_3_OR_NEWER + AddressablesBuildEvent evt = new AddressablesBuildEvent(data); + EditorAnalytics.SendAnalytic(evt); +#else + #pragma warning disable CS0618 // Type or member is obsolete + if (!EventIsRegistered(BuildEvent)) + if (!RegisterEvent(BuildEvent)) + return; + EditorAnalytics.SendEventWithLimit(BuildEvent, data); + #pragma warning restore CS0618 // Type or member is obsolete +#endif + } + + 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; + + +#if UNITY_2023_1_OR_NEWER + // Cannot post analytics events from contexts that don't have access to the package version + if (packageInfo == null) + return; +#endif + + var sessionStateKey = GetSessionStateKeyByUsageEventType(eventType); + + if (limitEventOncePerSession && sessionStateKey != null && SessionState.GetBool(sessionStateKey, false)) + return; + + if (!SessionState.GetBool(sessionStateKey, false)) + SessionState.SetBool(sessionStateKey, true); + + UsageData data = GenerateUsageData(eventType, (AnalyticsContentUpdateRestriction)contentUpdateRestriction); +#if UNITY_2023_3_OR_NEWER + AddressablesUsageEvent evt = new AddressablesUsageEvent(data); + EditorAnalytics.SendAnalytic(evt); +#else + #pragma warning disable CS0618 // Type or member is obsolete + if (!EventIsRegistered(UsageEvent)) + if (!RegisterEvent(UsageEvent)) + return; + EditorAnalytics.SendEventWithLimit(UsageEvent, data); + #pragma warning restore CS0618 // Type or member is obsolete +#endif + } + + private static bool RegisterEvent(string eventName) + { + bool eventSuccessfullyRegistered = false; +#pragma warning disable CS0618 // Type or member is obsolete + AnalyticsResult registerEvent = EditorAnalytics.RegisterEventWithLimit(eventName, 100, 100, VendorKey); +#pragma warning restore CS0618 // Type or member is obsolete + if (registerEvent == AnalyticsResult.Ok) + { + _registeredEvents.Add(eventName); + eventSuccessfullyRegistered = true; + } + + return eventSuccessfullyRegistered; + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/AddressableAnalytics.cs.meta b/Packages/com.unity.addressables/Editor/Build/AddressableAnalytics.cs.meta new file mode 100644 index 00000000..15318af7 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AddressableAnalytics.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3a6ea556a4c75be4a88f236f22eec817 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AddressableAssetSettingsLocator.cs b/Packages/com.unity.addressables/Editor/Build/AddressableAssetSettingsLocator.cs new file mode 100644 index 00000000..b5475290 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AddressableAssetSettingsLocator.cs @@ -0,0 +1,350 @@ +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_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); + } + } + } + + 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.Count); + using (new AddressablesFileEnumerationScope(m_AddressableAssetTree)) + { + foreach (AddressableAssetGroup g in m_Settings.groups) + { + if (g == null) + continue; + + foreach (AddressableAssetEntry e in g.entries) + { + 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.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('/'); + } + } + } + + 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/Packages/com.unity.addressables/Editor/Build/AddressableAssetSettingsLocator.cs.meta b/Packages/com.unity.addressables/Editor/Build/AddressableAssetSettingsLocator.cs.meta new file mode 100644 index 00000000..2128fc48 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AddressableAssetSettingsLocator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b9c2125236cf11d4a98cd25ea3214ad4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AddressablesBuildScriptHooks.cs b/Packages/com.unity.addressables/Editor/Build/AddressablesBuildScriptHooks.cs new file mode 100644 index 00000000..50b079d1 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AddressablesBuildScriptHooks.cs @@ -0,0 +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); + } + } + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/AddressablesBuildScriptHooks.cs.meta b/Packages/com.unity.addressables/Editor/Build/AddressablesBuildScriptHooks.cs.meta new file mode 100644 index 00000000..f877f7af --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AddressablesBuildScriptHooks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a15f049c10fa744ca827575ffac1c0d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilderInput.cs b/Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilderInput.cs new file mode 100644 index 00000000..6ce96eda --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilderInput.cs @@ -0,0 +1,117 @@ +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// Data builder context object for Addressables. This contains all of the necessary input data to a build. + /// + 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; } + + /// + /// Registry of files created during the build + /// + public FileRegistry Registry { get; private set; } + + /// + /// can be used in testing to append a suffix to file paths + /// + public 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_JSON_CATALOG + "catalog.json"; +#else + "catalog.bin"; +#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; + Registry = new FileRegistry(); + PreviousContentState = null; + } + + internal bool IsBuildAndRelease = false; + internal bool IsContentUpdateBuild = false; + + internal IBuildLogger Logger { get; set; } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilderInput.cs.meta b/Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilderInput.cs.meta new file mode 100644 index 00000000..20e7fe0f --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilderInput.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 69d3f19413a88324199b41186cf34b9f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilders.cs b/Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilders.cs new file mode 100644 index 00000000..ee6ce774 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilders.cs @@ -0,0 +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 that is generated during the build. + /// + 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 + /// The result of the data builder + 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. + /// + /// The type of IDataBuilderResult you want to produce from a build + /// The result of the data builder + 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 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; set; } + + /// + /// List of 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/Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilders.cs.meta b/Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilders.cs.meta new file mode 100644 index 00000000..ae171e4a --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AddressablesDataBuilders.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1912c97b524efd244bc0647b18230c7e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AddressablesPlayerBuildProcessor.cs b/Packages/com.unity.addressables/Editor/Build/AddressablesPlayerBuildProcessor.cs new file mode 100644 index 00000000..417fb604 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AddressablesPlayerBuildProcessor.cs @@ -0,0 +1,187 @@ +using System; +using System.IO; +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.AddressableAssets; +using UnityEditor.AddressableAssets.Build; +using UnityEditor.AddressableAssets.GUI; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.Build; +using UnityEngine; +using UnityEngine.AddressableAssets; + +/// +/// 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. + /// + /// Context for the Scriptable Build Pipeline on how to build AssetBundles + 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 + result = DefaultBuild(settings); + + 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); + } + } + + static AddressablesPlayerBuildResult DefaultBuild(AddressableAssetSettings settings) + { + var types = AddressableAssetUtility.GetTypes(); + var displayMenus = AddressableAssetsSettingsGroupEditor.CreateBuildMenus(types); + AddressableAssetsSettingsGroupEditor.IAddressablesBuildMenu defaultNewBuildMenu = null; + foreach (var buildMenu in displayMenus) + { + if (buildMenu.BuildMenuPath == "New Build") + { + defaultNewBuildMenu = buildMenu; + break; + } + } + + if (defaultNewBuildMenu != null) + { + AddressableAssetsSettingsGroupEditor.BuildMenuContext context = new AddressableAssetsSettingsGroupEditor.BuildMenuContext() + { buildScriptIndex = -1, BuildMenu = defaultNewBuildMenu, Settings = settings }; + return AddressableAssetsSettingsGroupEditor.BuildAddressablesWithResult(context); + } + else + { + AddressableAssetSettings.BuildPlayerContent(out AddressablesPlayerBuildResult result); + return result; + } + } + + 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; + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/AddressablesPlayerBuildProcessor.cs.meta b/Packages/com.unity.addressables/Editor/Build/AddressablesPlayerBuildProcessor.cs.meta new file mode 100644 index 00000000..7d5c0311 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AddressablesPlayerBuildProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 834e2bdb5fd1336429e26ec5bcbb77f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules.meta b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules.meta new file mode 100644 index 00000000..adcfc9c3 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eccc8dae555be31429a4bd74ee1d1f18 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeResultData.cs b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeResultData.cs new file mode 100644 index 00000000..0ce65067 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeResultData.cs @@ -0,0 +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(); + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeResultData.cs.meta b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeResultData.cs.meta new file mode 100644 index 00000000..0b487535 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeResultData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: abc77607c2a62ef48b8f7dec55cc6d91 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeRule.cs b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeRule.cs new file mode 100644 index 00000000..b76e12df --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeRule.cs @@ -0,0 +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(); + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeRule.cs.meta b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeRule.cs.meta new file mode 100644 index 00000000..800351db --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeRule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cfe8ad6aa7980734a89a782fcc937045 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeSystem.cs b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeSystem.cs new file mode 100644 index 00000000..e3955ff1 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeSystem.cs @@ -0,0 +1,217 @@ +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 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/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeSystem.cs.meta b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeSystem.cs.meta new file mode 100644 index 00000000..a13f40d6 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/AnalyzeSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6d97546331657044a99aed2e45ee76a2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BuildBundleLayout.cs b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BuildBundleLayout.cs new file mode 100644 index 00000000..090aaeb5 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BuildBundleLayout.cs @@ -0,0 +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(); + } + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BuildBundleLayout.cs.meta b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BuildBundleLayout.cs.meta new file mode 100644 index 00000000..fe01836d --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BuildBundleLayout.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d314656232cf1b24a9d7e6470f8f72eb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BundleRuleBase.cs b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BundleRuleBase.cs new file mode 100644 index 00000000..ac1fa4eb --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BundleRuleBase.cs @@ -0,0 +1,691 @@ +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; + /// + /// A list of all the Asset Bundle input definitions. Each entry is an Asset Bundle build map + /// + 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 CreateBuiltInBundle(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 + /// Asset Bundle build map entry + 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 + { + /// + /// The path of the resource file + /// + public string ResourcePath; + + /// + /// The name of the Asset Bundle + /// + public string AssetBundleName; + + /// + /// The path of a Unity asset + /// + 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/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BundleRuleBase.cs.meta b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BundleRuleBase.cs.meta new file mode 100644 index 00000000..ba9f3c0c --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/BundleRuleBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8aae9ccc172d3fd48a20726e5c902489 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs new file mode 100644 index 00000000..17f04a2d --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs @@ -0,0 +1,329 @@ +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 + { + /// + /// The group that contains an asset that is being duplicated + /// + public AddressableAssetGroup Group; + + /// + /// The path of the file that contains a duplicate asset + /// + public string DuplicatedFile; + + /// + /// The path of the asset getting duplicated + /// + public string AssetPath; + + /// + /// The guid of the group causing a duplication + /// + public GUID DuplicatedGroupGuid; + } + + /// + /// Results for duplicate results inverted check + /// + protected internal struct ExtraCheckBundleDupeData + { + /// + /// If true, the Analyze tree will organize results based on affected assets first. Otherwise, + /// we'll lead with Asset Bundle info first + /// + 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/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs.meta b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs.meta new file mode 100644 index 00000000..7c16bdfe --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckBundleDupeDependencies.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 327933a391986b441b4355cdd9257400 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs new file mode 100644 index 00000000..df01df84 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs @@ -0,0 +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(); + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs.meta b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs.meta new file mode 100644 index 00000000..2864c532 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckResourcesDupeDependencies.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 555da02c9c624644c9695f325ea6a22c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs new file mode 100644 index 00000000..82f69cc4 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs @@ -0,0 +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(); + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs.meta b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs.meta new file mode 100644 index 00000000..4414d215 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/AnalyzeRules/CheckSceneDupeDependencies.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bd1bea4352ab4fb49a0d15da275cd26d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks.meta b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks.meta new file mode 100644 index 00000000..c8f4607b --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 917423f37317e754b934cc66f05b860a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs new file mode 100644 index 00000000..8f260883 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs @@ -0,0 +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()))); + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs.meta b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs.meta new file mode 100644 index 00000000..417cd5d6 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/AddHashToBundleNameTask.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d624c3bd70705446adc7ee473ceb159 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs new file mode 100644 index 00000000..2b4556d2 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs @@ -0,0 +1,1330 @@ +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. Instead of using this directly inject + /// the value through IBuildLayoutParUse BuildLayoutParameters.BundleNameRemap instead + /// + public Dictionary BundleNameRemap + { + get { return m_BuildLayoutParameters.BundleNameRemap; } + set { m_BuildLayoutParameters.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; + + [InjectContext(ContextUsage.In)] + IBuildLayoutParameters m_BuildLayoutParameters; +#pragma warning restore 649 + + internal AddressablesDataBuilderInput m_AddressablesInput; + + 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, BuildLayout.File file, string asset) + { + var bid = new BucketIdentifier(file, asset); + if (!buckets.TryGetValue(bid, out AssetBucket bucket)) + { + bucket = new AssetBucket(); + bucket.guid = asset; + bucket.file = file; + buckets.Add(bid, bucket); + } + + return bucket; + } + + class AssetBucket + { + public string guid; + public bool isFilePathBucket; + public List objs = new List(); + public BuildLayout.ExplicitAsset ExplictAsset; + public BuildLayout.File file; + + 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; + } + + // Each asset bucket is uniquely identified by the guid + the file the guid is in. + // We can't just use the guid because duplicated assets will result in the same guid being in multiple files. + private struct BucketIdentifier + { + public BuildLayout.File file; + public string refGuid; + + public BucketIdentifier(BuildLayout.File file, string refGuid) + { + this.file = file; + this.refGuid = refGuid; + } + + public override bool Equals(object obj) + { + if (obj is BucketIdentifier other) + { + return Equals(other); + } + return false; + } + + public bool Equals(BucketIdentifier other) + { + return Equals(file, other.file) && string.Equals(refGuid, other.refGuid); + } + + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = hash * 31 + (file != null ? file.Name.GetHashCode() : 0); + hash = hash * 31 + (refGuid != null ? refGuid.GetHashCode() : 0); + return hash; + } + } + + public static bool operator ==(BucketIdentifier left, BucketIdentifier right) + { + return left.Equals(right); + } + + public static bool operator !=(BucketIdentifier left, BucketIdentifier right) + { + return !(left == right); + } + } + 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>(); + + Dictionary buckets = new Dictionary(); + HashSet monoScriptAssets = new HashSet(); + Dictionary> guidToOtherData = new Dictionary>(); + Dictionary> guidToObjectNames = new Dictionary>(); + + foreach (BuildLayout.File file in lookup.Files.Values) + { + 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, file, info.serializedObject.filePath.ToString()); + pathBucket.isFilePathBucket = true; + pathBucket.objs.Add(info); + continue; + } + } + + AssetBucket bucket = GetOrCreate(buckets, file, info.serializedObject.guid.ToString()); + bucket.objs.Add(info); + } + + // buckets can be shared across different files (i guess that's what a duplicated asset is) + if (sceneObjects.Count > 0) + { + BuildLayout.ExplicitAsset sceneAsset = file.Assets.First(x => x.AssetPath.EndsWith(".unity", StringComparison.OrdinalIgnoreCase)); + AssetBucket bucket = GetOrCreate(buckets, file, sceneAsset.Guid); + bucket.objs.AddRange(sceneObjects); + } + + // Update buckets with a reference to their explicit asset + file.Assets.ForEach(eAsset => + { + var bid = new BucketIdentifier(file, eAsset.Guid); + if (!buckets.TryGetValue(bid, out AssetBucket b)) + b = GetOrCreate(buckets, file, eAsset.Guid); // some assets might not pull in any objects + b.ExplictAsset = eAsset; + }); + + // Create entries for buckets that are implicitly pulled in + int assetInFileId = 0; + + foreach (AssetBucket bucket in buckets.Values.Where(x => x.ExplictAsset == null && x.file == file)) + { + 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 }); + + if (guidToOtherData.TryGetValue(implicitAsset.AssetGuid, out var dataFromOtherAssetList)) + dataFromOtherAssetList.Add(implicitAsset); + else + guidToOtherData[implicitAsset.AssetGuid] = new List { 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++; + var bid = new BucketIdentifier(file, asset.Guid); + bool bucketFound = buckets.TryGetValue(bid, out AssetBucket bucket); + if (!bucketFound) + { + Debug.LogWarning($"Failed to find AssetBucket for asset with guid: {asset.Guid} in file: {file.Name}. This asset will not be properly represented in the build layout."); + continue; + } + + 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) + { + Type importerType = AssetDatabase.GetImporterType(asset.AssetPath); + if (importerType == typeof(ModelImporter)) + asset.MainAssetType = AssetType.Model; + else if (importerType != null) + 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); + } + } + } + + foreach (BuildLayout.File file in lookup.Files.Values) + { + if (lookup.FileToFileObjectData.TryGetValue(file, out FileObjectData fData)) + { + HashSet explicitAssetsAddedAsExternal = new HashSet(); + 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 List dataFromOtherAssetList)) + { + foreach (var dataFromOtherAsset in dataFromOtherAssetList) + { + // Add the reference to the version of the asset stored in the same bundle as this one. This is important for duplicated assets. + // If there is only one, add it no matter what, since unity_builtin_extra may not share the same bundle as the scene that references it. + if (dataFromOtherAssetList.Count == 1 || dataFromOtherAsset.File.Bundle == file.Bundle) + { + dataFromOtherAsset.ReferencingAssets.Add(asset); + asset.InternalReferencedOtherAssets.Add(dataFromOtherAsset); + break; + } + } + } + else if (buckets.TryGetValue(new BucketIdentifier(file, 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.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_BuildLayoutParameters.BuildResultHash != null) + layout.BuildResultHash = m_BuildLayoutParameters.BuildResultHash; + + using (m_Log.ScopedStep(LogLevel.Info, "Generate Basic Information")) + { + SetLayoutMetaData(layout, aaSettings); + layout.AddressablesEditorSettings = GetAddressableEditorSettings(aaSettings); + layout.AddressablesRuntimeSettings = GetAddressableRuntimeSettings(aaContext); + } + + 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 == null) + continue; + + 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_BuildLayoutParameters.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 + { + AddressableAssetGroup selectedGroup = aaContext.Settings.GetSharedBundleGroup(); + b.Name = m_BuildLayoutParameters.BundleNameRemap[b.Name]; + b.Group = lookup.GroupLookup[selectedGroup.Guid]; // should this be set? + if (lookup.GroupLookup.TryGetValue(selectedGroup.Guid, out var resolvedGroup)) + b.Group = resolvedGroup; + else + Debug.LogWarning($"Group with GUID {selectedGroup.Guid} not found in lookup. Bundle group assignment skipped for {b.Name}."); + lookup.FilenameToBundle[b.Name] = b; + + b.FileSize = GetFileSizeFromPath(Path.Combine(lookup.GroupNameToBuildPath[selectedGroup.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; + editorSettings.EnableJsonCatalog = aaSettings.EnableJsonCatalog; + + if (aaSettings.BuiltInBundleNaming == BuiltInBundleNaming.Custom) + editorSettings.ShaderBundleNaming = aaSettings.BuiltInBundleCustomNaming; + else + editorSettings.ShaderBundleNaming = aaSettings.BuiltInBundleNaming.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; +#if ENABLE_JSON_CATALOG + editorSettings.BundleLocalCatalog = aaSettings.BundleLocalCatalog; +#endif + 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; + } + + BuildLayout.AddressablesRuntimeData GetAddressableRuntimeSettings(AddressableAssetsBuildContext aaContext) + { + if (aaContext.runtimeData == null) + { + Debug.LogError("Could not get runtime data for Addressables BuildReport"); + return null; + } + + BuildLayout.AddressablesRuntimeData runtimeSettings = new BuildLayout.AddressablesRuntimeData(); + runtimeSettings.LogResourceManagerExceptions = aaContext.runtimeData.LogResourceManagerExceptions; + + runtimeSettings.CatalogLoadPaths = new List(); + foreach (ResourceLocationData catalogLocation in aaContext.runtimeData.CatalogLocations) + runtimeSettings.CatalogLoadPaths.Add(catalogLocation.InternalId); + if (m_BuildLayoutParameters.CatalogHash != null) + runtimeSettings.CatalogHash = m_BuildLayoutParameters.CatalogHash; + + 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); + layout.m_FilePath = destinationPath; + } + + 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/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs.meta b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs.meta new file mode 100644 index 00000000..71e7ff3e --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/BuildLayoutGenerationTask.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d34ce007ffbd4e74c9151022c3fb56df +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs new file mode 100644 index 00000000..b7665c15 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs @@ -0,0 +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; + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs.meta b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs.meta new file mode 100644 index 00000000..93bdf4ba --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/ExtractDataTask.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9dafe60ff4149624880b04d0cea88719 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs new file mode 100644 index 00000000..e54d01f4 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs @@ -0,0 +1,370 @@ +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.GetSharedBundleGroup(); + 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; + } + + 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 + "."); + 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/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs.meta b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs.meta new file mode 100644 index 00000000..4ed43f20 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/BuildPipelineTasks/GenerateLocationListsTask.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b19f99025db4a1e44a095aa3f1284c54 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/BuildUtility.cs b/Packages/com.unity.addressables/Editor/Build/BuildUtility.cs new file mode 100644 index 00000000..121c3753 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/BuildUtility.cs @@ -0,0 +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; + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/BuildUtility.cs.meta b/Packages/com.unity.addressables/Editor/Build/BuildUtility.cs.meta new file mode 100644 index 00000000..74a28fd1 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/BuildUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: befd95e3f3af5eb49bf7c53d00cb4d44 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/BuiltInBundleNaming.cs b/Packages/com.unity.addressables/Editor/Build/BuiltInBundleNaming.cs new file mode 100644 index 00000000..8b2eaa22 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/BuiltInBundleNaming.cs @@ -0,0 +1,27 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// Naming conventions for the built-in bundle name prefix. + /// + public enum BuiltInBundleNaming + { + /// + /// Set the built-in bundle name prefix to the hash of the project name. + /// + ProjectName, + + /// + /// Set the built-in bundle name prefix to the guid of the default group. + /// + DefaultGroupGuid, + + /// + /// Set the built-in bundle name prefix to the user specified value. + /// + Custom + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/BuiltInBundleNaming.cs.meta b/Packages/com.unity.addressables/Editor/Build/BuiltInBundleNaming.cs.meta new file mode 100644 index 00000000..b7829dc1 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/BuiltInBundleNaming.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 35ddb9e112b0424479043537f5479a5b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/CcdBuildEvents.cs b/Packages/com.unity.addressables/Editor/Build/CcdBuildEvents.cs new file mode 100644 index 00000000..4e1924f7 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/CcdBuildEvents.cs @@ -0,0 +1,1011 @@ +#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; + } + + if (settings.m_CcdManagedData.IsConfigured()) + { + // this has been configured by a previous run + 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 + var environmentId = ProfileDataSourceSettings.GetSettings().GetEnvironmentId(settings.profileSettings, settings.activeProfileId); + CcdManagement.SetEnvironmentId(environmentId); // this should be getting the value from the active profile + var ccdBucket = await CreateManagedBucket(EditorUserBuildSettings.activeBuildTarget.ToString()); + if (ccdBucket == null) { + // the bucket already exists, we shouldn't be here if refresh was called + ccdBucket = await GetExistingManagedBucket(); + } + var environmentName = ProfileDataSourceSettings.GetSettings().GetEnvironmentName(settings.profileSettings, settings.activeProfileId); + ProfileDataSourceSettings.AddGroupTypeForRemoteBucket(CloudProjectSettings.projectId, environmentId, environmentName, ccdBucket, new List()); + 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 || !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 || !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 environmentId = ProfileDataSourceSettings.GetSettings().GetEnvironmentId(settings.profileSettings, settings.activeProfileId); + // if we haven't setup an automatic group since refresh we do it here + IEnumerable groupTypes = ProfileDataSourceSettings.GetSettings().GetGroupTypesByPrefix(string.Join( + ProfileGroupType.k_PrefixSeparator.ToString(), "CCD", CloudProjectSettings.projectId, + ProfileDataSourceSettings.GetSettings().GetEnvironmentId(settings.profileSettings, settings.activeProfileId))); + // if we have setup an automatic group we load it here + groupTypes = groupTypes.Concat(ProfileDataSourceSettings.GetSettings().GetGroupTypesByPrefix(AddressableAssetSettings.CcdManagerGroupTypePrefix)); + var automaticGroupType = groupTypes.FirstOrDefault(gt => + gt.GetVariableBySuffix($"{nameof(CcdBucket)}{nameof(CcdBucket.Name)}")?.Value == EditorUserBuildSettings.activeBuildTarget.ToString() + && gt.GetVariableBySuffix($"{nameof(ProfileDataSourceSettings.Environment)}{nameof(ProfileDataSourceSettings.Environment.id)}")?.Value == environmentId); + 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) + { + return null; + } + else + { + throw; + } + } + return ccdBucket; + } + + async Task GetExistingManagedBucket() + { + var buckets = await ProfileDataSourceSettings.GetAllBucketsAsync(); + var ccdBucket = buckets.First(bucket => + bucket.Value.Name == EditorUserBuildSettings.activeBuildTarget.ToString()).Value; + 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) + { + return Progress.Start("CCD", description, Progress.Options.Managed); + } + + void RemoveProgress(int progressId) + { + Progress.Remove(progressId); + } + + void ReportProgress(int progressId, float progress, string message) + { + Progress.Report(progressId, progress, message); + } + + 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/Packages/com.unity.addressables/Editor/Build/CcdBuildEvents.cs.meta b/Packages/com.unity.addressables/Editor/Build/CcdBuildEvents.cs.meta new file mode 100644 index 00000000..74b6c3a0 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/CcdBuildEvents.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 49f93c268e0343869a5a30defb8e5d51 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/ContentUpdateScript.cs b/Packages/com.unity.addressables/Editor/Build/ContentUpdateScript.cs new file mode 100644 index 00000000..af673ca7 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/ContentUpdateScript.cs @@ -0,0 +1,1083 @@ +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. This file should be preserved with each build to ensure that an update can be created. + /// + [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. + /// + /// 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. + public 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); + } + + /// + /// Gets the path of the cache data from a selected build. + /// + /// If true, the user is allowed to browse for a specific file. + /// The settings object to use for the build. + /// 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, 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 path of the content state bin file. + /// 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.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/Packages/com.unity.addressables/Editor/Build/ContentUpdateScript.cs.meta b/Packages/com.unity.addressables/Editor/Build/ContentUpdateScript.cs.meta new file mode 100644 index 00000000..a0923c67 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/ContentUpdateScript.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 36e2ba320a6ae3e4596bd1fe59b4fe21 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilderInterfaces.cs b/Packages/com.unity.addressables/Editor/Build/DataBuilderInterfaces.cs new file mode 100644 index 00000000..f24f2b97 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilderInterfaces.cs @@ -0,0 +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(); + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilderInterfaces.cs.meta b/Packages/com.unity.addressables/Editor/Build/DataBuilderInterfaces.cs.meta new file mode 100644 index 00000000..fb3eee7c --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilderInterfaces.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 732aa8bf67ed2de438b3f2f56850c43e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders.meta b/Packages/com.unity.addressables/Editor/Build/DataBuilders.meta new file mode 100644 index 00000000..dcb5c261 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a08fbf6a899af59419df19b538f8a18e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs b/Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs new file mode 100644 index 00000000..c74a71b3 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs @@ -0,0 +1,99 @@ +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. + /// + 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. + /// + public Dictionary> GuidToCatalogLocation = null; + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs.meta b/Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs.meta new file mode 100644 index 00000000..549d1da0 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBuildContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bdd672a655042ae4fa4c3f8c8d8853a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs b/Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs new file mode 100644 index 00000000..e412ac52 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs @@ -0,0 +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); + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs.meta b/Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs.meta new file mode 100644 index 00000000..769373ff --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/AddressableAssetsBundleBuildParameters.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e4e9f0f7eaff4094990720ec2b944faf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildLayoutParameters.cs b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildLayoutParameters.cs new file mode 100644 index 00000000..1cf03562 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildLayoutParameters.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEngine.AddressableAssets.ResourceLocators; + +namespace UnityEditor.AddressableAssets.Build.DataBuilders +{ + /// + /// Object used in the build layout + /// + public interface IBuildLayoutParameters : IContextObject + { + /// + /// A mapping of internal AssetBundle names to the file name + /// + Dictionary BundleNameRemap { get; set; } + + /// + /// Calculated hash of the build layout object + /// + string BuildResultHash { get; } + + /// + /// The hash of the associated catalog + /// + string CatalogHash { get; } + } + + /// + /// Concreate implementation for objects used in the build layout + /// + public class BuildLayoutParameters : IBuildLayoutParameters + { + private Dictionary m_BundleNameRemap; + private ContentCatalogData m_contentCatalogData; + + /// + /// Create a build layout parameter + /// + /// The map of internal bundle name to file name + public BuildLayoutParameters(Dictionary bundleNameRemap) + { + m_BundleNameRemap = bundleNameRemap; + } + + /// + /// Create a build layout parameter + /// + /// The map of internal bundle name to file name + /// Content Catalog used in the build + public BuildLayoutParameters(Dictionary bundleNameRemap, ContentCatalogData contentCatalogData) + { + m_BundleNameRemap = bundleNameRemap; + m_contentCatalogData = contentCatalogData; + } + + /// + /// A map of the internal AssetBundle name to the file name + /// + public Dictionary BundleNameRemap + { + get => m_BundleNameRemap; + set => m_BundleNameRemap = value; + } + + /// + /// Calculated hash of the build layout object + /// + public string BuildResultHash + { + get => m_contentCatalogData?.BuildResultHash; + } + + /// + /// The hash of the associated catalog + /// + public string CatalogHash + { + get => m_contentCatalogData?.LocalHash; + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildLayoutParameters.cs.meta b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildLayoutParameters.cs.meta new file mode 100644 index 00000000..d5022b4d --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildLayoutParameters.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5813cc79f668462b91d624cc6fec9ae3 +timeCreated: 1713381856 \ No newline at end of file diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptBase.cs b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptBase.cs new file mode 100644 index 00000000..1fb6b6e0 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptBase.cs @@ -0,0 +1,420 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +#if UNITY_2022_2_OR_NEWER +using UnityEditor.AddressableAssets.BuildReportVisualizer; +#endif +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; +using UnityEditor.Build.Pipeline.Interfaces; +using UnityEditor.Build.Pipeline.Utilities; +using UnityEditor.Experimental; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.AddressableAssets.Initialization; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.ResourceManagement.Util; +using UnityEngine.Serialization; +using System.Reflection; + + +namespace UnityEditor.AddressableAssets.Build.DataBuilders +{ + /// + /// Base class for build script assets + /// + public class BuildScriptBase : ScriptableObject, IDataBuilder + { + /// + /// Static part of the builtin bundle filename. + /// + public const string BuiltInBundleBaseName = "_unitybuiltinassets"; + + /// + /// 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; + + var error = ErrorCheckBundleSettings(assetGroup, aaContext); + if (error != string.Empty) + { + return error; + } + + 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; + } + + + internal static string ErrorCheckBundleSettings(AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext) + { + if (!assetGroup.HasSchema()) + return string.Empty; + + var message = string.Empty; + var settings = aaContext.Settings; + var schema = assetGroup.GetSchema(); + + if(settings.UseUnityWebRequestForLocalBundles && schema.StripDownloadOptions) + { + message = "Strip Download Options is enabled, but Use UnityWebRequest for Local Bundles is also enabled. " + + "These options are mutually exclusive and cannot be used together."; + } + + 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; + } + + + /// + /// 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 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; + } + + + /// + /// Copies the content state binary file from the temp directory to its final location and registers it in the + /// file registry and build results. + /// + /// Temporary location of the content state file. + /// Destination location of the content state file. + /// The builderInput object used in the build. + /// The build data result. + public virtual void CopyAndRegisterContentState(string tempPath, string contentStatePath, AddressablesDataBuilderInput builderInput, AddressablesPlayerBuildResult addrResult) + { + 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); + } + } + + /// + /// Notifies the user about the existence of the Addressables Report + /// + protected virtual void NotifyUserAboutBuildReport() + { + // Disabled to prevent interrupting build process + bool buildReportSettingCheck = true; + 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; + } + } + + /// + /// Displays the Addressables Report window + /// + protected virtual void DisplayBuildReport() + { + if (!Application.isBatchMode && ProjectConfigData.AutoOpenAddressablesReport && ProjectConfigData.GenerateBuildLayout) + { + BuildReportWindow.ShowWindowAfterBuild(); + } + } + + /// + /// Clears content update notifications from teh groups window + /// + /// A list of groups that were built + protected virtual void ClearContentUpdateNotifications(List groups) + { + foreach (var group in groups) + ContentUpdateScript.ClearContentUpdateNotifications(group); + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptBase.cs.meta b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptBase.cs.meta new file mode 100644 index 00000000..09e133b8 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8559dec58f92398448ea2ea83fd63c3e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptFastMode.cs b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptFastMode.cs new file mode 100644 index 00000000..17cc7995 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptFastMode.cs @@ -0,0 +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; + } + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptFastMode.cs.meta b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptFastMode.cs.meta new file mode 100644 index 00000000..99c976b9 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptFastMode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 88d21199f5d473f4db36845f2318f180 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedMode.cs b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedMode.cs new file mode 100644 index 00000000..0aed1ba7 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedMode.cs @@ -0,0 +1,1618 @@ +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 UnityEditor.AddressableAssets.BuildReportVisualizer; + +using static UnityEditor.AddressableAssets.Build.ContentUpdateScript; + + +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(); + + private Dictionary> m_PrimaryKeyToDependers = null; + private Dictionary m_PrimaryKeyToLocation = null; + private Dictionary> GetPrimaryKeyToDependerLocations(List locations) + { + 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 GetPrimaryKeyToLocation(List locations) + { + 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; + } + + /// + public override bool CanBuildData() + { + return typeof(T).IsAssignableFrom(typeof(AddressablesPlayerBuildResult)); + } + + /// + protected override TResult BuildDataImplementation(AddressablesDataBuilderInput builderInput) + { + + NotifyUserAboutBuildReport(); + + TResult result = default(TResult); + m_IncludedGroupsInBuild?.Clear(); + + InitializeBuildContext(builderInput, out AddressableAssetsBuildContext aaContext); + + using (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) + return result; + + var span = DateTime.Now - aaContext.buildStartTime; + result.Duration = span.TotalSeconds; + if (string.IsNullOrEmpty(result.Error)) + { + ClearContentUpdateNotifications(m_IncludedGroupsInBuild); + } + DisplayBuildReport(); + 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(); + // force these caches to be rebuilt + m_PrimaryKeyToDependers = null; + m_PrimaryKeyToLocation = null; + 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 + LogResourceManagerExceptions = aaSettings.buildSettings.LogResourceManagerExceptions, + DisableCatalogUpdateOnStartup = aaSettings.DisableCatalogUpdateOnStartup, +#if ENABLE_JSON_CATALOG + IsLocalCatalogInBundle = aaSettings.BundleLocalCatalog, +#endif + AddressablesVersion = Addressables.Version, + 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 GetBuiltInBundleNamePrefix(AddressableAssetsBuildContext aaContext) + { + return GetBuiltInBundleNamePrefix(aaContext.Settings); + } + + internal static string GetBuiltInBundleNamePrefix(AddressableAssetSettings settings) + { + string value = ""; + switch (settings.BuiltInBundleNaming) + { + case BuiltInBundleNaming.DefaultGroupGuid: + value = settings.DefaultGroup.Guid; + break; + case BuiltInBundleNaming.ProjectName: + value = Hash128.Compute(GetProjectName()).ToString(); + break; + case BuiltInBundleNaming.Custom: + value = settings.BuiltInBundleCustomNaming; + 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 + /// Addressables context object + /// The type of IDataBuilderResult object to be produced by the build + /// The IDataBuilderResult produced by the build + 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 builtinBundleName = GetBuiltInBundleNamePrefix(aaContext) + $"{BuiltInBundleBaseName}.bundle"; + + var schema = aaContext.Settings.DefaultGroup.GetSchema(); + AddBundleProvider(schema); + + string monoScriptBundleName = GetMonoScriptBundleNamePrefix(aaContext); + if (!string.IsNullOrEmpty(monoScriptBundleName)) + monoScriptBundleName += "_monoscripts.bundle"; + var buildTasks = RuntimeDataBuildTasks(builtinBundleName, monoScriptBundleName); + buildTasks.Add(extractData); + + IBundleBuildResults results; + using (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, 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 (Log.ScopedStep(LogLevel.Info, "PostProcessBundles")) + using (var progressTracker = new UnityEditor.Build.Pipeline.Utilities.ProgressTracker()) + { + progressTracker.UpdateTask("Post Processing AssetBundles"); + + AddressableAssetGroup sharedBundleGroup = aaContext.Settings.GetSharedBundleGroup(); + foreach (var assetGroup in groups) + { + if (!aaContext.assetGroupToBundles.ContainsKey(assetGroup)) + continue; + + using (Log.ScopedStep(LogLevel.Info, assetGroup.name)) + { + PostProcessBundles(assetGroup, results, addrResult, + builderInput.Registry, aaContext, + bundleRenameMap, postCatalogUpdateCallbacks, sharedBundleGroup); + } + } + } + + using (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); + m_Linker.AddSerializedClass(resultValue.includedSerializeReferenceFQN); + } + } + } + + ContentCatalogData contentCatalog = null; +#if ENABLE_JSON_CATALOG + using (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.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 (Log.ScopedStep(LogLevel.Info, "Generating Json")) + jsonText = JsonUtility.ToJson(contentCatalog); + if (aaContext.Settings.BuildRemoteCatalog || ProjectConfigData.GenerateBuildLayout) + { + using (Log.ScopedStep(LogLevel.Info, "Hashing Catalog")) + contentHash = HashingMethods.Calculate(jsonText).ToString(); + contentCatalog.LocalHash = contentHash; + } + + CreateCatalogFiles(jsonText, builderInput, aaContext, contentHash); + } +#else + using (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.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()); + } +#endif + + + using (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 o in aaContext.Settings.InitializationObjects) + { + if(o is IObjectInitializationDataProvider io) + { + var id = io.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 (Log.ScopedStep(LogLevel.Info, "Generate Settings")) + WriteFile(settingsPath, JsonUtility.ToJson(aaContext.runtimeData), builderInput.Registry); + + if (extractData.BuildCache != null && builderInput.PreviousContentState == null) + { + using (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 (Log.ScopedStep(LogLevel.Info, "Get Assets")) + aaContext.Settings.GetAllAssets(allEntries, false, ContentUpdateScript.GroupFilterFunc); + + 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 + } + + CopyAndRegisterContentState(tempPath, contentStatePath, builderInput, addrResult); + } + } + } + + 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 (Log.ScopedStep(LogLevel.Info, "Generate Build Layout")) + { + List tasks = new List(); + var buildLayoutTask = new BuildLayoutGenerationTask(); + extractData.BuildContext.SetContextObject(new BuildLayoutParameters(bundleRenameMap, contentCatalog)); + tasks.Add(buildLayoutTask); + BuildTasksRunner.Run(tasks, extractData.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_JSON_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); + + WriteFile(m_CatalogBuildPath, data, builderInput.Registry); + WriteFile(m_CatalogBuildPath.Replace(".bin", ".hash"), HashingMethods.Calculate(data).ToString(), 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"; + dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Local] = ResourceManagerRuntimeData.kCatalogAddress + "LocalHash"; + + 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); + + var localCatalogLoadPath = "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/catalog.hash"; + var localLoadLocation = new ResourceLocationData( + new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Local] }, + localCatalogLoadPath, + typeof(TextDataProvider), typeof(string)); + locations.Add(localLoadLocation); + } + + 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, 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); + WriteFile(m_CatalogBuildPath.Replace(".json", ".hash"), HashingMethods.Calculate(jsonText).ToString(), 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, 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"; + dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Local] = ResourceManagerRuntimeData.kCatalogAddress + "LocalHash"; + + 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); + + var localCatalogLoadPath = "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/catalog.hash"; + var localLoadLocation = new ResourceLocationData( + new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Local] }, + localCatalogLoadPath, + typeof(TextDataProvider), typeof(string)); + locations.Add(localLoadLocation); + } + + 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 + /// The error string, if any. + protected virtual string ProcessGroupSchema(AddressableAssetGroupSchema schema, AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext) + { + var bundledAssetSchema = schema as BundledAssetGroupSchema; + if (bundledAssetSchema != null) + return ProcessBundledAssetSchema(bundledAssetSchema, assetGroup, aaContext); + 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; + + 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); + } + + string buildPath = schema.BuildPath.GetValue(aaContext.Settings); + if (buildPath == AddressableAssetProfileSettings.undefinedEntryValue) + return ($"Addressable group {assetGroup.Name} build path is set to undefined. Change the path to build content."); + + string loadPath = schema.LoadPath.GetValue(aaContext.Settings); + if (loadPath == AddressableAssetProfileSettings.undefinedEntryValue) + Addressables.LogWarning($"Addressable group {assetGroup.Name} load path is set to undefined. Change the path to load content."); + + 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."); + + 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 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 builtinBundleName, 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 CreateBuiltInBundle(builtinBundleName)); + 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, AddressableAssetGroup sharedBundleGroup) + { + 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 (GetPrimaryKeyToLocation(aaContext.locations).TryGetValue(builtBundleNames[i], out ContentCatalogDataEntry dataEntry)) + { + var info = buildResult.BundleInfos[builtBundleNames[i]]; + bundleResultInfo.Crc = info.Crc; + bundleResultInfo.Hash = info.Hash.ToString(); + var bundleName = Path.GetFileNameWithoutExtension(info.FileName); + if (!schema.StripDownloadOptions) + { + dataEntry.Data = 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 = bundleName, + AssetLoadMode = schema.AssetLoadMode, + BundleSize = GetFileSize(info.FileName), + ClearOtherCachedVersionsWhenLoaded = schema.AssetBundledCacheClearBehavior == BundledAssetGroupSchema.CacheClearBehavior.ClearWhenWhenNewVersionLoaded + }; + } + bundleResultInfo.InternalBundleName = bundleName; + + if (assetGroup == sharedBundleGroup && info.Dependencies.Length == 0 && !string.IsNullOrEmpty(info.FileName) && + (info.FileName.EndsWith($"{BuiltInBundleBaseName}.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]); + bundleResultInfo.FilePath = StripHashFromBundleLocation(bundleResultInfo.FilePath); + } + + bundleRenameMap.Add(builtBundleNames[i], outputBundleNames[i]); + MoveFileToDestinationWithTimestampIfDifferent(srcPath, targetPath, 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) + { + if (!assetGroup.AllowNestedFolders && schema.BundleMode == BundledAssetGroupSchema.BundlePackingMode.PackSeparately) + assetBundleName = assetBundleName.Replace('/', '_'); + + 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; + m_PrimaryKeyToLocation.Remove(originalKey); + m_PrimaryKeyToLocation.Add(newPrimaryKey, forLocation); + + if (!GetPrimaryKeyToDependerLocations(aaContext.locations).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; + } + } + } + + m_PrimaryKeyToDependers.Remove(originalKey); + m_PrimaryKeyToDependers.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_JSON_CATALOG + var catalogPath = Addressables.BuildPath + "/catalog.json"; + DeleteFile(catalogPath); +#else + var catalogPath = Addressables.BuildPath + "/catalog.bin"; + 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/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedMode.cs.meta b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedMode.cs.meta new file mode 100644 index 00000000..e21795b3 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedMode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3e2e0ffa088c91d41a086d0b8cb16bdc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs new file mode 100644 index 00000000..8405227c --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs @@ -0,0 +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; + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs.meta b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs.meta new file mode 100644 index 00000000..2367ec44 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DataBuilders/BuildScriptPackedPlayMode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad8c280d42ee0ed41a27db23b43dd2bf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/DirectoryUtility.cs b/Packages/com.unity.addressables/Editor/Build/DirectoryUtility.cs new file mode 100644 index 00000000..06210d0d --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DirectoryUtility.cs @@ -0,0 +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); + } + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/DirectoryUtility.cs.meta b/Packages/com.unity.addressables/Editor/Build/DirectoryUtility.cs.meta new file mode 100644 index 00000000..012530d3 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/DirectoryUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f8683601388ff6b4bb7d1f1a52ee6108 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/FastModeInitializationOperation.cs b/Packages/com.unity.addressables/Editor/Build/FastModeInitializationOperation.cs new file mode 100644 index 00000000..fb2d5baf --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/FastModeInitializationOperation.cs @@ -0,0 +1,120 @@ +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; + AsyncOperationHandle> groupOp; + + public FastModeInitializationOperation(AddressablesImpl addressables, AddressableAssetSettings settings) + { + m_addressables = addressables; + m_settings = settings; + m_addressables.ResourceManager.RegisterForCallbacks(); + } + + 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)); + + 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 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."); + op.Release(); + }; + } + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/FastModeInitializationOperation.cs.meta b/Packages/com.unity.addressables/Editor/Build/FastModeInitializationOperation.cs.meta new file mode 100644 index 00000000..37f48062 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/FastModeInitializationOperation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bb8458bc10d7afe4f8ad0204ab6f1fd8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/FileRegistry.cs b/Packages/com.unity.addressables/Editor/Build/FileRegistry.cs new file mode 100644 index 00000000..ec8062f7 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/FileRegistry.cs @@ -0,0 +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; + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/FileRegistry.cs.meta b/Packages/com.unity.addressables/Editor/Build/FileRegistry.cs.meta new file mode 100644 index 00000000..f60aa387 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/FileRegistry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 776e8b00aee724f69a02402947a3967f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/Layout.meta b/Packages/com.unity.addressables/Editor/Build/Layout.meta new file mode 100644 index 00000000..f4e632be --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/Layout.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a9c61c97449b2ee4f9bf60464198246d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayout.cs b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayout.cs new file mode 100644 index 00000000..8ec913ab --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayout.cs @@ -0,0 +1,1395 @@ +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] + public string LocalCatalogBuildPath; + + /// + /// The build path of the remote content catalog, if one was built + /// + [SerializeField] + public string RemoteCatalogBuildPath; + + internal string m_FilePath; + + private bool m_HeaderRead = false; + internal 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; + } + + /// + /// Open a build layout file + /// + /// Path to the BuildLayout json file on disk + /// If the basic header information should be read + /// If the full build layout should be read + /// The loaded file + 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 use wants to Disable Binary Catalogs and use Json Catalogs + /// + public bool EnableJsonCatalog; + + /// + /// 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 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 + { + /// + /// The root Asset. + /// + [SerializeReference] + public ExplicitAsset rootAsset; + + /// + /// The dependent Asset. + /// + [SerializeReference] + public 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(); + + /// + /// A list of referenced explicit assets located in other AssetBundles. + /// + [SerializeReference] + public 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] public string ObjectName; + + /// + /// Component name if AssetType is a MonoBehaviour or Component + /// + [SerializeField] public 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] public List References = new List(); + } + + /// + /// Identification of an Object within the same file + /// + [Serializable] + public class ObjectReference + { + /// + /// The index of the Asset within the file. + /// + public int AssetId; + /// + /// The indices of the Objects referenced within the same or other files. + /// + 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] + public 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/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayout.cs.meta b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayout.cs.meta new file mode 100644 index 00000000..1eca3408 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayout.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4c1f91c2b38c564e9e4ab0c5ff1ac1a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutEnums.cs b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutEnums.cs new file mode 100644 index 00000000..b8287f2f --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutEnums.cs @@ -0,0 +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 + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutEnums.cs.meta b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutEnums.cs.meta new file mode 100644 index 00000000..b81cd9ff --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutEnums.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1d660cd53240140bd9d3975354f1fae0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutHelpers.cs b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutHelpers.cs new file mode 100644 index 00000000..d1275dea --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutHelpers.cs @@ -0,0 +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; + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutHelpers.cs.meta b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutHelpers.cs.meta new file mode 100644 index 00000000..80a1760d --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutHelpers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ac62285cba7c64612b59f2c0c4124c96 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutPrinter.cs b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutPrinter.cs new file mode 100644 index 00000000..54051486 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutPrinter.cs @@ -0,0 +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)}"); + } + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutPrinter.cs.meta b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutPrinter.cs.meta new file mode 100644 index 00000000..cf55e754 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutPrinter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 859e5046b2060774898d8e87f4e78761 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutSummary.cs b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutSummary.cs new file mode 100644 index 00000000..1f7c5860 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/Layout/BuildLayoutSummary.cs @@ -0,0 +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 + /// Naming conventions for the monoscript bundle name prefix. + /// + public enum MonoScriptBundleNaming + { + /// + /// 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/Packages/com.unity.addressables/Editor/Build/MonoScriptBundleNaming.cs.meta b/Packages/com.unity.addressables/Editor/Build/MonoScriptBundleNaming.cs.meta new file mode 100644 index 00000000..ff2da755 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/MonoScriptBundleNaming.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 74f5fbf77d99c4e45bf6421e5cf0e4cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs b/Packages/com.unity.addressables/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs new file mode 100644 index 00000000..5cadb6f6 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs @@ -0,0 +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(BuildScriptBase.BuiltInBundleBaseName, 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/Packages/com.unity.addressables/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs.meta b/Packages/com.unity.addressables/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs.meta new file mode 100644 index 00000000..b711ae2b --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/RevertUnchangedAssetsToPreviousAssetState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 00f6abb2299813b4881f1f2b0f6640b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/SceneManagerState.cs b/Packages/com.unity.addressables/Editor/Build/SceneManagerState.cs new file mode 100644 index 00000000..78a741c5 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/SceneManagerState.cs @@ -0,0 +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); + } + } + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/SceneManagerState.cs.meta b/Packages/com.unity.addressables/Editor/Build/SceneManagerState.cs.meta new file mode 100644 index 00000000..26f8d19d --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/SceneManagerState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e32f647f6eec5dd458031b2ccab2880b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/Build/SharedBundleSettings.cs b/Packages/com.unity.addressables/Editor/Build/SharedBundleSettings.cs new file mode 100644 index 00000000..38bf501a --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/SharedBundleSettings.cs @@ -0,0 +1,18 @@ +namespace UnityEditor.AddressableAssets.Build +{ + /// + /// Determines the group whose settings used for shared bundles (Built In and MonoScript bundles). + /// + public enum SharedBundleSettings + { + /// + /// Shared bundles uses the settings of the Default group. + /// + DefaultGroup, + + /// + /// Shared bundles uses the settings of a specified group. + /// + CustomGroup + } +} diff --git a/Packages/com.unity.addressables/Editor/Build/SharedBundleSettings.cs.meta b/Packages/com.unity.addressables/Editor/Build/SharedBundleSettings.cs.meta new file mode 100644 index 00000000..b86ab6a1 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/Build/SharedBundleSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62d8baf33e3cd06489536583bac85ac5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer.meta new file mode 100644 index 00000000..c4682033 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 80c1dc01ab09bbb4da317a0609fd0807 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources.meta new file mode 100644 index 00000000..fbb12809 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 65f885f0de018a44e82808b2dc55c571 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons.meta new file mode 100644 index 00000000..1fa8da7a --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8bc88e3d2dd8f37489b12c8cf3f21e5d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_DarkTheme.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_DarkTheme.png new file mode 100644 index 0000000000000000000000000000000000000000..2f4b634cc5b6c7e3cb378788f30dfe1d47ec3599 GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBevzk(V@L(#+esUF8x%xb-b=G3u-s*yCUot< z(ggmy4TAd?HY`|pAj0F}YQ3NT^}=O7m`-W^UZ=ij=kX(F+OJi4Mon4L7OCmFwn2a? zUH8@DXEI4W6M_y!bj#^6t~RVVbw8nnO*k${YDwk2>k<0v)cz((_{DrOxqj-;6h)xz N44$rjF6*2UngC*qOu+yE literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_DarkTheme.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_DarkTheme.png.meta new file mode 100644 index 00000000..48742c7c --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_DarkTheme.png.meta @@ -0,0 +1,158 @@ +fileFormatVersion: 2 +guid: 3a0ce64154675d64ba2a3fdcb3e92949 +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/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_DarkTheme@2x.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_DarkTheme@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8b08333ec01c9931f51c1116021998de7d322950 GIT binary patch literal 294 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?2=RS;(M3{v?36l5$8 za(7}_cTVOdki(Mh=eH(ypRTlE`1pQ9jKQ%tbBmReeHJJg z9@BolC;#@hPb``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBey*pBV@L(#+ers`8x(k4?T@kEU}#SgK9(Td zwn@5#Wi9)pTN#&*Fw0el*LnPZZ!aR@`$FmYp3{@(*k!HFogQ&DeN(WJ$h8oyIfx5$-OMA3;ZD%+PautK8tDnm{ Hr-UW|!V^Xl literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_LightTheme.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_LightTheme.png.meta new file mode 100644 index 00000000..26b810e0 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_LightTheme.png.meta @@ -0,0 +1,158 @@ +fileFormatVersion: 2 +guid: 1d77c469320df374f98081de5d7673be +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/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_LightTheme@2x.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_LightTheme@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..aeecd272fe035c43ca7df7bd848c924f2771e6f0 GIT binary patch literal 275 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?2=RS;(M3{v?36l5$8 za(7}_cTVOdki(Mh=L-aO6!(OLH8VPI&3`Xs&g)(xrg`PdZBps^8Y`MGCp~=B51=kyP|XNA67cYRxJ$? zclzm#8(;6fb*k&*SDT^9r8HZB`#I^e_y*zf?E1v5T+q|GeR<~q*fuIk}8cmk>zOZ?o Q2D+KS)78&qol`;+03dp0-v9sr literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_LightTheme@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_LightTheme@2x.png.meta new file mode 100644 index 00000000..b56e50f0 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_LeftPanel_LightTheme@2x.png.meta @@ -0,0 +1,158 @@ +fileFormatVersion: 2 +guid: acf11b360a699d34383fb6a9d78eed8f +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/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_DarkTheme.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_DarkTheme.png new file mode 100644 index 0000000000000000000000000000000000000000..74a1a86c36ca9b02db7e297f6f065db1de25120f GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBezB*EV@L(#+ers`8x#aszVomKG<{?A<;+b8 zzR+Igz`5K;CClL8j|uIccg5u8f8TiE`USg+_vuQnvR%&X$ynQN()}k>SbOOT6%NG@ zC%-1B1e|;#lhiXI=ukxWaelYtuHW{K+?-Z>RMb7b?lF7USJIsp!T2uP%xhZO{loqxd4cfpjU{3Xv? zNd;L2RqYb-gQmM0B@ftN-Tv*7GmGMdJNzy`etg*TxY~l@(HjGui0t+EezzK`El}26 zYW}=tQqaDAUm2x~KdvnQ=v4Pv$SGpOx$I*_+Dj!&5_&wXb7mi7vykAMTY1jd;(48k zBFl@yHNXDnGnKEM{bvf}DTdSrBL~R^JTi8SzZ`U#v+a_e_g#0n*|TxmOoyJ2Va8<| i`<}IaXJl#o!C;r~@zQ?-^J1VE7(8A5T-G@yGywpwS8Qqk literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_DarkTheme@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_DarkTheme@2x.png.meta new file mode 100644 index 00000000..104c8901 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_DarkTheme@2x.png.meta @@ -0,0 +1,158 @@ +fileFormatVersion: 2 +guid: 804b883d1ff6a3941b67819909b10b73 +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/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_LightTheme.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_LightTheme.png new file mode 100644 index 0000000000000000000000000000000000000000..de10e8fd6797723958e28223dc0770b2dbce91be GIT binary patch literal 212 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBex|33V@L(#+esUF8w_|@>@~PknhiqCPD?&@g z)iz8i;Vfa0bzr~12&8V*GF3EOX$+4$e9Hb_*s`bzY6X*fcr^~bV{tetZINMl?@?=0 QEYQsip00i_>zopr0BFf(DF6Tf literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_LightTheme@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_LightTheme@2x.png.meta new file mode 100644 index 00000000..a1058025 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/Button_RightPanel_LightTheme@2x.png.meta @@ -0,0 +1,158 @@ +fileFormatVersion: 2 +guid: dc63b9e976cf2234597ec4cef20023b4 +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/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..72bfd5ca6a8b4161563e1df1853578d549703cb7 GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{tZtT$B+ufwUZC>9#-ISWi)hfKfw{XP&uWy zgL&?fIT4GMw8JVd@e1*jeSl{`|)h$Nus3$*=u-)Y4p@ap{!VhR<{h zCq78$NPIr$y|RFbaE4mKx(ziaUnw-*`#pPW+2RMKvFQ!+nt^wOpXyDJg%;sceNSUk}>VC*xG+=7agLMZdD)7Ft?w9hG+QR$VbehSF((05T zo=YvI(qXd~n7yBVzvFSIuv*Iw?WGa=4#HdG*?t%lZ2Mf%r<6S*G5rX8&*oJ-G{cwd Q0s4`_)78&qol`;+02gw0#{d8T literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon.png.meta new file mode 100644 index 00000000..fcaba107 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@2x.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..52fbbfcaa364f1de2140aa5cc78fc6dc18f2e8f1 GIT binary patch literal 416 zcmV;R0bl-!P)$_ z%kr3I*_M`7Q&rXN^|E@Of%y*4ffm#-3_SP&Ji7FK-;zPjxiyA!Xg&%6+5-UgbzQfl zP*D^ctmqw2@E;fWet~(5z)ha#cTPkKbB^U4oQrcN10bmFx^Az97@Kph&{l?4fOy$8 z5I*zR7P?q6DTLH~5F;4RK<|2R)gvDG8;DfN3s{rPf7+}2T)`}?t z@Etfy#S{UAPP?{ZiU6jrngwDKAoZSWA>17176><&xfa3;fM8R3^+7yavorwcWUX*x z2nzIt(Vh^2H<0hpu9H^CaV2e23Y`EzOX>pv%hm8e%c`Njen}7E;jKF5p5n{^0000< KMNUMnLSTZc+@zEM literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@2x.png.meta new file mode 100644 index 00000000..a8b79a5d --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@2x.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@3x.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/FileNoIcon@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..d7aaacf8f5f6260c31fd8f38743592fe6948b3e2 GIT binary patch literal 559 zcmV+~0?_@5P)NKQSil)dPS6eeq$g>Ql7oQgj1(k-26=4HL?rUt1X&RN!^R!} zAdyHsG#S^}G|lfcO(pDzEXyu^-@mQfb8cq}j|Y^nBQOu!{sIq9F5MA(!K#R^bWN za+>Q2%kYHy^8h0;qaL0xd7!~zGcnB*7@#h|+^{nyRjjH2H`{=5DXu24HC0-d;wl2J zdEQbYT0pu;SxH0*_^z-P62StY<$<{I4T@n+VL{St@2}uvUFSbp>&#WajiozRwU$39*x-P*GdLN3t{tCAj xZWG_v>lN&b=lnuLAJlNjz|OcpB9VAL{s9zveiYPx$D@jB_R5%f(QcX+4KoE^>64NFJK`7F5$gk+dpW(@)7k^k1@>l!`9&+&}p_nD+ zqpk1BZdk{)Abs$d*_k)9JHvY3g;+Z37l^HN`~-Ui`d|beK*r8u-89W>RaK8r-H=65 zJTL}-eYR33gFMfl#&PVsu4}=MVHo9YTow$5HGN(0(skCQW zVD4)qGVk@gi_=hLZ?;7$DZw6-sGm!H1?gP58CaX~jd P00000NkvXXu0mjf61}4| literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon.png.meta new file mode 100644 index 00000000..f4471431 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon@2x.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformAndroidIcon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b0458f420aa3ee7dc48022e1b31470c09aef85e9 GIT binary patch literal 860 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 literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon@2x.png.meta new file mode 100644 index 00000000..5cbbb316 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformLuminIcon@2x.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformPS4Icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ff0bc06b072bb475441fa360c815cbfe9a125d72 GIT binary patch literal 447 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 literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon.png.meta new file mode 100644 index 00000000..a240e65f --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon@2x.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0cad42128d28ef1f5f5128324dcd9f2d601104d9 GIT binary patch literal 1558 zcmV+x2I={UP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+U=KHlH4E+MgLhvmVhLL#Bwl?s_Y=k&&8&Dx@RV@ zN`6w+rVLofLcRy+nJ~V6o#6{EDw#u4^IUR{xKc@lD>@#ptDH5(bk^s^dkD`@_HZ9y zm;|j{k5;#Tg{Q!! zJX6_sZt;|YcJTEa9u3K$QddkQ%tJ^bYL=aWted2wEmsXc_@JL81~j;KCJ^N5^KNa7 zj{-f3eCvhx>fd|s#OJ#0@=nXVHA3gp0n*RKKP7&cSne6|^MJ`M)JKu$>^|qXzOJSW zMe|-!G2GNy@4)eZ&Uwo@Un9rNo#4uZV1!qGSi;W+|D=RD z+meW)-?c(syw)|+Smag>F94yrx#=nJt!(`9Vf|pKf}oxr?=%j=Mf*`O zvzxmYuZ4@?4Ahc~6)&aK%AsPSidYr?6_$e!Intp=KJ4(L9JOKjwA8faX3bk^wR4w_ zW1{D7-FxYEP#8EVMjATuu;HVOI^2oakZ(Vw?!XZ4tnN=EW>JrNoQeVipTyQz#=zU2H<9MGOejAl6BDc5mcY*nRM+>;ZR-sQ$Kn1$qT~1$qT~1$qT~ z1^WL3$;2NI_$M}e2Q-OHD-L#0amY}eEQpFYN)?M>p|llRbuhW~51KS2DK3tJYr(;v#j1mgv#t)Vf*|+< z;^yY0=prS4mlRsWc*k)M?|tvf-FJXcFEiEbm;hAGGLo^Vn8~h+U9ae-8Nd*FC1&dJ z)M6T*b4)iZ;tk@NO-tvzPaI-JNg+Nb9yjQM#E)E; zU4G+Sa9H4(AtRlfCk_#dg*KMkm=z6`c$zq@s2b%98J88#Tb$K$l{N3lUl`13D=Dti z8bJ(8h$8_JGO8${3=0w3HBw9@={)M;A9nl+a>?W>fstbY6{wILKlmT~?yZ@hnsk$b zQK0k1wm(LJu3ex}v+eI=+isiy{%7DyYxyg6VD^*rT1yKb0sY&+#dS-Q_khbCVDL$o z49SuFw1j*fct4|W$^rwoK+l@nx8^xcAAmIVYWW5@I0VKDl)dip?m&Cr{;g^D?*}K% za*3K|6#@VN00v@9M??TB04e|~oKuE600009a7bBm000&x000&x0ZCFM@Bjb+2XskI zMF-^x2?!`6d~36u0003QNkl;cbI35QRTW8GsSkplnb^$Ov?UY!Ei+2^a-IQCWYy zSikrTivocCoxm4st}!IaIX45nmrQ9Qjwb5zNcj(2N-XJJQWe;@dU(`Uc6&%nvv%y- zgpJom8<82#4j+14B9$nsB1`|ct%92Q1& zG++4jd|^&@Ye^~t8Fn_d#Z#_M@9eu|XS?E7Jm)T_zJ$ZvX%Q07*qo IM6N<$f=Xf7s{jB1 literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon@2x.png.meta new file mode 100644 index 00000000..4efc7eba --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStadiaIcon@2x.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneLinux64Icon.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneLinux64Icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e6cc4a6a993d05321ec63c362539ca3f84493549 GIT binary patch literal 674 zcmV;T0$u%yP)Px%TuDShR5%fRQcZ|bVHDN()R}P@M@pOumF#D*U~pmWW)>w1K~ak~;zp1bEm|aP zCbunSl@v<2a3SeVB!WaCHwuP7WFRgKT&QTM;5h0qjX%%MHI30^E?mBQ?|Jup-@Whf zdCQGKc?B+jkKqG&e;VUB-x!n0v{ft?WBq>rcdyqwOeT{b(6SEapWpfy6-J}cSK|eX zL?SN$3l|CKsf)&!NF?%9D&_BVI*o8R{JvJJ6;vvf0Uy#xbGD3tHyjR+(EP(@v*|@5 zQ4<~G&CSi5IN7;wB+Cf+gTa7NDwTK5X7hazj89HZ4rMagH4t83Msk*v-QVBe#sa^1 zJf3@rM8XPi-R*W8u@bISDrIy!oeZ_5%cSB)wOY-j)9JT}*WffW)z?89?{>TGY&Pqg zVmRha7z%}+A0HpL_V)HJ13EjN!0YusY&M%^j^joymunaJfBO)Z%jIwReEu^)y8Wy% zdcA(D)oT4BZDcYT(gg|a-z}`&ZokMd%(&5LB&YScIgLi+1vK|2O$;NVlZ>9pLL_$# z2Ez@7Lh(Qxn|4@CmQ{2#h2?!3FVn{1FmjCBltLrSdfx z3_eCo@)aK(9PGqmv1ikK&FAy&;14}PE|_dtEEdm}Mg*r$r}L%NYJHQ-<(@(ZQoL*z z%6tcmXR%mT)N1uMv@sDFJ%I@X0=MLH`Bj!>SMk4Bg+k#K#FyIb_D_iFbTk@?H5!cp zOZ<*K9r^u!pTpreLN7O)k!~g@quQ)abIxX^-^NYz(KP1$0q}MDn5thrTL1t607*qo IM6N<$f~ZL}`~Uy| literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneLinux64Icon.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneLinux64Icon.png.meta new file mode 100644 index 00000000..115db00c --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneLinux64Icon.png.meta @@ -0,0 +1,134 @@ +fileFormatVersion: 2 +guid: 377dcfe91a2b68742aedc28e60d58544 +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/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneLinux64Icon@2x.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneLinux64Icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0c518725793638e3dfadbd6cbf9c160837e1a4bd GIT binary patch literal 1676 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 FV1l}}=n((_ literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneOSXIcon@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneOSXIcon@2x.png.meta new file mode 100644 index 00000000..1b1bdf98 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneOSXIcon@2x.png.meta @@ -0,0 +1,134 @@ +fileFormatVersion: 2 +guid: 4d343c92fcbf4c34eae9cee8dc8107b7 +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/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..6684e2f494ca52ea26ce8110942f9d516b7ed979 GIT binary patch literal 454 zcmV;%0XhDOP)Px$fJsC_R5%fpQ_W7oKoIT^ih&kr3Gra61w%?8df>tX_y#^rpP(lmg4ggZj4|8@ zH=^|>DMd;P-)tCC*AjJ-+1Z`>=IeBJM^%0o4Gke$&_UiTet!bJ!%jNQ;QmLHxdc8-%BrV(R z_6sihuwv{AWHy^UPp8wTf{<_}NwP++MGX8KM0OOQ3jIgGVIxYAo&PyA!A?$6Rdq)y z`{gq=FilX;&xqPxhu7?{(Kv_j)K@hYt4+G1x w`ZOmPBo}&xIiX={GXWD8S(%t}$VYay2h^RuCTcVkKL7v#07*qoM6N<$g8x9hApigX literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon.png.meta new file mode 100644 index 00000000..e7e9e714 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon.png.meta @@ -0,0 +1,134 @@ +fileFormatVersion: 2 +guid: 66e8376ba5f093047bc9ab5d3d61430b +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/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon@2x.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..dbc987ae00dd86e22f0a718570ddf8b1c62d8544 GIT binary patch literal 974 zcmV;<12O!GP)Px&h)G02R9Fe^S2<4`K@|3VU)UVNMmFm#ktJ%RK+@6xQW^>*N=y6=Xi}w*sM7Nz z93dq|Bv&*cNJvpc5d}z0aPYm}eBZ`njTSJwwnLRCJ-?YZ@AzhB{bt7L__yRl_`6t# zz6;hkI4a$hKTm{#uv_c}F8L&veI3j_N-nF&0)cX3mswm2nnVA_S zkx1mgnP4y&2!%o~;M0-;$Vtp?IS~PCU>7*Dva&L{xw-jtVPU~YGBGhRk0f)kSS;=H z`QkJ-Q?uFp1zi~ICIBX5FfNm?C#e_gU0q#GY;0`gLG#&cHhp}2{PFz!{AOoo=dIuG zpM>oP-Rm^`?*w^vYAbrDOYrc$X~JRY9|r=!v6EM^juGhAF;XlG|w14H zIZFbF?(XiEGBG*P`0YgE47%NJe-?Ip&9($U8cVRhq3rz%0Q6#U zutZLfB|{5FG5`za<2U&aK&$}w-_AFnyId~I_U4VlC)CeJ0PJ+kMuYmO<;`$7+!$mt zXsic-{#_Om0%#o_9lg1_x{9E{xbZ*dQK{p!6Npuh-iwm&@-@PENiZ9v;4` zR;w&ZPL7i`O@p8-oO^x5f?CtbZnwLQ%36W$25bO;bm-UD*FP(jN(%=CYqSvo0URO_ zqyqptaBf^)Ue<6HG)_-XzrZKd>2!>`&dj~p5wNjELQ+ricsv?bkVmmG&g49VG8i+U z8&(heluD)7`}_OF2h8pr#w57{3fRwYfJKEMEK{vk3t;JkmK{unK*pQ_uuJ?4Y*jXF zhZFm0%SXo017PG90OavUZ4V8A8$1rALjk}SJ@oRMK@SDM9AuQf0APDLS!YH`EPM%o zfto_`*pj7~W%u{N!NE&hr5AA_Rg%eM7MIaEUPy6&PhwoGlz|VI(H2TF9~UE&08roB z+Ioj*AHcktQ&0953Wd=2_O=3<&tx*$>FMcoqtW<;!{`ULp@~z`)_oE&SwtEasP%mQ;YtPfbnn<&(uqW+IWuEb2b1-7Vt7BoGKZ!@ySo z;Fgi3kbzOnK4(BF0}}xI??8Z?U0z;RbGe*CaCm2A`82~8`mwdo;s4zV0N4#A8KB%2 wD@Tw56hX4zf1Hj3z#w!oAi2#IG@j>w0Cy&z+gNB%%>V!Z07*qoM6N<$f_YQH-~a#s literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon@2x.png.meta new file mode 100644 index 00000000..f7994f29 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformStandaloneWindowsIcon@2x.png.meta @@ -0,0 +1,134 @@ +fileFormatVersion: 2 +guid: 561dd5984fde32741a712b4a968324fd +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/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..b0594418bac835814d9c49196dbe79cba87308c2 GIT binary patch literal 483 zcmV<90UZ8`P)Px$ok>JNR5%gMQcX(&Q51DPsA+^*2s0SC2#g4d0*7`k=3j^lH{v?%7Xk4-Ei^bv*3Y1Eva}*%x_xn2hM@KPeB~}mwc{-gsi^amI)oK?ciH?e*oWUBe z8iN*yZH8g^;kxcSa7mKr$Z;GG>!f$IK#F0QRkd1ulx11fb-hCh!G2^I#sl=mB6}qM z5Ljp+Zg2)XiBoXcW3g|wY$z*b-Y2IeD*~2J`e7b;kz`$vO zBuV%Vk~^-GnS4H9NT<`1@B8=;Rz!pr2pz{6wA<}#P1BUgWRi@EBxAHJ>j?s0a|>*} zUO#|2-@zk#1`eQUujO+27{+R21AD#RJ&ZR8mC3=IR`JIU5a*2l&?;Ic*TR#(fD!PY Z;2UQNw>BMiiZ%cM002ovPDHLkV1lck(-!~$ literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon.png.meta new file mode 100644 index 00000000..77536e19 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon@2x.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformSwitchIcon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4bbeab1610e5588fe803eb79ab01e6797ff999eb GIT binary patch literal 876 zcmV-y1C#uTP)Px&CP_p=R9Fe^R?mx4Q54q6tmy}ZLy%K6vncuj6SN83L_~`=Nt!~`#$Gg=lOiAQ%Kwd z{&5013DB3EZD0$aeG}LQ=&xHCgk;umIJ{b^RMr}e#?P*Xz-O6In(FoXdbwQw6p2JU zuq^`Q5{Y9tUib!lTWda_e+A;Ul3YE8-!($5m*-NUPU* zlBDfSCKGkL-S?nh0j>jgL_k@$BIX)TNv_0c_>y~~u;Kk zhUkyTIkX9tf%=}R!Dcd<^tD>8KSU~(dI5V&3raDIP9fTDX-}? zLCFeS#vAp7V}Lp#YWu(@wA=0X;dqX4xm@-!JUu==6%c`SJ=IO=NDiIG22^(YzOo zN}!Enm%HBJ@p#VT!P8MBLiJRFzw!+%;FmLWF&UM>7LMO=Cjhp`3{3T3 z04|;>yrAexfTe20HSc$L?${ zV6WNt;{dC&=a(5F86&xHs2w5*^6?uE2j`lzk&&mSDU90000Px$>PbXFR5%f1WWWTBKp|!zW(8s_7}M5M(&W5-@->pnRssj~^$WIdewZ$jHdz#EBF8b#-;+BqSvKa&vQ& zwY9aMaB*?*78Dd*2de)K#6OV@0GZ78?Af!~moHzw^YZ0Oc0NA7=gP{;Rw^ng-YhIE zY#{vq|Nnmv9z3}E`t|E8=H})ZP>UIuj~zSabN1}n$sa#{eERL%w@*NYcmdFW=RnO8 zFatR8s>UMu>eZ_kK+Te%Kmh?{uRuhAR#9yaQoeBdw-;ST3Ut2&xKm~{;nV6Vh@)%|S zy$G`OKTN@2V6t2X6xayFpd`)Y?(WW>mX@Y3E-r2iG*l0WH3S6(6@iv;K6&!w#?`A= yw*%FE!kU195-P!|6K#J>R8-#OHVV*jE50000Px(SV=@dR9FecS6xU{TNG|4XKEUm#=l0yq_oMKW|qP22Tiy^5A|vi6h6d#xm=Wx zF4qPE5kye%A$pNaA1*~HqG2@Zi`VoaQS*B7r^xXK9Y&qhoOE=U$?5wBj~vg8b{wr1 zd~^2RXYIAVz4qGstl6{YCyQbm{*}-bzR@$ zUjULKc1`G<&U9sEWf!KVrd~Lm&Iz~M{n>7}_tw_d-o?A)fC10~)RnU+sL2zqT-(~( zdeh_aI0gp?pI1~=nELzs&0eq919)dloWvEu3a z`uh7hIXPKNOH1R3L}y)HovEm(=+?r*f`vqehlkB@lmsvuk!#OGc#;&iP9VlSk|k8s zV6}hG&dzqCeQ|DX?!Td-p(kjc0^)&V)z#H^91e#SI^#`EO^=F;i+^uxYb&!@EUz&4 zNmf?YW#}1!!$1^p0N9cQ!$k##P;a$bpY`k&p_uZe?U-I>NcTo?Oa*59!O6+VO02}9 z)oS(0$;szI$PybHo1oY0X=uxp_&kVyuw4_FcLhV^08h_`_{7FyN#?hFK62&|-!Et5hoP)%TJOQ5T1hFZO+B z=YES46W~i}-*3Wh4+QOSadFW;Ha7MKNAB5fkz(e@N{WZb`S_!#7Bb03~(?ZwZ_{Fx1CF&PRU9SFcv9-GzmP4;mU8D)43O!?nBuqgv#|({<$? zG&W5_eD|wh_X2Pl;kV(ta2suYe);7~WEkW~&`FqMh z0Z2S(k(C2d>)gxf>FM{lw%>Jib&VAi6qHJJ0`&vsfLL$SEszslIXZ#1An2P=%zP(p zDFIftKUBm7d}TKFsg+glk76Od30coOQ7~M`Gc-3h_ef@D=E=CYxD%0)k;lWr!V+{k z-C?Ct8Fbe3;(~4A|ATLh;#0r@MucD~P0$&^idF?8`}6bj6H`-DlTnua5)lz`3?)_q z$~9KMQd=0>C^nm|GbSeH21acF|IBPTi3SN061N#O!bghFjEsyhl6whK=CP_lQow6t`TmzVcLe-2mzeEIfG)=(6SKt%i$qDE5d(L$Sj>bU`~Rsj3! w$-Z3zn7gUamN;61ZQ=i-@JDu213%@(R|Hd!WW63PQ2+n{07*qoM6N<$f*Z9qkN^Mx literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon@2x.png.meta new file mode 100644 index 00000000..72f6fb41 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWSAPlayerIcon@2x.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..9f29f81d7e7a9248909a1c2633f54fe7ba95ee86 GIT binary patch literal 496 zcmVPx$s!2paR5%fZQaw+?P!y%bgb#@!FbEMH9Gwit$-&>??#$#La3|qEFgmykCa#VU z15<~#3nT^;VLDgb+GbyId}xP9~F&bUK|K3(dY-5V4{2eVZLn&rSO$h;3Smju~9b1dWtUm$Za;|T#EUcTve;pbDH2%y&!kZIMhTPFsG1gHk+4dUt&I=dzNK&NX9Bp4GMU< zHlWpNwIe0`ZKVd4(G89{^?E(GSS&u_OOHIy6RA{ck2h~P9Ci%DxNEoDxAl76fPx(^hrcPR9FeEm(NdJRTRf(1c3?+7R5qoT^L)T{zwQ!HxdzJ!lGfvMiyO|vd}*O zN!-brkf;eRh?;IpO-R^C0)z!2q!@k#0t(@$P{2W?FvG8rnZfVp_1($LoA=0IJ;`_O zednHg?)RR1&V6tEK6mj;{hSSBfetY({d0bjB>9o^D4d6o^%)3>p)F#+gHLizdm>YngqicAOUHa!x+AJCJ%B2<{b-v3PFK{v^J$SA;!5;;2;om}HdC2q9m*{>NGUGM@ z&YsPsiIad8flw&4qlvam4V$O3}b z$OFoX+BQkZ9Ka&@JI~9@GxL1AySotZjDVAXY%OO|&MpuL7)K=5KLYo^ zvkGv|oqxc%-jMMm;y%4S4FL_Oix+_yx1k7JXNnSUIDKlWMxnncO{lJ}u1I|o9pCiy zG{@l?0cQ^2)e5HwByPj1s;ay4`L^&r1|CARvMVbq`3SK@#AE&a{TG&@8v!PB8*=$r z(%9Hopbk4pB-hiClwWeduMZLK2}|@II8+Bcn{pL50vJd2NtGZ_QBhGQ9gad85)!KR^GYo_XKiMe$35dP(-u;}U~sahr>9wd3I(@h_g>weK+?UEo11&PtE=nN znVFfN^Jy7X=!Pwx3~Ap`uh5JHJ4l|64*@QVp2b2fi;sM!sS9KzTVN%@yXQG z)B{z?x?VbuMeHF7TU=axN8>E|l8`U(abm7*b=@TsX4pUmaF#gczXM;o2<6A0722p^ w%I?DYmz^b<5HPm1*e4T0XYP5^qRUwR1wY5LQT2o(ZU6uP07*qoM6N<$f`s#gIsgCw literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon@2x.png.meta new file mode 100644 index 00000000..5487bb5a --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformWebGLIcon@2x.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..2624d6bab7bec5f04c03f2a0f24f99fd36e83113 GIT binary patch literal 502 zcmVPx$ut`KgR5%gMQoTz8aTwOlint-@LnH~VrHmGZ#_&IIa*zf$2XSZuepxJk4eNpgmSJB7 zm%uSN0Cms+e+31!dA;7lYPBl#`+XHuI-Sl#u~^)Nj{?rXY+&HoDijJap66Z3Wb&ff zY}R_c-YdkH*=%;NR4RpVhq9XsHjzm1hGC3Aqup-bg~MT|!{Ok{!4n*D{i-&v0AMbj^m=ZlLM(IGw^h~-4A*lso&&s zIWOver#?g?kyt*TzaNc8hNfw6P_4}%RF>MC^WKk4jcDwzEW!e3SfBJC(9*<{R z5QK9WX)or2X*3$qNyp6z7-UPQ(^pWf&sCa?494bbwOS(T{X`SBTCMh!N~O+lX9J{t snPSl@Q)w$8jhW80&O?w!N9TWpFXnOmd{z@_cmMzZ07*qoM6N<$f}tbccmMzZ literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon.png.meta new file mode 100644 index 00000000..e95dfc88 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon@2x.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e9d6fbfafc3a95084d674f416a00f457bc85b61e GIT binary patch literal 1189 zcmV;W1X}xvP)Px(Ur9tkR9Fe^R&7X|R}{7%YZp7yH0xp&zZzofw)RIy?LLH0^ zOWU;+QGZm*VEZ`+8>2?lNSI7P1hXjZ#&i|Is_|n^TtMR_YVg}cjUS19o;I(0jizq` z{WlLh-22{h?m6e4d(OFUSl9vm-y?7+!~jtKFd!bOV%rC=Xym#ih2j7W9|2@QIB*;| z3XnX&2C(J>=XB+7$?n z2GAf1U$3vPJ4JqYM@B||Ehs4Xz$e2fL;+_2IY383a)QDtKi4WWU|=I%uE`NPEJnN4h#%D*xcM)5$~z0swxNnEWl_os*=Rh z%hYPM*6DQG#ma>F*4CE0va<4H$T7Spii(Qj5eb{X7mrIzOAeJvl?u7n0ikLz4NMG` zqPe;Gj#!Z}_jb-0c{P>w^{+1Zz|7T@09exEY_G(0@~82q<^6M!TggG4;a zZ9=SwigCv#@Gk0fy7y;hX8soV2=jPeUfvb()G%iBcVcmIaSA+Ek^+z zPEAdXAmo>ml9JM6(SJkICm=dG!!sk(@W2rU}ZEyAu-=PlR><5l;3*Mn;}5E-wBEM%@D6?RGn%GX+peT897~h?||A9i{?w zw{5f8{1euaySux85tIfR`}_NikUa<4AGwzV$E;X;2Vg&tB$mpVv9U2T?-GvK6$-_b z+S=OkKt}!6y+)()D~(2T5oJ6>9cX61L+6_SAF*AuUt{3Yx`v+Kh!cdhw6qw~)6-Q* zvb(!>2L3pdo10snn3#CVVzC(DKv-8-ml@(NU@P#p|2S+!uL4nayZuij)q8mT0^Ymd z>32S@R%>fYN=h0M(gIx?fE5sQJEmZGR#w(qCX?yjj@A$-27}?V($Z4ieFVVV+Arc* z-b;)EolqjFz6;UrjyU?px6r|pGp~X+4%uf!C-{KG_4M>qLhIfZw_|G0#EbiXfW6T` zQ0*6T`x2wT_8E)E=L=-@fk literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon@2x.png.meta new file mode 100644 index 00000000..e7f38427 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformXboxOneIcon@2x.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..8178caad8ee21ea078ba7d601a56c6a09bcba188 GIT binary patch literal 522 zcmV+l0`>igP)Px$#7RU!R5%gMQaeb3Q54qyQI;VTWfDz6vx9p;ivu5 znI93vC+v3njKkrWB_Ch`(iK*#bhr_Jy=K&C+ExJILyL*{F6C5Z!@qy!$1XT8;G-30=Hb?CHD7w~|bN|1NE zUB+g!X*!+GBX}41v>vp3wOaj>NF)w)I-RZ2Xk6rSIhS6qA6_&;w+t${!O7tU`Dly! zUDRr|q$>bbDwR6SX0u1|$NEEnBWt(YA}V=`L?UaT{TW~$tCA#%Mx$}d@AsRaQ`tQX z^p59wN+_oxNDRZgVSNn-gZpN)`M6XnNu+Ze$D{APSSPx)I7vi7R9Fe^Ra;2pRUDqp%<(q5qwDUNsk^$igsZE0DKDEMX<)UpP!Ewvw6Q9Y z5E2rLkPqVJ!3Pz`%R`bE3`AW5FQ9qB0>ko>hKh+AIyj?i-gU+q`@XaOWpFN30WHK3Wc(9?NAu}#6?hZj2Yd=DFbf3XC1x-{1eUt*tHlHio;q z`>Um;rSGq;t@R*sx`Kj&H^~L)q!_%E*3)BNEIdKz?ih{6t*NQ0I;`CQlmHJBly6K< zPHMpU8{F41S9N!HKZNIdnVFf%m|q3RWeUj;f^kEutE6qv6@NkAsr)z-h0Z26=dkGU2@^#wS*!T`)TIYXsbfg~`7xACVDzKIeAY^ zOw3^U2;h^m9$Y&fA0MA~baYfEBqX>Zf{$U$25P6VtE=my@bK_Ja9E@YfQFm^)Mo^w z*C3wFbw;4FvQmwWYt_}&YR+R~V!|<}7s6V6Ee8#E2@4Ag1=U%)Y-P+pvnO3X)Ehs4H-I9`$!IhO2O?rB|KX~jF=ejwujDSy6RFv?ls;Y|b zoZ+(-0j?>^%ggUET1Ww-C54*dW-+taSVMstjpk!K&%f{remGkbb!AJjX>4q42gRhr zGp14+cwVuPrNK3MWMpJG3vXm(Wn~W`O3#+< zmg!{C8J3rq`C1$T0|Q0TLl(n21q_>8Qc_YV3Q3QC(0tYl*zFi%D)(j&K+A1n)#HDH zk@5pqv$M1FM?^#f=L|i$^j0)3@Eftum!$%jCNXGD0P~1Seh)GaaZ}mR(eVii@&L_c zth2K-7h!xWD=X_RWvu;zy~FnQ_D{iOloYYCu{UwS@4zg&;+NnjvNrI#K12aN=Buc$ zufGQ_ojgw~i{UDiJ!x)kPKL~IGc`2KtEi|b1%=a%{e2qAK^eWh8$JGQa2OeKMR!CE z+?tu0sYD}Nf65m8gZ1_GzKV*9RPY!LIw)QNe`pC65X_a-c%(h1$koHc!#N`(gJG35 zH8ttbv<@L20Oa!tGT+oi;5UdN)hgyi(E@S_pJFmBk`oKq@Vl?4awMx9FmN_$Qe7=9szp<{<{eL10@7k+DxT4=l}o! M07*qoM6N<$g8KxdLI3~& literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon@2x.png.meta new file mode 100644 index 00000000..16a8c3da --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformiOSIcon@2x.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..2f47560c05b751a34f02e84c49a898ad07d18e6c GIT binary patch literal 465 zcmV;?0WSWDP)Px$i%CR5R5%gsP`^t8aTLFw{vd1aeN6g2juh+X01Yr|$f2~&A1!Zso zXEK@S*=+U+UObCLB3_7(P1AhK<#Ml3x3OnD9>2J*>uWZfrwqfmqtQqMpT@sa9LM3< zj;3jk<#PGZaU33KDvGj&Wn?fIj9QlUo=T-|lF8()D2fvJs|j3a{%p6~`C;eEEb1vMyJ!M36J{0TLBlwRjbu)P^M5QpyKv%I!~+B z5{t!R7-HN75Bu4u*Xui21LE0Vkc22H;6>{m#_Kuh`?LBDdIgi=2_HfR00000NkvXX Hu0mjfBevIC literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon.png.meta new file mode 100644 index 00000000..14f2e5a6 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon@2x.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ce45fa31fc2ec54c4196cf820e472ac177b9f4e3 GIT binary patch literal 1169 zcmV;C1aA9@P)Px(OG!jQR9Fe^R9#5ZYZ%|0Tif(_a&B#|%!K?{7o#CU5~H;46b`xyZPec%c#O5z;MFECM5%tTQ9Kuw+aEq&OwwBPT~{~ZR_Z5Qo@AJ6kX z&+|U-^Yy+8MRF|d34|g9zjKMp zH5Q8{y1TpkvQDQvC=4PZB2?||?e|?S*IUSVfx4@!>r`@ba&90H_(VIkTCE=(9BjzW z&VGX}?^5gm%u7p4UeI_TT9z?tQ9f}oWl=VpEq--%)r-sWu{Qy6fDuj;7Zw)k`}_MZ zVsB|}Z9OwLH+NI7*V8X;;t~=Ptc#0_^=)l!S=egwQzMdvjd&3=Qy za1_~gK>ryKJ!i?kP&P0y@Tjt~@-M&NAIQnc*$0_uHCROe0r=3uTJjX|5(}bz3Tg%Z z1WfDe>(4=r0QH0knZ3x$%1WP|oxLyXnEB4dgtTtAJ7s!$`d)Ey@o}{3cMpA?C4d3m`3JTvBnI+W=M zs&ZSF8PT)4va&J_0V%bITsx4y@0W%rsfzDY3S_ibjk8v z1E6CAB7R`E+mq7L(hh-t2$`8cSsP`ZSx9pP%9p}k$6&(G4h;=m1y6fXZtB>|7^~HK z5JAvKEQQkA-rg2ZjSho=9|QTSwzf8R3k!q#A7p&DN|baEFXbfW;eYJ8_<8X>1J@zw zzwsAb$0fHgux`ls2e7?t(H5!`#C>eFv=~Gzvnnhsw1MZ4unk(1$z++IpMQ)4j}j9T z`IecnHa$I^|G+c8bL=_gY)9xH=jS#QV0OtB00000NkvXXu0mjfS9TKe literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon@2x.png.meta new file mode 100644 index 00000000..0dc88127 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/PlatformtvOSIcon@2x.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward.png new file mode 100644 index 0000000000000000000000000000000000000000..9c8d3cd46f9d4913cf826ee075df3868be4cb8ac GIT binary patch literal 260 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{!C97$B+ufyZvW*TNDIZTXkx8$iA8P({r1! zZld-LA+xXrvKj0Z4OUxN-U}3%R4K2Jsa2me^ZjGrX?OL#Ryt)=ZtJbR$^6No7vx60U1z_kK&=`V-7r9p}mPqt=OIYR|^=sf-7v zZvEz|nd|h~y+xK$&+>U~iu#QNM(yM?zd81KrhN*wKBDsJZ8gx544$rjF6*2UngG5% BS`YvL literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward.png.meta new file mode 100644 index 00000000..756621ed --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward@2x.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..450e882f0f3aeb4bb852bbd6107fd9c04d4d723e GIT binary patch literal 378 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?2=RS;(M3{v?36l5$8 za(7}_cTVOdki(Mh=@^*1Hd%tewtzGUwm<`7;>=IR02qT)9x^H21Vp z5!dG?zVZq^y^VEWBDdu34)(gLaD=B~%_EC{A)%!#iaR)aRvPj?oy}(6Xvn$L(R$I= zxCUiAHnwjWPg;|2HZcpabu4-R+j?2yaTB3)&YH~3(LT<_mp()~35Tg`&pjYv6`7kg z>r#Vgu+#!Ujo`~NEeEqRUhJQkdh_bC_$v%u_Pf_DKAN3#-$QamV9oUBm5e@n${AYo zEnY9}ws<)Cfb>!Rb%)NeWt`k_C*TJQQvt8Ye$~~E9E%xe8BXJUzJ;lgpbP0l+XkKsq2n& literal 0 HcmV?d00001 diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward@2x.png.meta b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward@2x.png.meta new file mode 100644 index 00000000..20209231 --- /dev/null +++ b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_History.Forward@2x.png.meta @@ -0,0 +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: diff --git a/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_icon dropdown@2x.png b/Packages/com.unity.addressables/Editor/BuildReportVisualizer/BuildReport Resources/Icons/d_icon dropdown@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..eff2c83038a37ecfd46b7d58412d0442b65ddafd GIT binary patch literal 282 zcmV+#0pST5X5d+AR}Z1n!p5UQbbCZ9kNRHh?FfbjYnXF^pP8!J7OYa9+0R~*pk72e|PVH zXIWZl0%-zD8bMvxo%deMNqk~TDPL8Uj`I^Bknb^ZEk*%RBi<6X*XZH_)AO2f$UkxW z3yO3xf3Aa0Ykh^Fi3M>?PT)?=$rU>oOsus#=Uju1_5(Kl!@SM&{7@9dYmAT2Vh00( zLYN#8O9p*z$(%lm1xP5%vPF>-_M0&m&%~JfBJ 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