att correção código

This commit is contained in:
Thereckless17 2026-09-21 08:06:10 -03:00
parent fa6b3ce3a2
commit 49e285b681
3032 changed files with 226867 additions and 28 deletions

View File

@ -121,3 +121,297 @@ NavMeshSettings:
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1001 &1322168687
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 1183153197497839751, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197497839751, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197497839751, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197497839751, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197528105060, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197528105060, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197528105060, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197528105060, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197541656595, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197541656595, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197541656595, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197589611976, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197589611976, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197589611976, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197589611976, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197656342392, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197656342392, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197656342392, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197656342392, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197937844454, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_LocalPosition.x
value: 34.40068
objectReference: {fileID: 0}
- target: {fileID: 1183153197937844454, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_LocalPosition.y
value: 198.20085
objectReference: {fileID: 0}
- target: {fileID: 1183153197937844454, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_LocalPosition.z
value: -225.97066
objectReference: {fileID: 0}
- target: {fileID: 1183153197937844454, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197937844454, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197937844454, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197937844454, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1183153197937844454, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197937844454, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197937844454, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197937844454, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153197937844455, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_Name
value: Game
objectReference: {fileID: 0}
- target: {fileID: 1183153198409181204, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198409181204, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198409181204, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198409181204, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198409181204, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198409181204, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198447002943, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198447002943, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198447002943, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198447002943, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198520103669, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198524887307, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198524887307, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198524887307, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198524887307, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153198524887307, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153199112226573, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153199112226573, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153199112226573, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153199112226573, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153199112226573, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153199112226573, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153199266324015, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153199266324015, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153199266324015, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1183153199266324015, guid: 1f51c230298a11a439665164fec7692c,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 1f51c230298a11a439665164fec7692c, type: 3}

BIN
Library/AnnotationManager Normal file

Binary file not shown.

Binary file not shown.

BIN
Library/ArtifactDB-lock Normal file

Binary file not shown.

View File

BIN
Library/BuildSettings.asset Normal file

Binary file not shown.

View File

@ -115,7 +115,7 @@ MonoBehaviour:
m_MinSize: {x: 679, y: 492}
m_MaxSize: {x: 14002, y: 14042}
vertical: 0
controlID: 58
controlID: 95
--- !u!114 &6
MonoBehaviour:
m_ObjectHideFlags: 52
@ -140,7 +140,7 @@ MonoBehaviour:
m_MinSize: {x: 403, y: 492}
m_MaxSize: {x: 10001, y: 14042}
vertical: 1
controlID: 120
controlID: 96
--- !u!114 &7
MonoBehaviour:
m_ObjectHideFlags: 52
@ -165,7 +165,7 @@ MonoBehaviour:
m_MinSize: {x: 403, y: 221}
m_MaxSize: {x: 8003, y: 4021}
vertical: 0
controlID: 121
controlID: 97
--- !u!114 &8
MonoBehaviour:
m_ObjectHideFlags: 52
@ -211,8 +211,8 @@ MonoBehaviour:
y: 0
width: 646
height: 348
m_MinSize: {x: 200, y: 200}
m_MaxSize: {x: 4000, y: 4000}
m_MinSize: {x: 202, y: 221}
m_MaxSize: {x: 4002, y: 4021}
m_ActualView: {fileID: 12}
m_Panes:
- {fileID: 14}
@ -267,8 +267,8 @@ MonoBehaviour:
y: 0
width: 434
height: 627
m_MinSize: {x: 275, y: 50}
m_MaxSize: {x: 4000, y: 4000}
m_MinSize: {x: 276, y: 71}
m_MaxSize: {x: 4001, y: 4021}
m_ActualView: {fileID: 19}
m_Panes:
- {fileID: 19}
@ -392,9 +392,9 @@ MonoBehaviour:
m_SceneHierarchy:
m_TreeViewState:
scrollPos: {x: 0, y: 0}
m_SelectedIDs: 5a890000
m_LastClickedID: 0
m_ExpandedIDs: d8ebfffff2ebffff02ecffff10ecffffb2eeffffb8eeffffcaeeffff34f1fffff4f3fffff4f8ffffd4faffffe0faffff70fbffff
m_SelectedIDs: a8f8ffff
m_LastClickedID: -1880
m_ExpandedIDs: a8f8ffffb6f8ffffc4f8ffffd4f9ffffdef9ffff00faffff10faffffc4faffff
m_RenameOverlay:
m_UserAcceptedRename: 0
m_Name:
@ -456,7 +456,7 @@ MonoBehaviour:
m_Position:
m_Target: {x: 0, y: 0, z: 0}
speed: 2
m_Value: {x: 272, y: 153, z: 0}
m_Value: {x: 0, y: 0, z: 0}
m_RenderMode: 0
m_CameraMode:
drawMode: 0
@ -508,7 +508,7 @@ MonoBehaviour:
m_Size:
m_Target: 10
speed: 2
m_Value: 1029.8591
m_Value: 22
m_Ortho:
m_Target: 1
speed: 2
@ -572,34 +572,34 @@ MonoBehaviour:
m_SkipHidden: 0
m_SearchArea: 1
m_Folders:
- Assets/RemoteResources/Games/M5/L8/002
- Assets/RemoteResources/Games/M5/L8/001
m_ViewMode: 1
m_StartGridSize: 58
m_LastFolders:
- Assets/RemoteResources/Games/M5/L8/002
- Assets/RemoteResources/Games/M5/L8/001
m_LastFoldersGridSize: 58
m_LastProjectPath: E:\GIT\ZOE\ZoeAppClass
m_LockTracker:
m_IsLocked: 0
m_FolderTreeState:
scrollPos: {x: 0, y: 2280}
m_SelectedIDs: 4e4c0000
m_LastClickedID: 19534
m_ExpandedIDs: 00000000ec420000a643000036470000384700003a4700001249000014490000204c00004a4c000000ca9a3b
scrollPos: {x: 0, y: 1922}
m_SelectedIDs: e04e0000
m_LastClickedID: 20192
m_ExpandedIDs: 00000000804500008245000086450000884500008a4500008c4500008e4500009045000000ca9a3b
m_RenameOverlay:
m_UserAcceptedRename: 0
m_Name:
m_OriginalName:
m_Name: TESTE
m_OriginalName: TESTE
m_EditFieldRect:
serializedVersion: 2
x: 0
y: 0
width: 0
height: 0
m_UserData: 0
m_UserData: 20196
m_IsWaitingForDelay: 0
m_IsRenaming: 0
m_OriginalEventType: 11
m_OriginalEventType: 0
m_IsRenamingFilename: 1
m_ClientGUIView: {fileID: 10}
m_SearchString:
@ -613,7 +613,7 @@ MonoBehaviour:
scrollPos: {x: 0, y: 0}
m_SelectedIDs:
m_LastClickedID: 0
m_ExpandedIDs: 00000000ec420000
m_ExpandedIDs: 0000000080450000824500008445000086450000884500008a4500008c4500008e45000090450000
m_RenameOverlay:
m_UserAcceptedRename: 0
m_Name:

Binary file not shown.

View File

@ -0,0 +1,19 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!162 &1
EditorUserSettings:
m_ObjectHideFlags: 0
serializedVersion: 4
m_ConfigSettings:
vcSharedLogLevel:
value: 0d5e400f0650
flags: 0
m_VCAutomaticAdd: 1
m_VCDebugCom: 0
m_VCDebugCmd: 0
m_VCDebugOut: 0
m_SemanticMergeMode: 2
m_VCShowFailedCheckout: 1
m_VCOverwriteFailedCheckoutAssets: 1
m_VCOverlayIcons: 1
m_VCAllowAsyncUpdate: 0

View File

@ -0,0 +1,2 @@
unityRebuildLibraryVersion: 11
unityForwardCompatibleVersion: 40

BIN
Library/MonoManager.asset Normal file

Binary file not shown.

View File

@ -0,0 +1,389 @@
# Changelog
All notable changes to this package will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [1.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
- Fixed sprite sheet loading syntax LoadAssetAsync<Sprite[]>("sprite").
- Note that this syntax requires an engine fix that is in 2019.3.0a10 and will be backported to 2019.2 and 2018.4.
## [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*<Type>(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<Sprite>("trees.trees_0").
- Known issue: loading IList<Sprite> from a Texture2D or IList<AnimationClip> 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<object> 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<long> 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

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6f6c277bb5d2a164e8c95a7f0754c0f6
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,97 @@
# Addressables Analyze
Analyze is a tool that gathers information on your Projects' Addressables layout. In some cases, Analyze may take appropriate actions to clean up the state of your Project. In others, Analyze is purely an informational tool that allows you to make more informed decisions about your Addressables layout.
## Using Analyze
In the Editor, open the **Addressables window** (**Window** > **Asset Management** > **Addressable Assets**), then click the **Analyze** button in the menu to open the **Analyze window**.
The Analyze window displays a list of Analyze rules, along with the following operations:
* Analyze Secelcted Rules
* Fix Selected Rules
* Clear Selected Rules
### The analyze operation
The analyze operation is the information-gathering step of the rule. Running this action on a rule or set of rules gathers data about the build, dependency maps, and more. Each rule is responsible for gathering the desired data and reporting it back as a list of `AnalyzeResult` objects.
No action should be taken to modify any data or the state of the Project during the analyze step. Based on the data gathered in this step, the [fix](#the-fix-operation) operation may be the appropriate course of action. Some rules, however, only contain an analyze step, as no reasonably appropriate and universal action can be taken based on the information gathered. [_Check Scene to Addressable Duplicate Dependencies_](#check-scene-to-addressable-duplicate-dependencies) and [_Check Resources to Addressable Duplicate Dependencies_](#check-resources-to-addressable-duplicate-dependencies) are examples of such rules.
Rules that are purely informational and contain no fix operation are categorized as **Unfixable Rules**. Those that do have a fix operation are categorized as **Fixable Rules**.
### The fix operation
For **Fixable Rules**, you may choose to run the fix operation. This uses data gathered during the analyze step to perform any necessary modifications and resolve the issues.
[_Check Duplicate Group Dependencies_](#check-duplicate-group-dependencies) is an example of a fixable rule, because there is a reasonably appropriate action that can be taken to resolve the issues detected in the analysis.
### The clear step
This operation will remove any data gathered by the analysis and update the `TreeView` accordingly.
## Provided Analyze rules
### Fixable rules
#### Check Duplicate Group Dependencies
This rule checks for potentially duplicated assets, by scanning all groups with `BundledAssetGroupSchemas` and projecting the asset group layout. This essentially requires triggering a full build, so this check is time-consuming and performance-intensive.
**Issues**: Duplicated assets result from assets in different groups sharing dependencies, for example two Prefabs that share a material existing in different Addressable groups. That material (and any of its dependencies) would be pulled into both groups containing the Prefabs. To prevent this, the material must be marked as Addressable, either with one of the Prefabs, or in its own space, thereby putting the material and its dependencies in a separate Addressable group.
**Resolution**: If this check discovers any issues, running the fix operation on this rule creates a new Addressable group in which to move all dependent assets.
**Exceptions**: If you have an asset containing multiple objects, it is possible for different groups to only pull in portions of the asset, and not actually duplicate. An FBX with many meshes is an example of this. If one mesh is in "GroupA" and another is in "GroupB", this rule will think that the FBX is shared, and extract it into its own group if you run the fix operation. In this edge case, running the fix operation is actually harmful, as neither group would have the full FBX asset.
Also note that duplicate assets may not always be an issue. If assets will never be requested by the same set of users (for example, region-specific assets), then duplicate dependencies may be desired, or at least inconsequential. Each Project is unique, so fixing duplicate asset dependencies should be evaluated on a case by case basis.
### Unfixable rules
#### Check Resources to Addressable Duplicate Dependencies
This rule detects if any assets or asset dependencies are duplicated between built Addressable data and assets residing in a `Resources` folder.
**Issues**: These duplications mean that data will be included in both the application build and the Addressables build.
**Resolution**: This rule is unfixable, because no appropriate action exists. It is purely informational, alerting you to the redundancy. You must decide how to proceed and what action to take, if any. One example of a possible manual fix is to move the offending asset(s) out of the _Resources_ folder, and make them Addressable.
#### Check Scene to Addressable Duplicate Dependencies
This rule detects any assets or asset dependencies that are shared between the Scenes in the Editor Scene list and Addressables.
**Issues**: These duplications mean that data will be included in both the application build and the Addressables build.
**Resolution**: It is purely informational, alerting you to the redundancy. You must decide how to proceed and what action to take, if any. One example of a possible manual fix is to pull the built-in Scene(s) with duplicated references out of Build Settings and make it an Addressable Scene.
## Extending Analyze
Each unique Project may require additional Analyze rules beyond what comes pre-packaged. The Addressable Assets System allows you to create your own custom rule classes.
### AnalyzeRule objects
Create a new child class of the `AnalyzeRule` class, overriding the following properties:
* `CanFix` tells Analyze if the rule is deemed fixable or not.
* `ruleName` is the display name you'll see for this rule in the **Analyze window**.
You'll also need to override the following methods, which are detailed below:
* `List<AnalyzeResult> RefreshAnalysis(AddressableAssetSettings settings)`
* `void FixIssues(AddressableAssetSettings settings)`
* `void ClearAnalysis()`.
**Note**: If your rule is designated unfixable, you don't have to override the `FixIssues` method.
#### RefreshAnalysis
This is your analyze operation. In this method, perform any calculations you'd like and cache any data you might need for a potential fix. The return value is a `List<AnalyzeResult>` list. After you'd gathered your data, create a new `AnalyzeResult` for each entry in your analysis, containing the data as a string for the first parameter and a `MessageType` for the second (to optionally designate the message type as a warning or error). Return the list of objects you create.
If you need to make child elements in the `TreeView` for a particular `AnalyzeResult` object, you can delineate the parent item and any children with `kDelimiter`. Include the delimiter between the parent and child items.
#### FixIssues
This is your fix operation. If there is an appropriate action to take in response to the analyze step, execute it here.
#### ClearAnalysis
This is your clear operation. Any data you cached in the analyze step can be cleaned or removed in this function. The `TreeView` will update to reflect the lack of data.
### Adding custom rules to the GUI
A custom rule must register itself with the GUI class using `AnalyzeWindow.RegisterNewRule<RuleType>()`, in order to show up in the **Analyze window**. For example:
```
class MyRule : AnalyzeRule {}
[InitializeOnLoad]
class RegisterMyRule
{
static RegisterMyRule()
{
AnalyzeWindow.RegisterNewRule<MyRule>();
}
}
```

View File

@ -0,0 +1,70 @@
# Async operation handling
Several methods from the `Addressables` API return an `AsyncOperationHandle` struct. The main purpose of this handle is to allow access to the status and result of an operation. The result of the operation is valid until you call `Addressables.Release` or `Addressables.ReleaseInstance` with the operation (for more information on releasing assets, see documentation on [memory management](MemoryManagement.md).
When the operation completes, the `AsyncOperationHandle.Status` property is either `AsyncOperationStatus.Succeeded` or `AsyncOperationStatus.Failed`. If successful, you can access the result through the `AsyncOperationHandle.Result` property.
You can either check the operation status periodically, or register for a completed callback using the `AsyncOperationHandle.Complete` event. When you no longer need the asset provided by a returned `AsyncOperationHandle` struct, you should [release](MemoryManagement.md) it using the `Addressables.Release` method.
### Type vs typeless handles
Most `Addressables` API methods return a generic `AsyncOperationHandle<T>`struct, allowing type safety for the `AsyncOperationHandle.Completed` event, and for the `AsyncOperationHandle.Result` object. There is also a non-generic `AsyncOperationHandle` struct, and you can convert between the two handles as desired.
Note that a runtime exception occurs if you attempt to cast a non-generic handle to a generic handle of an incorrect type. For example:
```
AsyncOperationHandle<Texture2D> textureHandle = Addressables.LoadAssetAsync<Texture2D>("mytexture");
// Convert the AsyncOperationHandle<Texture2D> to an AsyncOperationHandle:
AsyncOperationHandle nonGenericHandle = textureHandle;
// Convert the AsyncOperationHandle to an AsyncOperationHandle<Texture2D>:
AsyncOperationHandle<Texture2D> textureHandle2 = nonGenericHandle.Convert<Texture2D>();
// This will throw and exception because Texture2D is required:
AsyncOperationHandle<Texture> textureHandle3 = nonGenericHandle.Convert<Texture>();
```
### AsyncOperationHandle use case examples
Register a listener for completion events using the `AsyncOperationHandle.Completed` callback:
```
private void TextureHandle_Completed(AsyncOperationHandle<Texture2D> handle) {
if (handle.Status == AsyncOperationStatus.Succeeded) {
Texture2D result = handle.Result;
// The texture is ready for use.
}
}
void Start() {
AsyncOperationHandle<Texture2D> textureHandle = Addressables.LoadAsset<Texture2D>("mytexture");
textureHandle.Completed += TextureHandle_Completed;
}
```
`AsyncOperationHandle` implements `IEnumerator` so it can be yielded in coroutines:
```
public IEnumerator Start() {
AsyncOperationHandle<Texture2D> handle = Addressables.LoadAssetAsync<Texture2D>("mytexture");
yield return handle;
if (handle.Status == AsyncOperationStatus.Succeeded) {
Texture2D texture = handle.Result;
// The texture is ready for use.
// ...
// Release the asset after its use:
Addressables.Release(handle);
}
}
```
Addressables also supports asynchronous `await` through the `AsyncOperationHandle.Task` property:
```
public async Start() {
AsyncOperationHandle<Texture2D> handle = Addressables.LoadAssetAsync<Texture2D>("mytexture");
await handle.Task;
// The task is complete. Be sure to check the Status is succeessful before storing the Result.
}
```
#### Please Note:
Loading scenes with `SceneManager.LoadSceneAsync` with `allowSceneActivation` set to false or using `Addressables.LoadSceneAsync` and passing in false for the `activateOnLoad` parameter can lead to subsequent async operations being blocked and unable to complete. Please checkout the `allowSceneActivation` documentation here: https://docs.unity3d.com/ScriptReference/AsyncOperation-allowSceneActivation.html

View File

@ -0,0 +1,16 @@
# Custom operations
The [`IResourceProvider`](../api/UnityEngine.ResourceManagement.ResourceProviders.IResourceProvider.html) API allows you to extend the loading process by defining locations and dependencies in a data-driven manner.
In some cases, you might want to create a custom operation. The `IResourceProvider` API is internally built on top of these custom operations.
### Creating custom operations
Create custom operations by deriving from the [`AsyncOperationBase`](../api/UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationBase-1.html) class and overriding the desired virtual methods. You can pass the derived operation to the `ResourceManager.StartOperation` method to start the operation and receive an `AsyncOperationHandle` struct. Operations started this way are registered with the `ResourceManager` and appear in the [Addressables Profiler](MemoryManagement.md#the-addressable-profiler).
#### Executing the operation
The `ResourceManager` invokes the `AsyncOperationBase.Execute` method for your custom operation once the optional dependent operation completes.
#### Completion handling
When your custom operation completes, call `AsyncOperationBase.Complete` on your custom operation object. You can call this within the `Execute` method or defer it to outside the call. Calling `AsyncOperationBase.Complete` notifies the `ResourceManager` that the operation is complete and will invoke the associated `AsyncOperationHandle.Completed` events.
#### Terminating the operation
The `ResourceManager` invokes `AsyncOperationBase.Destroy` method for your custom operation when you release the `AsyncOperationHandle` that references it. This is where you should release any memory or resources associated with your custom operation.

View File

@ -0,0 +1,158 @@
# Addressable Assets development cycle
One of the key benefits of Addressable Assets is decoupling how you arrange, build, and load your content. Traditionally, these facets of development are heavily tied together.
## Traditional asset management
If you arrange content in _Resources_ directories, it gets built into the base application and you must load the content using the [`Resources.Load`](https://docs.unity3d.com/ScriptReference/Resources.Load.html) method, supplying the path to the resource. To access content stored elsewhere, you would use direct references or asset bundles. If you use asset bundles, you would again load by path, tying your load and organization strategies together. If your asset bundles are remote, or have dependencies on other bundles, you have to write code to manage downloading, loading, and unloading all of your bundles.
## Addressable Asset management
Giving an asset an address allows you to load it using that address, no matter where it is in your Project or how you built the asset. You can change an Addressable Asset’s path or filename without issue. You can also move the Addressable Asset from the _Resources_ folder, or from a local build destination, to some other build location (including remote ones), without ever changing your loading code.
### Asset group schemas
Schemas define a set of data. You can attach schemas to asset groups in the Inspector. The set of schemas attached to a group defines how the build processes its contents. For example, when building in packed mode, groups with the `BundledAssetGroupSchema` schema attached to them act as sources for asset bundles. You can combine sets of schemas into templates that you use to define new groups. You can add schema templates via the `AddressableAssetsSettings` Inspector.
## Build scripts
Build scripts are represented as [`ScriptableObject`](https://docs.unity3d.com/Manual/class-ScriptableObject.html) assets in the Project that implement the [`IDataBuilder`](../api/UnityEditor.AddressableAssets.Build.IDataBuilder.html) interface. Users can create their own build scripts and add them to the `AddressableAssetSettings` object through its Inspector. To apply a build script in the **Addressables window** (**Window** > **Asset Management** > **Addressables**), select **Build Script**, and choose a dropdown option. Currently, there are three scripts implemented to support the full application build, and three Play mode scripts for iterating in the Editor.
### Play mode scripts
The Addressable Assets package has three build scripts that create Play mode data to help you accelerate app development.
#### Fast mode
Fast mode (`BuildScriptFastMode`) allows you to run the game quickly as you work through the flow of your game. Fast mode loads assets directly through the asset database for quick iteration with no analysis or asset bundle creation.
#### Virtual mode
Virtual mode (`BuildScriptVirtualMode`) analyzes content for layout and dependencies without creating asset bundles. Assets load from the asset database though the `ResourceManager`, as if they were loaded through bundles. To see when bundles load or unload during game play, view the asset usage in the [**Addressable Profiler window**](MemoryManagement.md#the-addressable-profiler) (**Window** > **Asset Management** > **Addressable Profiler**).
Virtual mode helps you simulate load strategies and tweak your content groups to find the right balance for a production release.
#### Packed Play mode
Packed Play mode (`BuildScriptPackedPlayMode`) uses asset bundles that are already built. This mode most closely matches a deployed application build, but it requires you to build the data as a separate step. If you aren't modifying assets, this mode is the fastest since it does not process any data when entering Play mode. You must either build the content for this mode in the **Addressables window** (**Window** > **Asset Management** > **Addressables**) by selecting **Build** > **Build Player Content**, or using the `AddressableAssetSettings.BuildPlayerContent()` method in your game script.
#### Choosing the right script
To apply a Play mode script, from the **Addressables window** menu (**Window** > **Asset Management** > **Addressables**), select **Play Mode Script** and choose from the dropdown options. Each mode has its own time and place during development and deployment. The following table illustrates stages of the development cycle, in which a particular mode is useful.
| | **Design** | **Develop** | **Build** | **Test / Play** | **Publish** |
|:---|:---|:---|:---|:---|:---|
| Fast | x | x | | In-Editor only | |
| Virtual | x | x | Asset bundle layout | In-Editor only | |
| Packed | | | Asset bundles | x | x |
## Analysis and debugging
By default, Addressable Assets only logs warnings and errors. You can enable detailed logging by opening the **Player** settings window (**Edit** > **Project Settings** > **Player**), navigating to the **Other Settings** > **Configuration** section, and adding "`ADDRESSABLES_LOG_ALL`" to the **Scripting Define Symbols** field.
You can also disable exceptions by unchecking the **Log Runtime Exceptions** option in the `AddressableAssetSettings` object Inspector. You can implement the [`ResourceManager.ExceptionHandler`](../api/UnityEngine.ResourceManagement.ResourceManager.html) property with your own exception handler if desired, but this should be done after Addressables finishes runtime initialization (see below).
## Initialization objects
You can attach objects to the Addressable Assets settings and pass them to the initialization process at runtime. The `CacheInitializationSettings` object controls Unity's caching API at runtime. To create your own initialization object, create a ScriptableObject that implements the [`IObjectInitializationDataProvider`](../api/UnityEngine.ResourceManagement.Util.IObjectInitializationDataProvider.html) interface. This is the Editor component of the system responsible for creating the `ObjectInitializationData` that is serialized with the runtime data.
## Content update workflow
Unity recommends structuring your game content into two categories:
* **Static** content that you never expect to update.
* **Dynamic** content that you expect to update.
In this structure, static content ships with the application (or downloads soon after install), and resides in very few large bundles. Dynamic content resides online, ideally in smaller bundles to minimize the amount of data needed for each update. One of the goals of the Addressable Assets System is to make this structure easy to work with and modify without having to change your scripts.
However, the Addressable Assets System can also accommodate situations that require changes to the "static" content, when you don't want to publish a whole new application build.
### How it works
Addressables uses a content catalog to map an address to each asset, specifying where and how to load it. In order to provide your app with the ability to modify that mapping, your original app must be aware of an online copy of this catalog. To set that up, enable the **Build Remote Catalog** setting on the `AddressableAssetSettings` Inspector. This ensures that a copy of the catalog gets built to and loaded from the specified paths. This load path cannot change once your app has shipped. The content update process creates a new version of the catalog (with the same file name) to overwrite the file at the previously specified load path.
Building an application generates a unique app content version string, which identifies what content catalog each app should load. A given server can contain catalogs of multiple versions of your app without conflict. We store the data we need in the _addressables_content_state.bin_ file. This includes the version string, along with hash information for any asset that is contained in a group marked as `StaticContent`. By default, this file is located in the same folder as your _AddressableAssetSettings.asset_ file.
The _addressables_content_state.bin_ file contains hash and dependency information for every `StaticContent` asset group in the Addressables system. All groups building to the _StreamingAssets_ folder should be marked as `StaticContent`, though large remote groups may also benefit from this designation. During the next step (preparing for content update, described below), this hash information determines if any `StaticContent` groups contain changed assets, and thus need those assets moved elsewhere.
### Preparing for content updates
If you have modified assets in any `StaticContent` groups, you'll need to run the **Prepare For Content Update** command. This will take any modified asset out of the static groups and move them to a new group. To generate the new asset groups:
1. Open the **Addressables window** in the Unity Editor (**Window** > **Asset Management** > **Addressable Assets**).
2. In the **Addressables window**, select **Build** on the top menu bar, then **Prepare For Content Update**.
3. In the **Build Data File** dialog that opens, select the _addressables_content_state.bin_ file (by default, this is located in the _Assets/AddressableAssetsData_ Project directory.
This data is used to determine which assets or dependencies have been modified since the application was last built. The system moves these assets to a new group in preparation for the content update build.
**Note**: This command will do nothing if all your changes are confined to non-static groups.
**Important**: Before running the prepare operation, Unity recommends branching your version control system. The prepare operation rearranges your asset groups in a way suited for updating content. Branching ensures that next time you ship a new player, you can return to your preferred content arrangement.
### Building for content updates
To build for a content update:
1. Open the **Addressables window** in the Unity Editor (**Window** > **Asset Management** > **Addressable Assets**).
2. In the **Addressables window**, select **Build** on the top menu, then **Build For Content Update**.
3. In the **Build Data File** dialog that opens, select the build folder of an existing application build. The build folder must contain an _addressables_content_state.bin_ file.
The build generates a content catalog, a hash file, and the asset bundles.
The generated content catalog has the same name as the catalog in the selected application build, overwriting the old catalog and hash file. The application loads the hash file to determine if a new catalog is available. The system loads unmodified assets from existing bundles that were shipped with the application or already downloaded.
The system uses the content version string and location information from the _addressables_content_state.bin_ file to create the asset bundles. Asset bundles that do not contain updated content are written using the same file names as those in the build selected for the update. If an asset bundle contains updated content, a new asset bundle is generated that contains the updated content, with a new file name so that it can coexist with the original. Only asset bundles with new file names must be copied to the location that hosts your content.
The system also builds asset bundles for static content, but you do not need to upload them to the content hosting location, as no Addressables asset entries reference them.
### Content update examples
In this example, a shipped application is aware of the following groups:
| **`Local_Static`** | **`Remote_Static`** | **`Remote_NonStatic`** |
|:---------|:---------|:---------|
| `AssetA` | `AssetL` | `AssetX` |
| `AssetB` | `AssetM` | `AssetY` |
| `AssetC` | `AssetN` | `AssetZ` |
As this version is live, there are players that have `Local_Static` on their devices, and potentially have either or both of the remote bundles cached locally.
If you modify one asset from each group (`AssetA`, `AssetL`, and `AssetX`), then run **Prepare For Content Update**, the results in your local Addressable settings are now:
| **`Local_Static`** | **`Remote_Static`** | **`Remote_NonStatic`** | **`content_update_group (non-static)`** |
|:---------|:---------|:---------|:---------|
| | | `AssetX` | `AssetA` |
| `AssetB` | `AssetM` | `AssetY` | `AssetL` |
| `AssetC` | `AssetN` | `AssetZ` | |
Note that the prepare operation actually edits the static groups, which may seem counter intuitive. The key, however, is that the system builds the above layout, but discards the build results for any static groups. As such, you end up with the following from a player's perspective:
| **`Local_Static`** |
|:---------|
| `AssetA` |
| `AssetB` |
| `AssetC` |
The `Local_Static` bundle is already on player devices, which you can't change. This old version of `AssetA` is no longer referenced. Instead, it is stuck on player devices as dead data.
| **`Remote_Static`** |
|:---------|
| `AssetL` |
| `AssetM` |
| `AssetN` |
The `Remote_Static` bundle is unchanged. If it is not already cached on a player's device, it will download when `AssetM` or `AssetN` is requested. Like `AssetA`, this old version of `AssetL` is no longer referenced.
| **`Remote_NonStatic`** (old) |
|:---------|
| `AssetX` |
| `AssetY` |
| `AssetZ` |
The `Remote_NonStatic` bundle is now old. You could delete it from the server, but either way it will not be downloaded from this point forward. If cached, it will eventually leave the cache. Like `AssetA` and `AssetL`, this old version of `AssetX` is no longer referenced.
| **`Remote_NonStatic`** (new) |
|:---------|
| `AssetX` |
| `AssetY` |
| `AssetZ` |
The old `Remote_NonStatic` bundle is replaced with a new version, distinguished by its hash file. The modified version of `AssetX` is updated with this new bundle.
| **`content_update_group`** |
|:---------|
| `AssetA` |
| `AssetL` |
The `content_update_group` bundle consists of the modified assets that will be referenced moving forward.
Here are the implications of this example:
1. Any changed local assets remain unused on the user's device forever.
2. If the user already cached a non-static bundle, they will need to re-download the bundle, including the unchanged assets (in this instance, for example, `AssetY` and `AssetZ`). Ideally, the user has not cached the bundle, in which case they simply need to download the new `Remote_NonStatic` bundle.
3. If the user has already cached the `Static_Remote` bundle, they only need to download the updated asset (in this instance, `AssetL` via `content_update_group`). This is ideal in this case. If the user has not cached the bundle, they must download both the new `AssetL` via `content_update_group` and the now-defunct `AssetL` via the untouched `Remote_Static` bundle. Regardless of the initial cache state, at some point the user will have the defunct `AssetL` on their device, cached indefinitely despite never being accessed.
The best setup for your remote content will depend on your specific use case.

View File

@ -0,0 +1,135 @@
# Getting started with Addressable Assets
## Installing the Addressable Assets package
**Important**: The Addressable Asset System requires Unity version 2018.3 or later.
To install this package, follow the instructions in the [Package Manager documentation](https://docs.unity3d.com/Packages/com.unity.package-manager-ui@1.7/manual/index.html).
## Preparing Addressable Assets
### Marking assets as Addressable
There are two ways to mark an asset as Addressable in the Unity Editor:
* In the object's Inspector.
* In the **Addressables window**.
#### Using the Inspector
In your **Project window**, select the desired asset to view its Inspector. In the Inspector, click the **Address** checkbox and enter a name by which to identify the asset.
![Marking an asset as Addressable in the Inspector window.](images/inspectorcheckbox.png)
#### Using the Addressables window
Select **Window** > **Asset Management** > **Addressables** to open the **Addressables window**. Next, drag the desired asset from your **Project window** into one of the asset groups in the **Addressables window**.
![Marking an asset as Addressable in the Addressables window.](images/addressableswindow.png)
### Specifying an address
The default address for your asset is the path to the asset in your Project (for example, _Assets/images/myImage.png_). To change the asset's address from the **Addressables window**, right-click the asset and select **Rename**.
When you first start using Addressable Assets, the system saves some edit-time and run-time data assets for your Project in the _Assets/AddressableAssetsData_ file, which should be added to your version control check-in.
### Building your Addressable content
The Addressables Asset System needs to build your content into files that can be consumed by the running game before you build the application. This step is not automatic. You can build this content via the Editor or API:
* To build content in the Editor, open the **Addressables window**, then select **Build** > **Build Player Content**.
* To build content using the API, use [`AddressableAssetSettings.BuildPlayerContent()`](../api/UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.html#methods).
## Using Addressable Assets
### Loading or instantiating by address
You can load or instantiate an Addressable Asset at run-time. Loading an asset loads all dependencies into memory (including the asset's bundle data if applicable), allowing you to use the asset when you need to. This does not actually put the desired asset into your scene. To add the asset to your scene you must instantiate. Using Addressables instantiation intefraces will load the asset, then immediately adds it to your Scene.
To access an asset from your game script using a string address, declare the `UnityEngine.AddressableAssets` namespace, then call the following methods:
```
Addressables.LoadAssetAsync<GameObject>("AssetAddress");
```
This loads the asset with the specified address.
```
Addressables.InstantiateAsync("AssetAddress");
```
This instantiates the asset with the specified address into your Scene.
**Note**: `LoadAssetAsync` and `InstantiateAsync` are asynchronous operations. You may provide a callback to work with the asset when it finishes loading (see documentation on [**Async operation handling**](AddressableAssetsAsyncOperationHandle) for more information).
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine.AddressableAssets;
using UnityEngine;
public class AddressablesExample : MonoBehaviour {
GameObject myGameObject;
...
Addressables.LoadAssetAsync<GameObject>("AssetAddress").Completed += OnLoadDone;
}
private void OnLoadDone(UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle<GameObject> obj)
{
// In a production environment, you should add exception handling to catch scenarios such as a null result.
myGameObject = obj.Result;
}
}
```
#### Sub-assets and components
Sub-assets and components are special cases for asset loading.
* **Components**: You cannot load a GameObject's component directly as an asset. You must load or instantiate the GameObject, then retrieve the component reference from it.
* **Sub-assets**: The system supports loading sub-assets, but requires special syntax. Examples of potential sub-assets include sprites in a sprite sheet, or animation clips in an FBX file. To load them, use the following example syntax:
`Addressables.LoadAssetAsync<IList<Sprite>>("MySpriteSheetAddress");`
### Using the AssetReference class
The `AssetReference` class provides a way to access Addressable Assets without needing to know their addresses. To access an Addressable Asset using the `AssetReference` class:
1. Select a GameObject from your Scene hierarchy or **Project window**.
2. In the Inspector, click the **Add Component** button, then select the component type. Any serializable component can support an `AssetReference` variable (for example, a game script, ScriptableObject, or other serializable class).
3. Add a public `AssetReference` variable in the component (for example, `public AssetReference explosion;`).
4. In the Inspector, select which Addressable Asset to link to the object, by either dragging the asset from the **Project window** into the exposed `AssetReference` field, or choosing from the dropdown of previously defined Addressable Assets in your Project (shown below).
![Referencing an Addressable Asset via script component.](images/Inspectorreferenceselection2.png)
To load or instantiate an `AssetReference` asset, call its corresponding method. For example:
```
AssetRefMember.LoadAssetAsync<GameObject>();
```
or
```
AssetRefMember.InstantiateAsync(pos, rot);
```
**Note**: As with normal Addressable Assets, `LoadAssetAsync` and `InstantiateAsync` are asynchronous operations. You may provide a callback to work with the asset when it finishes loading (see documentation on [**Async operation handling**](AddressableAssetsAsyncOperationHandle) for more information).
## Build considerations
### Local data in StreamingAssets
The Addressable Asset System needs some files at runtime to know what to load and how to load it. Those files are generated when you build Addressables data and wind up in the _StreamingAssets_ folder, which is a special folder in Unity that includes all its files in the build. When you build Addressables content, the system stages those files in the Library. Then, when you build the application, the system copies the required files over to _StreamingAssets_, builds, and deletes them from the folder. This way, you can build data for multiple platforms while only having the relevant data included in each build.
In addition to the Addressables-specific data, any groups that build their data for local use will also use the Library platform-specific staging location. To verify that this works, set your build path and load paths to profile variables starting with `[UnityEngine.AddressableAssets.Addressables.BuildPath]` and `{UnityEngine.AddressableAssets.Addressables.RuntimePath}` respectively. You can specify these settings in the `AddressableAssetSettings` Inspector (by default, this object is located in your Project's _Assets/AddressableAssetsData_ directory).
### Downloading in Advance
Calling the `Addressables.DownloadDependenciesAsync()` method loads the dependencies for the address or label that you pass in. Typically, this is the asset bundle.
The [`AsyncOperationHandle`](AddressableAssetsAsyncOperationHandle.md) struct returned by this call includes a `PercentComplete` attribute that you can use to monitor and display download progress. You can also have the app wait until the content has loaded.
If you wish to ask the user for consent prior to download, use `Addressables.GetDownloadSize()` to return how much space is needed to download the content from a given address or label. Note that this takes into account any previously downloaded bundles that are still in Unity's asset bundle cache.
While it can be advantageous to download assets for your app in advance, there are instances where you might choose not do so. For example:
* If your app has a large amount of online content, and you generally expect users to only ever interact with a portion of it.
* You have an app that must be connected online to function. If all your app's content is in small bundles, you might choose to download content as needed.
Rather than using the percent complete value to wait until the content is loaded, you can use the preload functionality to show that the download has started, then continue on. This implementation would require a loading or waiting screen to handle instances where the asset has not finished loading by the time it's needed.
### Building for multiple platforms
The Addressable Asset System generates asset bundles containing your Addressable Assets when building application content. Asset bundles are platform-dependant, and thus must be rebuilt for every unique platform you intend to support.
By default, when building Addressables app data, data for your given platform is stored in platform-specific subdirectories of the Addressables build path(s). The runtime path accounts for these platform folders, and points to the applicable app data.
**Note**: If you use the Addressables `BuildScriptPackedPlayMode` script in the Editor Play mode, Addressables will attempt to load data for your current active build target. As such, issues may arise if your current build target data isn't compatible with your current Editor platform. For more information, see documentation on [Play mode scripts](AddressableAssetsDevelopmentCycle.md#play-mode-scripts).

View File

@ -0,0 +1,89 @@
# Asset Hosting Services
## Overview
Hosting Services provide an integrated facility for using Addressable Assets configuration data to serve packed content to local or network-connected application builds from within the Unity Editor. Hosting Services are designed to improve iteration velocity when testing packed content, and can also be used to serve content to connected clients on local and remote networks.
### Packed mode testing and iteration
Moving from Editor Play mode testing to platform application build testing introduces complexities and time costs to the development process. Hosting Services provide extensible Editor-embedded content delivery services that map directly to your Addressables group configuration. Using a custom Addressables profile, you can quickly configure your application to load all content from the Unity Editor itself. This includes builds deployed to mobile devices, or any other platform, that have network access to your development system.
### Turn-key content server
You can deploy Asset Hosting Services into a server environment by running in batch mode (headless) to host content for both intranet- and internet-facing Unity application clients.
## Setup
This article details the initial setup of Asset Hosting Services for your Project. While the setup guide focuses on Editor workflows, you can use the API to configure Hosting Services by setting the `HostingServicesManager` property of the [`AddressableAssetSettings`](../api/UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.html) class.
### Configuring a new Hosting Service
Use the **Hosting window** to add, configure, and enable new Hosting Services. In the Editor, select **Window** > **Asset Management** > **Hosting Services**, or click the **Hosting** button from the **Addressables window** menu to access the **Hosting window**.
![The Hosting window.](images/HostingServicesWindow_1.png)
To add a new Hosting Service, click the **Add Service** button.
![Adding a new Hosting Service.](images/HostingServicesAddService_1.png)
In the **Add Service** dialog that appears, you can select a predefined service type or define a custom service type. To use a predefined service type, choose from the **Service Type** drop-down options. Use the **Descriptive Name** field enter a name for the service.
**Note**: For more information on implementing custom hosting service types, see the section on [custom services](#custom-services).
The newly added service appears in the **Hosting Services** section of the **Hosting window**, and defaults to the disabled state. To initiate the service, click the **Enable Service** button.
![The updated Hosting window after adding a service.](images/HostingServicesWindow_2.png)
The HTTP Hosting Service automatically assigns a port number when it starts. The port number is saved and reused between Unity sessions. To choose a different port, either assign a specific port number in the **Port** field, or use the **Reset** button to randomly assign a different port.
**Note**: If you reset the port number, you must execute a full application build to generate and embed the correct URL.
The HTTP Hosting Service is now enabled and ready to serve content from the directory specified in the `BuildPath` of each asset group.
### Profile setup
When working with Hosting Services during development, Unity recommends creating a profile that configures all asset groups to load content from the Hosting Service using a directory or directories created specifically for that purpose.
In the **Addressables window** menu (**Window** > **Asset Management** > **Addressable Assets**), select **Profiles** > **Inspect Profile Settings**. You can also access these settings via the `AddressableAssetSettings` Inspector.
Next, create a new profile. In the following example, the new profile is called "Editor Hosted".
![Creating a service profile.](images/HostingServicesProfiles_1.png)
Modify the loading path fields to instead load from the Hosting Service. `HttpHostingService` is a URL that uses the local IP address and the port assigned to the service. From the **Hosting window**, you can use the profile variables named `PrivateIpAddress` and `HostingServicePort` to construct the url (for example, `http://[PrivateIpAddress]:[HostingServicePort]`).
Additionally, you should modify all build path variables to point to a common directory outside of the Project's _Assets_ folder.
![Configuring the service's profile.](images/HostingServicesProfiles_2.png)
Verify that each group is configured correctly. Ensure that the `BuildPath` and `LoadPath` paths are set to their respective profile keys that are modified for use with Hosting Services. In this example, you can see how the profile variables in the `LoadPath` are expanded to build a correct base URL for loading from Hosted Services.
![Inspecting the service's load paths.](images/HostingServicesGroups_1.png)
Finally, select the new profile from the **Addressables window**, create a build, and deploy to the target device. The Unity Editor now serves all load requests from the application through the `HttpHostingService` service. You can now make additions and changes to content without redeployment. Rebuild the Addressable content, and relaunch the already deployed application to refresh the content.
![Selecting a Hosting Service profile.](images/HostingServicesProfiles_3.png)
### Batch mode
You can also use Hosting Services to serve content from the Unity Editor running in batch mode. To do so, launch Unity from the command line with the following options:
```
-batchMode -executeMethod UnityEditor.AddressableAssets.HostingServicesManager.BatchMode
```
This loads the Hosting Services configuration from the default `AddressableAssetSettings` object, and starts all configured services.
To use an alternative `AddressableAssetSettings` configuration, create your own static method entry point, to call through the `UnityEditor.AddressableAssets.HostingServicesManager.BatchMode(AddressableAssetSettings settings)` overload.
<a name="custom-services"></a>
## Custom Services
Hosting Services are designed to be extensible, allowing you to implement your own custom logic for serving content-loading requests from the Addressable Assets System. For example:
* Support a custom [`IResourceProvider`](../api/UnityEngine.ResourceManagement.ResourceProviders.IResourceProvider.html) that uses a non-HTTP protocol for downloading content.
* Manage an external process for serving content that matches your production CDN solution (such as an Apache HTTP server).
### Implementing a custom service
The `HostingServicesManager` can manage any class that implements an `IHostingService` interface (for more details on method parameters and return values, see the [API documentation](../api/UnityEditor.AddressableAssets.IHostingService.html).
To create a new custom service:
1. Follow the steps outlined in the [configuring a new Hosting Service](#configuring-a-new-hosting-service) section above to access the **Add Service** dialog.
2. Select **Custom**, then drag and drop the applicable script into the field, or select it from the object picker. The dialog validates that the selected script implements the `IHostingService` interface.
3. To finish adding the service, click the **Add** button.
Moving forward, your custom service will appear in the **Service Type** drop-down options.
![Adding a custom Asset Hosting Service.](images/HostingServicesAddService_2.png)

View File

@ -0,0 +1,25 @@
# Upgrading to the Addressables system
This article details how to modify your existing Project to take advantage of Addressable Assets. There are three traditional methods for referencing assets:
* **[Direct References](#the-direct-reference-method)**: Add assets directly into components or Scenes, which the application loads automatically.
* **[Resource Folders](#the-resource-folders-method)**: Add assets to your _Resource_ folder and load them by filename.
* **[Asset Bundles](#the-asset-bundles-method)**: Add assets to asset bundles, then load them with their dependencies by file path.
### The direct reference method
To migrate from this approach, follow these steps:
1. Replace your direct references to objects with asset references (for example, `public GameObject directRefMember;` becomes `public AssetReference AssetRefMember;`).
2. Drag assets onto the appropriate component’s Inspector, as you would for a direct reference.
3. If you'd like to load an asset based on an object rather than a string name, instantiate it directly from the `AssetReference` object you created in your setup (for example, `AssetRefMember.LoadAssetAsync<GameObject>();` or `AssetRefMember.InstantiateAsync(pos, rot);`).
**Note**: The Addressable Asset System loads assets asynchronously. When you update your direct references to asset references, you must also update your code to operate asynchronously.
### The Resource folders method
When you mark an asset in a _Resources_ folder as Addressable, the system automatically moves the asset from the _Resources_ folder to a new folder in your Project named _Resources_moved_. The default address for a moved asset is the old path, omitting the folder name. For example, your loading code might change from `Resources.LoadAsync<GameObject>("desert/tank.prefab");` to `Addressables.LoadAssetAsync<GameObject>("desert/tank.prefab");`.
### The asset bundles method
When you open the **Addressables window**, Unity offers to convert all asset bundles into Addressable Asset groups. This is the easiest way to migrate your code.
If you choose to convert your Assets manually, click the **Ignore** button. Then, either use the direct reference or resource folder methods previously described.
The default path for the address of an asset is its file path. If you use the path as the asset's address, you'd load the asset in the same manner as you would load from a bundle. The Addressable Asset System handles the loading of the bundle and all its dependencies.

View File

@ -0,0 +1,19 @@
# Addressable Assets Overview
The Addressable Assets System consists of two packages:
* Addressable Assets package (primary package)
* Scriptable Build Pipeline package (dependency)
When you install the Addressable Assets package, the Scriptable Build Pipeline package installs at the same time.
## Concepts
The following concepts are referenced throughout this documentation:
* **Address**: An asset's location identifier for easy runtime retrieval.
* **`AddressableAssetData` directory**: Stores your Addressable Asset metadata in your Project’s _Assets_ directory.
* **Asset group**: A set of Addressable Assets available for build-time processing.
* **Asset group schema**: Defines a set of data that you can assign to a group and use during the build.
* **`AssetReference`**: An object that operates like a direct reference, but with deferred initialization. The `AssetReference` object stores the GUID as an Addressable that you can load on demand.
* **Asynchronous loading**: Allows the location of the asset and its dependencies to change throughout the course of your development without changing the game code. Asynchronous loading is foundational to the Addressable Asset System.
* **Build script**: Runs asset group processors to package assets, and provides the mapping between addresses and _Resource_ locations for the Resource Manager.
* **Label**: Provides an additional Addressable Asset identifier for runtime loading of similar items (for example, `Addressables.DownloadDependenciesAsync("spaceHazards");`).

View File

@ -0,0 +1,49 @@
# Memory management
## Mirroring load and unload
When working with Addressable Assets, the primary way to ensure proper memory management is to mirror your load and unload calls correctly. How you do so depends on your asset types and load methods. In all cases, however, the release method can either take the loaded asset, or an operation handle returned by the load. For example, during Scene creation (described below) the load returns a `AsyncOperationHandle<SceneInstance>`, which you can release via this returned handle, or by keeping up with the `handle.Result` (in this case, a `SceneInstance`).
### Asset loading
To load an asset, use `Addressables.LoadAssetAsync` or `Addressables.LoadAssetsAsync`.
This loads the asset into memory without instantiating it. Every time the load call executes, it adds one to the ref-count for each asset loaded. If you call `LoadAssetAsync` three times with the same address, you will get three different instances of an [`AsyncOperationHandle`](../api/UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.html) struct back, all referencing the same underlying operation. That operation has a ref-count of three for the corresponding asset. If the load succeeds, the resulting `AsyncOperationHandle` struct contains the asset in the `.Result` property. You can use the loaded asset to instantiate using Unity's built-in instantiation methods, which does not increment the Addressables ref-count.
To unload the asset, use the `Addressables.Release` method, which decrements the ref-count. When a given asset's ref-count is zero, that asset is ready to be unloaded, and decrements the ref-count of any dependencies.
**Note**: The asset may or may not be unloaded immediately, contingent on existing dependencies. For more information, read the section on [when memory is cleared](#when-is-memory-cleared-).
### Scene loading
To load a Scene, use `Addressables.LoadSceneAsync`. You can use this method to load a Scene in `Single` mode, which closes all open Scenes, or in `Additive` mode (for more information, see documentation on [Scene mode loading](https://docs.unity3d.com/ScriptReference/SceneManagement.LoadSceneMode.html).
To unload a Scene, use `Addressables.UnloadSceneAsync`, or open a new Scene in `Single` mode. You can open a new Scene by either using the Addressables interface, or using the `SceneManager.LoadScene` or `SceneManager.LoadSceneAsync` methods. Opening a new Scene closes the current one, properly decrementing the ref-count.
### GameObject instantiation
To load and instantiate a GameObject asset, use `Addressables.InstantiateAsync`. This instantiates the Prefab located by the specified `location` parameter. The Addressables system will load the Prefab and its dependencies, incrementing the ref-count of all associated assets.
Calling `InstantiateAsync` three times on the same address results in all dependent assets having a ref-count of three. Unlike calling `LoadAssetAsync` three times, however, each `InstantiateAsync` call returns an `AsyncOperationHandle` pointing to a unique operation. This is because the result of each `InstantiateAsync` is a unique instance. Another distinction between `InstantiateAsync` and other load calls is the optional `trackHandle` parameter. When set to `false`, you must keep the `AsyncOperationHandle` to use while releasing your instance. This is more efficient, but requires more development effort.
To destroy an instantiated gameObject, use `Addressables.ReleaseInstance`, or close the Scene that contains the instantiated object. This Scene can have been loaded (and thus closed) in `Additive` or `Single` mode. This Scene can also have been loaded using either the `Addressables` or `SceneManagement` API. As noted above, if you set `trackHandle` to `false`, you can only call `Addressables.ReleaseInstance` with the handle, not with the actual GameObject.
**Note**: If you call `Addressables.ReleaseInstance` on an instance that was not created using the `Addressables` API, or was created with `trackHandle==false`, the system detects that and returns `false` to indicate that the method was unable to release the specified instance. The instance will not be destroyed in this case.
`Addressables.InstantiateAsync` has some associated overhead, so if you need to instantiate the same objects hundreds of times per frame, consider loading via the `Addressables` API, then instantiating through other methods. In this case, you would call `Addressables.LoadAssetAsync`, then save the result and call `GameObject.Instantiate()` for that result. This allows flexibility to call `Instantiate` in a synchronous way. The downside is that the Addressables system has no knowledge of how many instances you created, which can lead to memory issues if not properly managed. For example, a Prefab referencing a texture would no longer have a valid loaded texture to reference, causing rendering issues (or worse). These sorts of problems can be hard to track down as you may not immediately trigger the memory unload (see section on [clearing memory](#when-is-memory-cleared-), below).
## The Addressable Profiler
Use the **Addressable Profiler window** to monitor the ref-counts of all Addressables system operations. To access the window in the Editor, select **Window** > **Asset Management** > **Addressable Profiler**.
**Important**: In order to view data in the profiler, you must enable the **Send Profiler Events** setting in your `AddressableAssetSettings` object's Inspector.
The following information is available in the profiler:
* A white vertical line indicates the frame in which a load request occurred.
* A blue background indicates that an asset is currently loaded.
* The green part of the graph indicates an asset's current ref-count.
## When is memory cleared?
An asset no longer being referenced (indicated by the end of a blue section in the profiler) does not necessarily mean that asset was unloaded. A common applicable scenario involves multiple assets in an asset bundle. For example:
* You have three assets (`tree`, `tank`, and `cow`) in an asset bundle (`stuff`).
* When `tree` loads, the profiler displays a single ref-count for `tree`, and one for `stuff`.
* Later, when `tank` loads, the profiler displays a single ref-count for both `tree` and `tank`, and two ref-counts for the `stuff` bundle.
* If you release `tree`, it's ref-count becomes zero, and the blue bar goes away.
In this example, the `tree` asset is not actually unloaded at this point. You can load an asset bundle, or its partial contents, but you cannot partially unload an asset bundle. No asset in `stuff` will unload until the bundle itself is completely unloaded. The exception to this rule is the engine interface [`Resources.UnloadUnusedAssets`](https://docs.unity3d.com/ScriptReference/Resources.UnloadUnusedAssets.html). Executing this method in the above scenario will cause `tree` to unload. Because the Addressables system cannot be aware of these events, the profiler graph only reflects the Addressables ref-counts (not exactly what memory holds). Note that if you choose to use `Resources.UnloadUnusedAssets`, it is a very slow operation, and should only be called on a screen that won't show any hitches (such as a loading screen).

View File

@ -0,0 +1,10 @@
* [Addressable Asset System](index)
* [Addressable Assets overview](AddressableAssetsOverview)
* [Getting started](AddressableAssetsGettingStarted)
* [Development cycle](AddressableAssetsDevelopmentCycle)
* [Hosting Services](AddressableAssetsHostingServices)
* [Memory Management](MemoryManagement)
* [Async Operation Handle](AddressableAssetsAsyncOperationHandle)
* [Custom Operations](AddressableAssetsCustomOperation)
* [Analyze](AddressableAssetsAnalyze)
* [Migration Guide](AddressableAssetsMigrationGuide)

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: b855c9273a2924ca2a7fc7c5bf2565af
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: 731ce7caea6b14c3b8dfc649b60ae3ae
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: d2bec5581eef4450b82c1d520db604c2
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: 3b8f63e518f1a4c14b7e22f025f885d6
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: 127a942f897824ff0884e74f97f45844
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: 503decdf700ec4d5787e72a5c5497e98
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: 2bcb5ba40e59e4d2a8d6a7b651994d0c
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: d67c623d370194e6e98435d1c7dc15b2
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: f8c497f554ad9d04eaee231687cda3e9
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: a0fc7478c4d38894faae2afc1de98109
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: 3ec505066001b944a8f3dc4ad7d6cc7c
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,88 @@
fileFormatVersion: 2
guid: b6311971a725d264e8842e523a1651b5
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,22 @@
# Unity Addressable Asset System
The Addressable Asset System provides an easy way to load assets by “address”. It handles asset management overhead by simplifying content pack creation and deployment.
The Addressable Asset System uses asynchronous loading to support loading from any location with any collection of dependencies. Whether you use direct references, traditional asset bundles, or _Resource_ folders for asset management, Addressable Assets provide a simpler way to make your game more dynamic.
## What is an asset?
An asset is content that you use to create your game or app. Common examples of assets include Prefabs, textures, materials, audio clips, and animations.
## What is an Addressable Asset?
Making an asset "Addressable" allows you to use that asset's unique address to call it from anywhere. Whether that asset resides in the local application or on a content delivery network, the Addressable Asset System locates and returns it. You can load a single Addressable Asset via its address, or load many Addressable Assets using a custom group label that you define.
## Why use Addressable Assets?
Traditional means of structuring game assets make it challenging to efficiently load content. Addressables shorten your iteration cycles, allowing you to devote more time to designing, coding, and testing your application.
* **Iteration time**: Referring to content by its address is extremely efficient. Optimizations to the content no longer require changes to your code.
* **Dependency management**: The system returns all dependencies of the requested content, so that all meshes, shaders, animations, and so forth load before returning the content to you.
* **Memory management**: The system unloads assets as well as loading them, counting references automatically and providing a robust profiler to help you spot potential memory problems.
* **Content packing**: Because the system maps and understands complex dependency chains, it allows for efficient packing of bundles, even when moving or renaming assets. You can easily prepare assets for both local and remote deployment, to support downloadable content and reduced application size.
## What about my existing game?
The Addressable Asset System provides a [migration path](AddressableAssetsMigrationGuide.md) for upgrading, whether you use direct references, _Resource_ folders, or asset bundles.

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: b38733bdad235b34b993286370a11791
folderAsset: yes
timeCreated: 1498750562
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,174 @@
using System;
using UnityEditor;
using UnityEditor.AddressableAssets.Settings;
using UnityEngine;
using UnityEngine.Serialization;
namespace UnityEditor.AddressableAssets
{
/// <summary>
/// Class used to get and set the default Addressable Asset settings object.
/// </summary>
public class AddressableAssetSettingsDefaultObject : ScriptableObject
{
/// <summary>
/// Default name for the addressable assets settings
/// </summary>
public const string kDefaultConfigAssetName = "AddressableAssetSettings";
/// <summary>
/// The default folder for the serialized version of this class.
/// </summary>
public const string kDefaultConfigFolder = "Assets/AddressableAssetsData";
/// <summary>
/// The name of the default config object
/// </summary>
public const string kDefaultConfigObjectName = "com.unity.addressableassets";
/// <summary>
/// Default path for addressable asset settings assets.
/// </summary>
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<AddressableAssetSettings>(path);
if (settings != null)
AddressablesAssetPostProcessor.OnPostProcess = settings.OnPostprocessAllAssets;
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 = settings.OnPostprocessAllAssets;
m_AddressableAssetSettingsGuid = AssetDatabase.AssetPathToGUID(path);
}
static AddressableAssetSettings s_DefaultSettingsObject;
/// <summary>
/// Used to determine if a default settings asset exists.
/// </summary>
public static bool SettingsExists
{
get
{
AddressableAssetSettingsDefaultObject so;
if (EditorBuildSettings.TryGetConfigObject(kDefaultConfigObjectName, out so))
return !string.IsNullOrEmpty(AssetDatabase.GUIDToAssetPath(so.m_AddressableAssetSettingsGuid));
return false;
}
}
/// <summary>
/// Gets the default addressable asset settings object. This will return null during editor startup if EditorApplication.isUpdating or EditorApplication.isCompiling are true.
/// </summary>
public static AddressableAssetSettings Settings
{
get
{
if (s_DefaultSettingsObject == null && !EditorApplication.isUpdating && !EditorApplication.isCompiling)
{
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<AddressableAssetSettingsDefaultObject>();
so.SetSettingsObject(s_DefaultSettingsObject);
AssetDatabase.CreateAsset(so, kDefaultConfigFolder + "/DefaultObject.asset");
EditorUtility.SetDirty(so);
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<AddressableAssetSettingsDefaultObject>();
AssetDatabase.CreateAsset(so, kDefaultConfigFolder + "/DefaultObject.asset");
AssetDatabase.SaveAssets();
EditorBuildSettings.AddConfigObject(kDefaultConfigObjectName, so, true);
}
so.SetSettingsObject(s_DefaultSettingsObject);
EditorUtility.SetDirty(so);
AssetDatabase.SaveAssets();
}
}
/// <summary>
/// Gets the settings object with the option to create a new one if it does not exist.
/// </summary>
/// <param name="create">If true and no settings object exists, a new one will be created using the default config folder and asset name.</param>
/// <returns>The default settings object.</returns>
public static AddressableAssetSettings GetSettings(bool create)
{
if (Settings == null && create)
Settings = AddressableAssetSettings.Create(kDefaultConfigFolder, kDefaultConfigAssetName, true, true);
return Settings;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3a189bb168d8d90478a09ea08c2f3d72
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: e449fe7932420f940adb4c9b75596bd2
folderAsset: yes
timeCreated: 1504023214
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,64 @@
using System;
using UnityEditor.AddressableAssets.Settings;
using UnityEngine.Analytics;
namespace UnityEditor.AddressableAssets
{
internal static class AddressableAnalytics
{
private const string VendorKey = "unity.addressables";
private const string EventName = "addressables";
private static bool _eventRegistered = false;
[Serializable]
private struct AnalyticsData
{
public string BuildScriptName;
public int NumberOfAddressableAssets;
};
internal static void Report(AddressableAssetSettings currentSettings)
{
//The event shouldn't be able to report if this is disabled but if we know we're not going to report
//Lets early out and not waste time gathering all the data
if (!UnityEngine.Analytics.Analytics.enabled)
return;
ReportImpl(currentSettings);
}
private static void ReportImpl(AddressableAssetSettings currentSettings)
{
if (!_eventRegistered)
{
//If the event isn't registered, attempt to register it. If unsuccessful, return.
if (!RegisterEvent())
return;
}
//Gather how many addressable assets we have
int numberOfAddressableAssets = 0;
foreach (var group in currentSettings.groups)
numberOfAddressableAssets += group.entries.Count;
AnalyticsData data = new AnalyticsData()
{
BuildScriptName = currentSettings.ActivePlayerDataBuilder.Name,
NumberOfAddressableAssets = numberOfAddressableAssets,
};
//Report
EditorAnalytics.SendEventWithLimit(EventName, data);
}
//Returns true if registering the event was successful
private static bool RegisterEvent()
{
AnalyticsResult registerEvent = EditorAnalytics.RegisterEventWithLimit(EventName, 100, 100, VendorKey);
if (registerEvent == AnalyticsResult.Ok)
_eventRegistered = true;
return _eventRegistered;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3a6ea556a4c75be4a88f236f22eec817
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,79 @@
using System;
using System.IO;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
namespace UnityEditor.AddressableAssets.Build
{
/// <summary>
/// Entry point to set callbacks for builds.
/// </summary>
public static class BuildScript
{
/// <summary>
/// Global delegate for handling the result of AddressableAssets builds. This will get called for player builds and when entering play mode.
/// </summary>
public static Action<AddressableAssetBuildResult> buildCompleted;
}
static class AddressablesBuildScriptHooks
{
[InitializeOnLoadMethod]
static void Init()
{
EditorApplication.playModeStateChanged += OnEditorPlayModeChanged;
}
static void OnEditorPlayModeChanged(PlayModeStateChange state)
{
if (state == PlayModeStateChange.ExitingEditMode)
{
var settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null)
return;
if (settings.ActivePlayModeDataBuilder == null)
{
var err = "Active play mode build script is null.";
Debug.LogError(err);
if (BuildScript.buildCompleted != null)
{
var result = AddressableAssetBuildResult.CreateResult<AddressableAssetBuildResult>(null, 0, err);
BuildScript.buildCompleted(result);
}
return;
}
if (!settings.ActivePlayModeDataBuilder.CanBuildData<AddressablesPlayModeBuildResult>())
{
var err = string.Format("Active build script {0} cannot build AddressablesPlayModeBuildResult.", settings.ActivePlayModeDataBuilder);
Debug.LogError(err);
if (BuildScript.buildCompleted != null)
{
var result = AddressableAssetBuildResult.CreateResult<AddressableAssetBuildResult>(null, 0, err);
BuildScript.buildCompleted(result);
}
return;
}
var res = settings.ActivePlayModeDataBuilder.BuildData<AddressablesPlayModeBuildResult>(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);
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a15f049c10fa744ca827575ffac1c0d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using UnityEditor.AddressableAssets.Settings;
using UnityEngine;
using UnityEngine.AddressableAssets;
namespace UnityEditor.AddressableAssets.Build
{
/// <summary>
/// Data builder context object for Addressables.
/// </summary>
public class AddressablesDataBuilderInput
{
/// <summary>
/// The main addressables settings object.
/// </summary>
public AddressableAssetSettings AddressableSettings { get; private set; }
/// <summary>
/// Build target group.
/// </summary>
public BuildTargetGroup TargetGroup { get; private set; }
/// <summary>
/// Build target.
/// </summary>
public BuildTarget Target { get; private set; }
/// <summary>
/// Player build version.
/// </summary>
public string PlayerVersion { get; private set; }
/// <summary>
/// Bool to signify if profiler events should be broadcast.
/// </summary>
public bool ProfilerEventsEnabled { get; private set; }
/// <summary>
/// Registry of files created during the build
/// </summary>
public FileRegistry Registry { get; private set; }
//used only by tests to inject custom info into build...
internal string PathFormat = string.Empty;
/// <summary>
/// The name of the default Runtime Settings file.
/// </summary>
public string RuntimeSettingsFilename = "settings.json";
/// <summary>
/// The name of the default Runtime Catalog file.
/// </summary>
public string RuntimeCatalogFilename = "catalog.json";
/// <summary>
/// Creates a default context object with values taken from the AddressableAssetSettings parameter.
/// </summary>
/// <param name="settings">The settings object to pull values from.</param>
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);
}
/// <summary>
/// Creates a default context object with values taken from the AddressableAssetSettings parameter.
/// </summary>
/// <param name="settings">The settings object to pull values from.</param>
/// <param name="playerBuildVersion">The player build version.</param>
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);
}
void SetAllValues(AddressableAssetSettings settings, BuildTargetGroup buildTargetGroup, BuildTarget buildTarget, string playerBuildVersion)
{
AddressableSettings = settings;
TargetGroup = buildTargetGroup;
Target = buildTarget;
PlayerVersion = playerBuildVersion;
ProfilerEventsEnabled = ProjectConfigData.postProfilerEvents;
Registry = new FileRegistry();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 69d3f19413a88324199b41186cf34b9f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.AddressableAssets.Build
{
/// <summary>
/// Contains information about the status of the build.
/// </summary>
public class AddressableAssetBuildResult : IDataBuilderResult
{
/// <summary>
/// Duration of build, in seconds.
/// </summary>
public double Duration { get; set; }
/// <summary>
/// The number of addressable assets contained in the build.
/// </summary>
public int LocationCount { get; set; }
/// <summary>
/// Error that caused the build to fail.
/// </summary>
public string Error { get; set; }
/// <summary>
/// Path of runtime settings file
/// </summary>
public string OutputPath { get; set; }
/// <summary>
/// Registry of files created during the build
/// </summary>
public FileRegistry FileRegistry { get; set; }
/// <summary>
/// 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.
/// </summary>
/// <param name="settingsPath">Path to the settings.json file (name may not always match that exactly) generated by this build</param>
/// <param name="locCount">Number of locations created by this build</param>
/// <param name="err">Error string if there were problems with the build. Defaults to empty</param>
/// <typeparam name="TResult">The actual build result created</typeparam>
/// <returns></returns>
public static TResult CreateResult<TResult>(string settingsPath, int locCount, string err = "") where TResult : IDataBuilderResult
{
var opResult = Activator.CreateInstance<TResult>();
opResult.OutputPath = settingsPath;
opResult.Duration = 0;
opResult.Error = err;
return opResult;
}
}
/// <summary>
/// Build result for entering play mode in the editor.
/// </summary>
[Serializable]
public class AddressablesPlayModeBuildResult : AddressableAssetBuildResult
{
}
/// <summary>
/// Build result for building the player.
/// </summary>
public class AddressablesPlayerBuildResult : AddressableAssetBuildResult
{
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1912c97b524efd244bc0647b18230c7e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,39 @@
using System.IO;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
using UnityEngine.AddressableAssets;
public class AddressablesPlayerBuildProcessor : IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
public int callbackOrder
{
get { return 1; }
}
public void OnPostprocessBuild(BuildReport report)
{
string addressablesStreamingAssets =
Application.streamingAssetsPath + "/" + Addressables.StreamingAssetsSubFolder;
if (Directory.Exists(Addressables.PlayerBuildDataPath))
{
Debug.Log(string.Format("Deleting Addressables data from {0}.", Addressables.PlayerBuildDataPath));
Directory.Delete(Addressables.PlayerBuildDataPath, true);
}
//Will delete the directory only if it's empty
DirectoryUtility.DeleteDirectory(addressablesStreamingAssets);
}
public void OnPreprocessBuild(BuildReport report)
{
if (Directory.Exists(Addressables.BuildPath))
{
Debug.Log(string.Format(
"Copying Addressables data from {0} to {1}. These copies will be deleted at the end of the build.",
Addressables.BuildPath, Addressables.PlayerBuildDataPath));
DirectoryUtility.DirectoryCopy(Addressables.BuildPath, Addressables.PlayerBuildDataPath, true);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 834e2bdb5fd1336429e26ec5bcbb77f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 7e7671decac0653418c193e1e9bc4d3e
guid: 85d34cd37047d904e847f7f5e2b1bd25
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.AddressableAssets.Build.AnalyzeRules
{
[Serializable]
public class AnalyzeResultData : ScriptableObject, ISerializationCallbackReceiver
{
[Serializable]
private class RuleToResults
{
[SerializeField] public string RuleName;
[SerializeField] public List<AnalyzeRule.AnalyzeResult> Results;
public RuleToResults(string ruleName, List<AnalyzeRule.AnalyzeResult> results)
{
RuleName = ruleName;
Results = results;
}
}
[SerializeField] private List<RuleToResults> m_RuleToResults = new List<RuleToResults>();
internal Dictionary<string, List<AnalyzeRule.AnalyzeResult>> Data =
new Dictionary<string, List<AnalyzeRule.AnalyzeResult>>();
public void OnAfterDeserialize()
{
for (int i = 0; i < m_RuleToResults.Count; i++)
Data.Add(m_RuleToResults[i].RuleName, m_RuleToResults[i].Results);
}
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();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: abc77607c2a62ef48b8f7dec55cc6d91
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using UnityEditor.AddressableAssets.Settings;
using UnityEngine;
namespace UnityEditor.AddressableAssets.Build.AnalyzeRules
{
/// <summary>
/// Base class for creating rules to analyze Addressables data. Use AnalyzeWindow.RegisterNewRule<T>() to register
/// a rule with the GUI window.
/// </summary>
[Serializable]
public class AnalyzeRule
{
/// <summary>
/// True if this rule can fix itself. If child class sets this to true, class must override FixIssues
/// </summary>
public virtual bool CanFix { get; set; }
[SerializeField]
internal List<AnalyzeResult> m_Results = new List<AnalyzeResult>();
[NonSerialized]
protected AnalyzeResult noErrors = new AnalyzeResult{resultName = "No issues found"};
/// <summary>
/// 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
/// </summary>
public const char kDelimiter = ':';
/// <summary>
/// Result data returned by rules.
/// </summary>
[Serializable]
public class AnalyzeResult
{
[SerializeField]
string m_ResultName;
/// <summary>
/// Name of result data. This name uses AnalyzeRule.kDelimiter to signify breaks in the tree display.
/// </summary>
public string resultName
{
get { return m_ResultName; }
set { m_ResultName = value; }
}
[SerializeField]
MessageType m_Severity = MessageType.None;
/// <summary>
/// Severity of rule result
/// </summary>
public MessageType severity
{
get { return m_Severity; }
set { m_Severity = value; }
}
}
/// <summary>
/// Display name for rule
/// </summary>
public virtual string ruleName
{
get { return GetType().ToString(); }
}
/// <summary>
/// This method runs the actual analysis for the rule.
/// </summary>
/// <param name="settings">The settings object to analyze</param>
/// <returns>A list of resulting information (warnings, errors, or info)</returns>
public virtual List<AnalyzeResult> RefreshAnalysis(AddressableAssetSettings settings)
{
return new List<AnalyzeResult>();
}
/// <summary>
/// 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.
/// </summary>
/// <param name="settings">The settings object to analyze</param>
public virtual void FixIssues(AddressableAssetSettings settings)
{
throw new NotImplementedException("FixIssues not implemented for class: '" + GetType() + "'.");
}
/// <summary>
/// Clears out the analysis results. When overriding, use to clear rule-specific data as well.
/// </summary>
public virtual void ClearAnalysis()
{
m_Results.Clear();
}
internal virtual void Revert()
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cfe8ad6aa7980734a89a782fcc937045
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,58 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.AddressableAssets.GUI;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.Build.Pipeline;
using UnityEditor.SceneManagement;
using UnityEngine;
namespace UnityEditor.AddressableAssets.Build.AnalyzeRules
{
class BuildBundleLayout : BundleRuleBase
{
public override bool CanFix { get{return false;} }
public override string ruleName { get {return "Build Bundle Layout";}}
public override List<AnalyzeResult> RefreshAnalysis(AddressableAssetSettings settings)
{
ClearAnalysis();
if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
{
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);
RefreshBuild(GetBuildContext(settings));
m_Results = (from bundleBuild in m_AllBundleInputDefs
let bundleName = bundleBuild.assetBundleName
from asset in bundleBuild.assetNames
select new AnalyzeResult { resultName = bundleName + kDelimiter + "Explicit" + kDelimiter + asset }).ToList();
m_Results.AddRange((from fileToBundle in m_ExtractData.WriteData.FileToBundle
from guid in GetImplicitGuidsForBundle(fileToBundle.Key)
let bundleName = fileToBundle.Value
let assetPath = AssetDatabase.GUIDToAssetPath(guid.ToString())
where AddressableAssetUtility.IsPathValidForEntry(assetPath)
select new AnalyzeResult { resultName = bundleName + kDelimiter + "Implicit" + kDelimiter + assetPath }).ToList());
if (m_Results.Count == 0)
m_Results.Add(noErrors);
return m_Results;
}
[InitializeOnLoad]
class RegisterBuildBundleLayout
{
static RegisterBuildBundleLayout()
{
AnalyzeWindow.RegisterNewRule<BuildBundleLayout>();
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d314656232cf1b24a9d7e6470f8f72eb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,269 @@
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.SceneManagement;
using UnityEngine;
using UnityEngine.AddressableAssets.Initialization;
using UnityEngine.AddressableAssets.ResourceLocators;
namespace UnityEditor.AddressableAssets.Build.AnalyzeRules
{
class BundleRuleBase : AnalyzeRule
{
[NonSerialized]
internal List<GUID> m_AddressableAssets = new List<GUID>();
[NonSerialized]
internal Dictionary<string, List<GUID>> m_ResourcesToDependencies = new Dictionary<string, List<GUID>>();
[NonSerialized]
internal readonly List<ContentCatalogDataEntry> m_Locations = new List<ContentCatalogDataEntry>();
[NonSerialized]
internal readonly List<AssetBundleBuild> m_AllBundleInputDefs = new List<AssetBundleBuild>();
[NonSerialized]
internal readonly Dictionary<string, string> m_BundleToAssetGroup = new Dictionary<string, string>();
[NonSerialized]
internal ExtractDataTask m_ExtractData = new ExtractDataTask();
internal IList<IBuildTask> RuntimeDataBuildTasks(string builtinShaderBundleName)
{
var buildTasks = new List<IBuildTask>();
// Setup
buildTasks.Add(new SwitchToBuildPlatform());
buildTasks.Add(new RebuildSpriteAtlasCache());
// Player Scripts
buildTasks.Add(new BuildPlayerScripts());
// Dependency
buildTasks.Add(new CalculateSceneDependencyData());
buildTasks.Add(new CalculateAssetDependencyData());
buildTasks.Add(new StripUnusedSpriteSources());
buildTasks.Add(new CreateBuiltInShadersBundle(builtinShaderBundleName));
// Packing
buildTasks.Add(new GenerateBundlePacking());
buildTasks.Add(new UpdateBundleObjectLayout());
buildTasks.Add(new GenerateBundleCommands());
buildTasks.Add(new GenerateSubAssetPathMaps());
buildTasks.Add(new GenerateBundleMaps());
return buildTasks;
}
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
};
return aaContext;
}
protected bool IsValidPath(string path)
{
return AddressableAssetUtility.IsPathValidForEntry(path) &&
!path.ToLower().Contains("/resources/") &&
!path.ToLower().StartsWith("resources/");
}
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);
buildTasks.Add(m_ExtractData);
IBundleBuildResults buildResults;
var exitCode = ContentPipeline.BuildAssetBundles(buildParams, new BundleBuildContent(m_AllBundleInputDefs),
out buildResults, buildTasks, buildContext);
GenerateLocationListsTask.Run(buildContext, m_ExtractData.WriteData);
return exitCode;
}
internal List<GUID> GetAllBundleDependencies()
{
var explicitGuids = m_ExtractData.WriteData.AssetToFiles.Keys;
var implicitGuids = GetImplicitGuidToFilesMap().Keys;
var allBundleGuids = explicitGuids.Union(implicitGuids);
return allBundleGuids.ToList();
}
internal void IntersectResourcesDepedenciesWithBundleDependencies(List<GUID> 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);
}
}
internal virtual void BuiltInResourcesToDependenciesMap(string[] resourcePaths)
{
foreach (string path in resourcePaths)
{
string[] dependencies = AssetDatabase.GetDependencies(path);
if (!m_ResourcesToDependencies.ContainsKey(path))
m_ResourcesToDependencies.Add(path, new List<GUID>());
m_ResourcesToDependencies[path].AddRange(from dependency in dependencies
select new GUID(AssetDatabase.AssetPathToGUID(dependency)));
}
}
internal void CalculateInputDefinitions(AddressableAssetSettings settings)
{
foreach (AddressableAssetGroup group in settings.groups)
{
if (group.HasSchema<BundledAssetGroupSchema>())
{
var schema = group.GetSchema<BundledAssetGroupSchema>();
List<AssetBundleBuild> bundleInputDefinitions = new List<AssetBundleBuild>();
BuildScriptPackedMode.PrepGroupBundlePacking(group, bundleInputDefinitions, m_Locations,
schema.BundleMode);
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);
}
}
}
internal AssetBundleBuild CreateUniqueBundle(AssetBundleBuild bid)
{
int count = 1;
var newName = bid.assetBundleName;
while (m_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
};
}
internal List<GUID> GetImplicitGuidsForBundle(string fileName)
{
List<GUID> guids = (from id in m_ExtractData.WriteData.FileToObjects[fileName]
where !m_ExtractData.WriteData.AssetToFiles.Keys.Contains(id.guid)
select id.guid).ToList();
return guids;
}
internal Dictionary<GUID, List<string>> GetImplicitGuidToFilesMap()
{
Dictionary<GUID, List<string>> implicitGuids = new Dictionary<GUID, List<string>>();
IEnumerable<KeyValuePair<ObjectIdentifier, string>> 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<ObjectIdentifier, string>(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<string>());
implicitGuids[objectIdToFile.Key.guid].Add(objectIdToFile.Value);
}
return implicitGuids;
}
internal List<AnalyzeResult> CalculateBuiltInResourceDependenciesToBundleDependecies(AddressableAssetSettings settings, string[] builtInResourcesPaths)
{
List<AnalyzeResult> results = new List<AnalyzeResult>();
if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
{
Debug.LogError("Cannot run Analyze with unsaved scenes");
results.Add(new AnalyzeResult{resultName = ruleName + "Cannot run Analyze with unsaved scenes"});
return results;
}
m_AddressableAssets = (from aaGroup in settings.groups
from entry in aaGroup.entries
select new GUID(entry.guid)).ToList();
BuiltInResourcesToDependenciesMap(builtInResourcesPaths);
CalculateInputDefinitions(settings);
var context = GetBuildContext(settings);
ReturnCode exitCode = RefreshBuild(context);
if (exitCode < ReturnCode.Success)
{
Debug.LogError("Analyze build failed. " + exitCode);
results.Add(new AnalyzeResult{resultName = ruleName + "Analyze build failed. " + exitCode});
return results;
}
IntersectResourcesDepedenciesWithBundleDependencies(GetAllBundleDependencies());
results = (from resource in m_ResourcesToDependencies.Keys
from dependency in m_ResourcesToDependencies[resource]
where m_ExtractData.WriteData.AssetToFiles.ContainsKey(dependency)
let assetPath = AssetDatabase.GUIDToAssetPath(dependency.ToString())
let files = m_ExtractData.WriteData.AssetToFiles[dependency]
from file in files
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;
}
public override void ClearAnalysis()
{
m_Locations.Clear();
m_AddressableAssets.Clear();
m_AllBundleInputDefs.Clear();
m_BundleToAssetGroup.Clear();
m_ResourcesToDependencies.Clear();
m_ExtractData = new ExtractDataTask();
base.ClearAnalysis();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8aae9ccc172d3fd48a20726e5c902489
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.AddressableAssets.Build.DataBuilders;
using UnityEditor.AddressableAssets.GUI;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEditor.Build.Pipeline;
using UnityEditor.SceneManagement;
using UnityEngine;
namespace UnityEditor.AddressableAssets.Build.AnalyzeRules
{
class CheckBundleDupeDependencies : BundleRuleBase
{
internal struct CheckDupeResult
{
public AddressableAssetGroup Group;
public List<string> DuplicatedFiles;
public string AssetPath;
public GUID DuplicatedGroupGuid;
}
public override bool CanFix
{
get { return true; }
}
public override string ruleName
{ get { return "Check Duplicate Bundle Dependencies"; } }
[NonSerialized]
internal readonly Dictionary<string, Dictionary<string, List<string>>> m_AllIssues = new Dictionary<string, Dictionary<string, List<string>>>();
[SerializeField]
internal HashSet<GUID> m_ImplicitAssets;
public override List<AnalyzeResult> RefreshAnalysis(AddressableAssetSettings settings)
{
ClearAnalysis();
return CheckForDuplicateDependencies(settings);
}
List<AnalyzeResult> CheckForDuplicateDependencies(AddressableAssetSettings settings)
{
if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
{
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 (m_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_Results = (from issueGroup in m_AllIssues
from bundle in issueGroup.Value
from item in bundle.Value
select new AnalyzeResult {resultName = ruleName + kDelimiter +
issueGroup.Key + kDelimiter +
bundle.Key + kDelimiter +
item, severity = MessageType.Warning}).ToList();
}
if (m_Results.Count == 0)
m_Results.Add(noErrors);
return m_Results;
}
internal IEnumerable<CheckDupeResult> CalculateDuplicates(Dictionary<GUID, List<string>> implicitGuids, AddressableAssetsBuildContext aaContext)
{
//Get all guids that have more than one bundle referencing them
IEnumerable<KeyValuePair<GUID, List<string>>> validGuids =
from dupeGuid in implicitGuids
where dupeGuid.Value.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 = m_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.Guid == bundleToGroup)
select new CheckDupeResult
{
Group = selectedGroup,
DuplicatedFiles = guidToFile.Value,
AssetPath = AssetDatabase.GUIDToAssetPath(guidToFile.Key.ToString()),
DuplicatedGroupGuid = guidToFile.Key
};
}
internal void BuildImplicitDuplicatedAssetsSet(IEnumerable<CheckDupeResult> checkDupeResults)
{
m_ImplicitAssets = new HashSet<GUID>();
foreach (var checkDupeResult in checkDupeResults)
{
Dictionary<string, List<string>> groupData;
if (!m_AllIssues.TryGetValue(checkDupeResult.Group.Name, out groupData))
{
groupData = new Dictionary<string, List<string>>();
m_AllIssues.Add(checkDupeResult.Group.Name, groupData);
}
foreach (string file in checkDupeResult.DuplicatedFiles)
{
List<string> assets;
if (!groupData.TryGetValue(m_ExtractData.WriteData.FileToBundle[file], out assets))
{
assets = new List<string>();
groupData.Add(m_ExtractData.WriteData.FileToBundle[file], assets);
}
assets.Add(checkDupeResult.AssetPath);
}
m_ImplicitAssets.Add(checkDupeResult.DuplicatedGroupGuid);
}
}
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<ContentUpdateGroupSchema>().StaticContent = true;
foreach (var asset in m_ImplicitAssets)
settings.CreateOrMoveEntry(asset.ToString(), group, false, false);
}
public override void ClearAnalysis()
{
m_AllIssues.Clear();
m_ImplicitAssets = null;
base.ClearAnalysis();
}
}
[InitializeOnLoad]
class RegisterCheckBundleDupeDependencies
{
static RegisterCheckBundleDupeDependencies()
{
AnalyzeWindow.RegisterNewRule<CheckBundleDupeDependencies>();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 327933a391986b441b4355cdd9257400
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor.AddressableAssets.GUI;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.Build.Pipeline;
using UnityEditor.SceneManagement;
using UnityEngine;
namespace UnityEditor.AddressableAssets.Build.AnalyzeRules
{
class CheckResourcesDupeDependencies : BundleRuleBase
{
public override bool CanFix
{
get { return false; }
}
public override string ruleName
{
get { return "Check Resources to Addressable Duplicate Dependencies"; }
}
public override List<AnalyzeResult> RefreshAnalysis(AddressableAssetSettings settings)
{
ClearAnalysis();
string[] resourceDirectory = Directory.GetDirectories("Assets", "Resources", SearchOption.AllDirectories);
List<string> resourcePaths = new List<string>();
foreach (string directory in resourceDirectory)
resourcePaths.AddRange(Directory.GetFiles(directory, "*", SearchOption.AllDirectories));
return CalculateBuiltInResourceDependenciesToBundleDependecies(settings, resourcePaths.ToArray());
}
public override void FixIssues(AddressableAssetSettings settings)
{
//Do nothing. There's nothing to fix.
}
}
[InitializeOnLoad]
class RegisterCheckResourcesDupeDependencies
{
static RegisterCheckResourcesDupeDependencies()
{
AnalyzeWindow.RegisterNewRule<CheckResourcesDupeDependencies>();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 555da02c9c624644c9695f325ea6a22c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,47 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor.AddressableAssets.GUI;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.Build.Pipeline;
using UnityEditor.SceneManagement;
using UnityEngine;
namespace UnityEditor.AddressableAssets.Build.AnalyzeRules
{
class CheckSceneDupeDependencies : BundleRuleBase
{
public override bool CanFix
{
get { return false; }
}
public override string ruleName
{
get { return "Check Scene to Addressable Duplicate Dependencies"; }
}
public override List<AnalyzeResult> RefreshAnalysis(AddressableAssetSettings settings)
{
ClearAnalysis();
string[] scenePaths = (from editorScene in EditorBuildSettings.scenes
select editorScene.path).ToArray();
return CalculateBuiltInResourceDependenciesToBundleDependecies(settings, scenePaths);
}
public override void FixIssues(AddressableAssetSettings settings)
{
//Do nothing. There's nothing to fix.
}
}
[InitializeOnLoad]
class RegisterCheckSceneDupeDependencies
{
static RegisterCheckSceneDupeDependencies()
{
AnalyzeWindow.RegisterNewRule<CheckSceneDupeDependencies>();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bd1bea4352ab4fb49a0d15da275cd26d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2e63e5dd2cdcb394984e15b78da0a927
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,53 @@
using System;
using UnityEditor.Build.Pipeline;
using UnityEditor.Build.Pipeline.Injector;
using UnityEditor.Build.Pipeline.Interfaces;
namespace UnityEditor.AddressableAssets.Build.BuildPipelineTasks
{
/// <summary>
/// The BuildTask used to extract write data from the build.
/// </summary>
public class ExtractDataTask : IBuildTask
{
/// <summary>
/// The ExtractDataTask version.
/// </summary>
public int Version { get { return 1; } }
/// <summary>
/// Get the injected dependency data of the task.
/// </summary>
public IDependencyData DependencyData { get { return m_DependencyData; } }
/// <summary>
/// Get the injected write data of the task.
/// </summary>
public IBundleWriteData WriteData { get { return m_WriteData; } }
/// <summary>
/// Get the injected build cache of the task.
/// </summary>
public IBuildCache BuildCache { get { return m_BuildCache; } }
#pragma warning disable 649
[InjectContext(ContextUsage.In)]
IDependencyData m_DependencyData;
[InjectContext(ContextUsage.In)]
IBundleWriteData m_WriteData;
[InjectContext(ContextUsage.In)]
IBuildCache m_BuildCache;
#pragma warning restore 649
/// <summary>
/// Runs the ExtractDataTask. The data for this task is all injected context so no operations are performed in the Run step.
/// </summary>
/// <returns>Success.</returns>
public ReturnCode Run()
{
return ReturnCode.Success;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9dafe60ff4149624880b04d0cea88719
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,153 @@
using System;
using System.Collections.Generic;
using UnityEditor.AddressableAssets.Build.DataBuilders;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
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;
using UnityEngine.ResourceManagement.ResourceProviders;
namespace UnityEditor.AddressableAssets.Build.BuildPipelineTasks
{
/// <summary>
/// The BuildTask used to create location lists for Addressable assets.
/// </summary>
public class GenerateLocationListsTask : IBuildTask
{
const int k_Version = 1;
/// <summary>
/// The GenerateLocationListsTask version.
/// </summary>
public int Version { get { return k_Version; } }
#pragma warning disable 649
[InjectContext(ContextUsage.In)]
IAddressableAssetsBuildContext m_AaBuildContext;
[InjectContext]
IBundleWriteData m_WriteData;
#pragma warning restore 649
/// <summary>
/// Runs the build task with the injected context.
/// </summary>
/// <returns>The success or failure ReturnCode</returns>
public ReturnCode Run()
{
return Run(m_AaBuildContext, m_WriteData);
}
/// <summary>
/// Runs the build task with a give context and write data.
/// </summary>
/// <param name="aaBuildContext">The addressables build context.</param>
/// <param name="writeData">The write data used to generate the location lists.</param>
/// <returns>The success or failure ReturnCode</returns>
public static ReturnCode Run(IAddressableAssetsBuildContext aaBuildContext, IBundleWriteData writeData)
{
var aaContext = aaBuildContext as AddressableAssetsBuildContext;
if (aaContext == null)
return ReturnCode.Error;
var aaSettings = aaContext.settings;
var locations = aaContext.locations;
var bundleToAssetGroup = aaContext.bundleToAssetGroup;
var bundleToAssets = new Dictionary<string, List<GUID>>();
var dependencySetForBundle = new Dictionary<string, HashSet<string>>();
foreach (var k in writeData.AssetToFiles)
{
List<GUID> assetList;
var bundle = writeData.FileToBundle[k.Value[0]];
if (!bundleToAssets.TryGetValue(bundle, out assetList))
bundleToAssets.Add(bundle, assetList = new List<GUID>());
HashSet<string> bundleDeps;
if (!dependencySetForBundle.TryGetValue(bundle, out bundleDeps))
dependencySetForBundle.Add(bundle, bundleDeps = new HashSet<string>());
for (int i = 0; i < k.Value.Count; i++)
bundleDeps.Add(writeData.FileToBundle[k.Value[i]]);
foreach (var file in k.Value)
{
var fileBundle = writeData.FileToBundle[file];
if (!bundleToAssets.ContainsKey(fileBundle))
bundleToAssets.Add(fileBundle, new List<GUID>());
}
assetList.Add(k.Key);
}
var assetGroupToBundle = (aaContext.assetGroupToBundles = new Dictionary<AddressableAssetGroup, List<string>>());
foreach (var kvp in bundleToAssets)
{
AddressableAssetGroup assetGroup = aaSettings.DefaultGroup;
string groupGuid;
if (bundleToAssetGroup.TryGetValue(kvp.Key, out groupGuid))
assetGroup = aaSettings.FindGroup(g => g.Guid == groupGuid);
List<string> bundles;
if (!assetGroupToBundle.TryGetValue(assetGroup, out bundles))
assetGroupToBundle.Add(assetGroup, bundles = new List<string>());
bundles.Add(kvp.Key);
HashSet<string> bundleDeps = null;
dependencySetForBundle.TryGetValue(kvp.Key, out bundleDeps);
CreateResourceLocationData(assetGroup, kvp.Key, GetLoadPath(assetGroup, kvp.Key), GetBundleProviderName(assetGroup), GetAssetProviderName(assetGroup), kvp.Value, bundleDeps, locations);
}
return ReturnCode.Success;
}
static string GetBundleProviderName(AddressableAssetGroup group)
{
return group.GetSchema<BundledAssetGroupSchema>().GetBundleCachedProviderId();
}
static string GetAssetProviderName(AddressableAssetGroup group)
{
return group.GetSchema<BundledAssetGroupSchema>().GetAssetCachedProviderId();
}
static string GetLoadPath(AddressableAssetGroup group, string name)
{
var bagSchema = group.GetSchema<BundledAssetGroupSchema>();
if (bagSchema == null || bagSchema.LoadPath == null)
{
Debug.LogError("Unable to determine load path for " + name + ". Check that your default group is not '" + AddressableAssetSettings.PlayerDataGroupName + "'");
return string.Empty;
}
var loadPath = bagSchema.LoadPath.GetValue(group.Settings) + "/" + name;
if(!string.IsNullOrEmpty(bagSchema.UrlSuffix))
loadPath += bagSchema.UrlSuffix;
return loadPath;
}
internal static void CreateResourceLocationData(
AddressableAssetGroup assetGroup,
string bundleName,
string bundleInternalId,
string bundleProvider,
string assetProvider,
List<GUID> assetsInBundle,
HashSet<string> bundleDependencies,
List<ContentCatalogDataEntry> locations)
{
locations.Add(new ContentCatalogDataEntry(typeof(IAssetBundleResource), bundleInternalId, bundleProvider, new object[] { bundleName }));
var assets = new List<AddressableAssetEntry>();
assetGroup.GatherAllAssets(assets, true, true);
var guidToEntry = new Dictionary<string, AddressableAssetEntry>();
foreach (var a in assets)
guidToEntry.Add(a.guid, a);
foreach (var a in assetsInBundle)
{
AddressableAssetEntry entry;
if (!guidToEntry.TryGetValue(a.ToString(), out entry))
continue;
entry.CreateCatalogEntries(locations, true, assetProvider, bundleDependencies, null);
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b19f99025db4a1e44a095aa3f1284c54
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,55 @@
using System.Collections.Generic;
using System.IO;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEditor.Compilation;
namespace UnityEditor.AddressableAssets.Build
{
internal class BuildUtility
{
static HashSet<string> s_EditorAssemblies = null;
static HashSet<string> editorAssemblies
{
get
{
if (s_EditorAssemblies == null)
{
s_EditorAssemblies = new HashSet<string>();
foreach (var assembly in CompilationPipeline.GetAssemblies())
{
if ((assembly.flags & AssemblyFlags.EditorAssembly) != 0)
s_EditorAssemblies.Add(assembly.name);
}
}
return s_EditorAssemblies;
}
}
public static bool IsEditorAssembly(System.Reflection.Assembly assembly)
{
var splitName = assembly.FullName.Split(',');
return splitName.Length > 0 && editorAssemblies.Contains(splitName[0]);
}
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:
string fileName = Path.GetFileNameWithoutExtension(sourceBundleName);
if(!string.IsNullOrEmpty(fileName))
result = sourceBundleName.Replace(fileName, hash);
break;
}
return result;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: befd95e3f3af5eb49bf7c53d00cb4d44
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,437 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEngine;
using UnityEngine.AddressableAssets;
namespace UnityEditor.AddressableAssets.Build
{
[Serializable]
struct AssetState : IEquatable<AssetState>
{
public GUID guid;
public Hash128 hash;
public bool Equals(AssetState other)
{
return guid == other.guid && hash == other.hash;
}
}
[Serializable]
class CachedAssetState : IEquatable<CachedAssetState>
{
public AssetState asset;
public AssetState[] dependencies;
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;
}
}
/// <summary>
/// Data stored with each build that is used to generated content updates.
/// </summary>
[Serializable]
class AddressablesContentState
{
/// <summary>
/// The version that the player was built with. This is usually set to AddressableAssetSettings.PlayerBuildVersion.
/// </summary>
[SerializeField]
public string playerVersion;
/// <summary>
/// The version of the unity editor used to build the player.
/// </summary>
[SerializeField]
public string editorVersion;
/// <summary>
/// Dependency information for all assets in the build that have been marked StaticContent.
/// </summary>
[SerializeField]
public CachedAssetState[] cachedInfos;
/// <summary>
/// The path of a remote catalog. This is the only place the player knows to look for an updated catalog.
/// </summary>
[SerializeField]
public string remoteCatalogLoadPath;
}
/// <summary>
/// Contains methods used for the content update workflow.
/// </summary>
public static class ContentUpdateScript
{
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, IEnumerable<GUID> dependencies, out CachedAssetState cachedAssetState)
{
cachedAssetState = null;
AssetState assetState;
if (!GetAssetState(asset, out assetState))
return false;
var visited = new HashSet<GUID>();
visited.Add(asset);
var dependencyStates = new List<AssetState>();
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();
return true;
}
static bool HasAssetOrDependencyChanged(CachedAssetState cachedInfo)
{
CachedAssetState newCachedInfo;
if (!GetCachedAssetStateForData(cachedInfo.asset.guid, cachedInfo.dependencies.Select(x => x.guid), out newCachedInfo))
return true;
return !cachedInfo.Equals(newCachedInfo);
}
/// <summary>
/// Save the content update information for a set of AddressableAssetEntry objects.
/// </summary>
/// <param name="path">File to write content stat info to. If file already exists, it will be deleted before the new file is created.</param>
/// <param name="entries">The entries to save.</param>
/// <param name="dependencyData">The raw dependency information generated from the build.</param>
/// <param name="playerVersion">The player version to save. This is usually set to AddressableAssetSettings.PlayerBuildVersion.</param>
/// <param name="remoteCatalogPath">The server path (if any) that contains an updateable content catalog. If this is empty, updates cannot occur.</param>
/// <returns>True if the file is saved, false otherwise.</returns>
public static bool SaveContentState(string path, List<AddressableAssetEntry> entries, IDependencyData dependencyData, string playerVersion, string remoteCatalogPath)
{
try
{
IList<CachedAssetState> cachedInfos = new List<CachedAssetState>();
foreach (var assetData in dependencyData.AssetInfo)
{
CachedAssetState cachedAssetState;
if (GetCachedAssetStateForData(assetData.Key, assetData.Value.referencedObjects.Select(x => x.guid), out cachedAssetState))
cachedInfos.Add(cachedAssetState);
}
foreach (var sceneData in dependencyData.SceneInfo)
{
CachedAssetState cachedAssetState;
if (GetCachedAssetStateForData(sceneData.Key, sceneData.Value.referencedObjects.Select(x => x.guid), out cachedAssetState))
cachedInfos.Add(cachedAssetState);
}
var cacheData = new AddressablesContentState
{
cachedInfos = cachedInfos.ToArray(),
playerVersion = playerVersion,
editorVersion = Application.unityVersion,
remoteCatalogLoadPath = remoteCatalogPath
};
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 (Exception e)
{
Debug.LogException(e);
return false;
}
}
/// <summary>
/// Gets the path of the cache data from a selected build.
/// </summary>
/// <param name="browse">If true, the user is allowed to browse for a specific file.</param>
/// <returns></returns>
public static string GetContentStateDataPath(bool browse)
{
var assetPath = AddressableAssetSettingsDefaultObject.kDefaultConfigFolder;
if (AddressableAssetSettingsDefaultObject.Settings != null)
assetPath = AddressableAssetSettingsDefaultObject.Settings.ConfigFolder;
assetPath = Path.Combine(assetPath, PlatformMappingService.GetPlatform().ToString());
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;
}
Directory.CreateDirectory(assetPath);
var path = Path.Combine(assetPath, "addressables_content_state.bin");
return path;
}
/// <summary>
/// Loads cache data from a specific location
/// </summary>
/// <param name="contentStateDataPath"></param>
/// <returns></returns>
internal 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;
}
return cacheData;
}
static bool s_StreamingAssetsExists;
static string kStreamingAssetsPath = "Assets/StreamingAssets";
internal static void Cleanup(bool deleteStreamingAssetsFolderIfEmpty)
{
if (Directory.Exists(Addressables.BuildPath))
{
Directory.Delete(Addressables.BuildPath, true);
if (File.Exists(Addressables.BuildPath + ".meta"))
File.Delete(Addressables.BuildPath + ".meta");
}
if (deleteStreamingAssetsFolderIfEmpty)
{
if (Directory.Exists(kStreamingAssetsPath))
{
var files = Directory.GetFiles(kStreamingAssetsPath);
if (files.Length == 0)
{
Directory.Delete(kStreamingAssetsPath);
if (File.Exists(kStreamingAssetsPath + ".meta"))
File.Delete(kStreamingAssetsPath + ".meta");
}
}
}
}
/// <summary>
/// Builds player content using the player content version from a specified cache file.
/// </summary>
/// <param name="settings">The settings object to use for the build.</param>
/// <param name="contentStateDataPath">The path of the cache data to use.</param>
/// <returns>The build operation.</returns>
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);
Cleanup(!s_StreamingAssetsExists);
SceneManagerState.Record();
var result = settings.ActivePlayerDataBuilder.BuildData<AddressablesPlayerBuildResult>(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;
}
/// <summary>
/// Get all modified addressable asset entries in groups that have BundledAssetGroupSchema and ContentUpdateGroupSchema with static content enabled.
/// </summary>
/// <param name="settings">Addressable asset settings.</param>
/// <param name="cacheDataPath">The cache data path.</param>
/// <returns>A list of all modified entries (list is empty if there are none); null if failed to load cache data.</returns>
//temporarily switched back to internal for 1.1.x releases. Will be public in 1.2+
//public static List<AddressableAssetEntry> GatherModifiedEntries(AddressableAssetSettings settings, string cacheDataPath)
internal static List<AddressableAssetEntry> GatherModifiedEntries(AddressableAssetSettings settings, string cacheDataPath)
{
var cacheData = LoadContentState(cacheDataPath);
if (cacheData == null)
{
return null;
}
List<string> noBundledAssetGroupSchema = new List<string>();
List<string> noStaticContent = new List<string>();
var allEntries = new List<AddressableAssetEntry>();
settings.GetAllAssets(allEntries, g =>
{
if (!g.HasSchema<BundledAssetGroupSchema>())
{
noBundledAssetGroupSchema.Add(g.Name);
return false;
}
if (!g.HasSchema<ContentUpdateGroupSchema>())
{
noStaticContent.Add(g.Name);
return false;
}
if (!g.GetSchema<ContentUpdateGroupSchema>().StaticContent)
{
noStaticContent.Add(g.Name);
return 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<string, CachedAssetState>();
foreach (var cacheInfo in cacheData.cachedInfos)
if (cacheInfo != null)
entryToCacheInfo[cacheInfo.asset.guid.ToString()] = cacheInfo;
var modifiedEntries = new List<AddressableAssetEntry>();
foreach (var entry in allEntries)
{
CachedAssetState cachedInfo;
if (!entryToCacheInfo.TryGetValue(entry.guid, out cachedInfo) || HasAssetOrDependencyChanged(cachedInfo))
modifiedEntries.Add(entry);
}
return modifiedEntries;
}
private static void AddInvalidGroupsToLogMessage(StringBuilder builder, List<string> 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("");
}
}
/// <summary>
/// Create a new AddressableAssetGroup with the items and mark it as remote.
/// </summary>
/// <param name="settings">The settings object.</param>
/// <param name="items">The items to move.</param>
/// <param name="groupName">The name of the new group.</param>
public static void CreateContentUpdateGroup(AddressableAssetSettings settings, List<AddressableAssetEntry> items, string groupName)
{
var contentGroup = settings.CreateGroup(settings.FindUniqueGroupName(groupName), false, false, true, null);
var schema = contentGroup.AddSchema<BundledAssetGroupSchema>();
schema.BuildPath.SetVariableByName(settings, AddressableAssetSettings.kRemoteBuildPath);
schema.LoadPath.SetVariableByName(settings, AddressableAssetSettings.kRemoteLoadPath);
schema.BundleMode = BundledAssetGroupSchema.BundlePackingMode.PackTogether;
contentGroup.AddSchema<ContentUpdateGroupSchema>().StaticContent = false;
settings.MoveEntries(items, contentGroup);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 36e2ba320a6ae3e4596bd1fe59b4fe21
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.AddressableAssets.Build
{
/// <summary>
/// The result of IDataBuilder.Build.
/// </summary>
public interface IDataBuilderResult
{
/// <summary>
/// Duration of the build in seconds.
/// </summary>
double Duration { get; set; }
/// <summary>
/// Error string, if any. If Succeeded is true, this may be null.
/// </summary>
string Error { get; set; }
/// <summary>
/// Path of runtime settings file
/// </summary>
string OutputPath { get; set; }
/// <summary>
/// Registry of files created during the build
/// </summary>
FileRegistry FileRegistry { get; set; }
}
/// <summary>
/// Builds objects of type IDataBuilderResult.
/// </summary>
public interface IDataBuilder
{
/// <summary>
/// The name of the builder, used for GUI.
/// </summary>
string Name { get; }
/// <summary>
/// Can this builder build the type of data requested.
/// </summary>
/// <typeparam name="T">The data type.</typeparam>
/// <returns>True if the build can build it.</returns>
bool CanBuildData<T>() where T : IDataBuilderResult;
/// <summary>
/// Build the data of a specific type.
/// </summary>
/// <typeparam name="TResult">The data type.</typeparam>
/// <param name="builderInput">The builderInput used to build the data.</param>
/// <returns>The built data.</returns>
TResult BuildData<TResult>(AddressablesDataBuilderInput builderInput) where TResult : IDataBuilderResult;
/// <summary>
/// Clears all cached data.
/// </summary>
void ClearCachedData();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 732aa8bf67ed2de438b3f2f56850c43e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5064f4f2812f9e741be2105c6c338f98
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,26 @@
using System.Collections.Generic;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEngine.AddressableAssets.Initialization;
using UnityEngine.AddressableAssets.ResourceLocators;
namespace UnityEditor.AddressableAssets.Build.DataBuilders
{
/// <summary>
/// Interface for any Addressables specific context objects to be used in the Scriptable Build Pipeline context store
/// </summary>
public interface IAddressableAssetsBuildContext : IContextObject { }
/// <summary>
/// Simple context object for passing data through SBP, between different sections of Addressables code.
/// </summary>
public class AddressableAssetsBuildContext : IAddressableAssetsBuildContext
{
public AddressableAssetSettings settings;
public ResourceManagerRuntimeData runtimeData;
public List<ContentCatalogDataEntry> locations;
public Dictionary<string, string> bundleToAssetGroup;
public Dictionary<AddressableAssetGroup, List<string>> assetGroupToBundles;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bdd672a655042ae4fa4c3f8c8d8853a6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,83 @@
using System.Collections.Generic;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEditor.Build.Pipeline;
using UnityEngine;
namespace UnityEditor.AddressableAssets.Build.DataBuilders
{
/// <summary>
/// Custom bundle parameter container that provides custom compression settings per bundle.
/// </summary>
public class AddressableAssetsBundleBuildParameters : BundleBuildParameters
{
Dictionary<string, string> m_bundleToAssetGroup;
AddressableAssetSettings m_settings;
/// <summary>
/// Create a AddressableAssetsBundleBuildParameters with data needed to determine the correct compression per bundle.
/// </summary>
/// <param name="aaSettings">The AddressableAssetSettings object to use for retrieving groups.</param>
/// <param name="bundleToAssetGroup">Mapping of bundle identifier to guid of asset groups.</param>
/// <param name="target">The build target. This is used by the BundleBuildParameters base class.</param>
/// <param name="group">The build target group. This is used by the BundleBuildParameters base class.</param>
/// <param name="outputFolder">The path for the output folder. This is used by the BundleBuildParameters base class.</param>
public AddressableAssetsBundleBuildParameters(AddressableAssetSettings aaSettings, Dictionary<string, string> bundleToAssetGroup, BuildTarget target, BuildTargetGroup group, string outputFolder) : base(target, group, outputFolder)
{
UseCache = true;
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<BundledAssetGroupSchema>())
BundleCompression = ConverBundleCompressiontToBuildCompression(m_settings.DefaultGroup.GetSchema<BundledAssetGroupSchema>().Compression);
else
BundleCompression = target == BuildTarget.WebGL ? BuildCompression.LZ4Runtime : BuildCompression.LZMA;
}
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;
}
/// <summary>
/// Get the compressions settings for the specified asset bundle.
/// </summary>
/// <param name="identifier">The identifier of the asset bundle.</param>
/// <returns>The compression setting for the asset group. If the group is not found, the default compression is used.</returns>
public override BuildCompression GetCompressionForIdentifier(string identifier)
{
string groupGuid;
if (m_bundleToAssetGroup.TryGetValue(identifier, out groupGuid))
{
var group = m_settings.FindGroup(g => g.Guid == groupGuid);
if (group != null)
{
var abSchema = group.GetSchema<BundledAssetGroupSchema>();
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);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e4e9f0f7eaff4094990720ec2b944faf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,212 @@
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEngine;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.ResourceManagement.Util;
using UnityEngine.Serialization;
namespace UnityEditor.AddressableAssets.Build.DataBuilders
{
/// <summary>
/// Base class for build script assets
/// </summary>
public class BuildScriptBase : ScriptableObject, IDataBuilder
{
/// <summary>
/// The type of instance provider to create for the Addressables system.
/// </summary>
[FormerlySerializedAs("m_InstanceProviderType")]
[SerializedTypeRestrictionAttribute(type = typeof(IInstanceProvider))]
public SerializedType instanceProviderType = new SerializedType() { Value = typeof(InstanceProvider) };
/// <summary>
/// The type of scene provider to create for the addressables system.
/// </summary>
[FormerlySerializedAs("m_SceneProviderType")]
[SerializedTypeRestrictionAttribute(type = typeof(ISceneProvider))]
public SerializedType sceneProviderType = new SerializedType() { Value = typeof(SceneProvider) };
/// <summary>
/// The descriptive name used in the UI.
/// </summary>
public virtual string Name
{
get
{
return "Undefined";
}
}
/// <summary>
/// Build the specified data with the provided builderInput. This is the public entry point.
/// Child class overrides should use <see cref="BuildDataImplementation{TResult}"/>
/// </summary>
/// <typeparam name="TResult">The type of data to build.</typeparam>
/// <param name="builderInput">The builderInput object used in the build.</param>
/// <returns>The build data result.</returns>
public TResult BuildData<TResult>(AddressablesDataBuilderInput builderInput) where TResult : IDataBuilderResult
{
if (!CanBuildData<TResult>())
{
var message = "Data builder " + Name + " cannot build requested type: " + typeof(TResult);
Debug.LogError(message);
return AddressableAssetBuildResult.CreateResult<TResult>(null, 0, message);
}
// Append the file registry to the results
var result = BuildDataImplementation<TResult>(builderInput);
if (result != null)
result.FileRegistry = builderInput.Registry;
return result;
}
/// <summary>
/// The implementation of <see cref="BuildData{TResult}"/>. That is the public entry point,
/// this is the home for child class overrides.
/// </summary>
/// <param name="builderInput">The builderInput object used in the build</param>
/// <typeparam name="TResult">The type of data to build</typeparam>
/// <returns>The build data result</returns>
protected virtual TResult BuildDataImplementation<TResult>(AddressablesDataBuilderInput builderInput) where TResult : IDataBuilderResult
{
return default(TResult);
}
/// <summary>
/// Loops over each group, after doing some data checking.
/// </summary>
/// <param name="aaContext">The Addressables builderInput object to base the group processing on</param>
/// <returns>An error string if there were any problems processing the groups</returns>
protected virtual string ProcessAllGroups(AddressableAssetsBuildContext aaContext)
{
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];
var errorString = ProcessGroup(assetGroup, aaContext);
if(!string.IsNullOrEmpty(errorString))
return errorString;
}
return string.Empty;
}
/// <summary>
/// Build processing of an individual group.
/// </summary>
/// <param name="assetGroup">The group to process</param>
/// <param name="aaContext">The Addressables builderInput object to base the group processing on</param>
/// <returns>An error string if there were any problems processing the groups</returns>
protected virtual string ProcessGroup(AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext)
{
return string.Empty;
}
/// <summary>
/// Used to determine if this builder is capable of building a specific type of data.
/// </summary>
/// <typeparam name="T">The type of data needed to be built.</typeparam>
/// <returns>True if this builder can build this data.</returns>
public virtual bool CanBuildData<T>() where T : IDataBuilderResult
{
return false;
}
/// <summary>
/// Utility method for creating locations from player data.
/// </summary>
/// <param name="assetGroup">The group to extract the locations from.</param>
/// <param name="locations">The list of created locations to fill in.</param>
/// <returns>True if any legacy locations were created. This is used by the build scripts to determine if a legacy provider is needed.</returns>
protected bool CreateLocationsForPlayerData(PlayerDataGroupSchema playerDataSchema, AddressableAssetGroup assetGroup, List<ContentCatalogDataEntry> locations)
{
bool needsLegacyProvider = false;
if (playerDataSchema != null && (playerDataSchema.IncludeBuildSettingsScenes || playerDataSchema.IncludeResourcesFolders))
{
var entries = new List<AddressableAssetEntry>();
assetGroup.GatherAllAssets(entries, true, true);
foreach (var a in entries)
{
if (!playerDataSchema.IncludeBuildSettingsScenes && a.IsInSceneList)
continue;
if (!playerDataSchema.IncludeResourcesFolders && a.IsInResources)
continue;
a.CreateCatalogEntries(locations, false, a.IsScene ? "" : typeof(LegacyResourcesProvider).FullName, null, null);
if (!a.IsScene)
needsLegacyProvider = true;
}
}
return needsLegacyProvider;
}
/// <summary>
/// Utility method for deleting files.
/// </summary>
/// <param name="path">The file path to delete.</param>
protected static void DeleteFile(string path)
{
try
{
if (File.Exists(path))
File.Delete(path);
}
catch (Exception ex)
{
Debug.LogException(ex);
}
}
/// <summary>
/// Utility method to write a file. The directory will be created if it does not exist.
/// </summary>
/// <param name="path">The path of the file to write.</param>
/// <param name="content">The content of the file.</param>
/// <param name="registry">The file registry used to track all produced artifacts.</param>
/// <returns>True if the file was written.</returns>
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;
}
}
/// <summary>
/// Used to clean up any cached data created by this builder.
/// </summary>
public virtual void ClearCachedData()
{
}
/// <summary>
/// Checks to see if the data is built for the given builder.
/// </summary>
public virtual bool IsDataBuilt()
{
return false;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8559dec58f92398448ea2ea83fd63c3e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.Initialization;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.AddressableAssets.ResourceProviders;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.ResourceManagement.Util;
namespace UnityEditor.AddressableAssets.Build.DataBuilders
{
/// <summary>
/// Build script used for fast iteration in the editor.
/// </summary>
[CreateAssetMenu(fileName = "BuildScriptFast.asset", menuName = "Addressable Assets/Data Builders/Fast Mode")]
public class BuildScriptFastMode : BuildScriptBase
{
/// <inheritdoc />
public override string Name
{
get
{
return "Fast Mode";
}
}
/// <inheritdoc />
public override bool CanBuildData<T>()
{
return typeof(T).IsAssignableFrom(typeof(AddressablesPlayModeBuildResult));
}
/// <inheritdoc />
public override void ClearCachedData()
{
DeleteFile(string.Format(PathFormat, "", "catalog"));
DeleteFile(string.Format(PathFormat, "", "settings"));
}
/// <inheritdoc />
public override bool IsDataBuilt()
{
var catalogPath = string.Format(PathFormat, "", "catalog");
var settingsPath = string.Format(PathFormat, "", "settings");
return File.Exists(catalogPath) &&
File.Exists(settingsPath);
}
private string m_PathFormatStore;
private string PathFormat
{
get
{
if(string.IsNullOrEmpty(m_PathFormatStore))
m_PathFormatStore = "{0}Library/com.unity.addressables/{1}_BuildScriptFastMode.json";
return m_PathFormatStore;
}
set { m_PathFormatStore = value; }
}
bool m_NeedsLegacyProvider = false;
/// <inheritdoc />
protected override TResult BuildDataImplementation<TResult>(AddressablesDataBuilderInput context)
{
TResult result = default(TResult);
var timer = new Stopwatch();
timer.Start();
var aaSettings = context.AddressableSettings;
PathFormat = context.PathFormat;
//create runtime data
var aaContext = new AddressableAssetsBuildContext
{
settings = aaSettings,
runtimeData = new ResourceManagerRuntimeData(),
bundleToAssetGroup = null,
locations = new List<ContentCatalogDataEntry>()
};
aaContext.runtimeData.BuildTarget = context.Target.ToString();
aaContext.runtimeData.LogResourceManagerExceptions = aaSettings.buildSettings.LogResourceManagerExceptions;
aaContext.runtimeData.ProfileEvents = ProjectConfigData.postProfilerEvents;
aaContext.runtimeData.CatalogLocations.Add(new ResourceLocationData(new[] { ResourceManagerRuntimeData.kCatalogAddress }, string.Format(PathFormat, "file://{UnityEngine.Application.dataPath}/../", "catalog"), typeof(ContentCatalogProvider), typeof(ContentCatalogData)));
var errorString = ProcessAllGroups(aaContext);
if(!string.IsNullOrEmpty(errorString))
result = AddressableAssetBuildResult.CreateResult<TResult>(null, 0, errorString);
if (result == null)
{
foreach (var io in aaSettings.InitializationObjects)
{
if (io is IObjectInitializationDataProvider)
aaContext.runtimeData.InitializationObjects.Add((io as IObjectInitializationDataProvider).CreateObjectInitializationData());
}
var settingsPath = string.Format(PathFormat, "", "settings");
WriteFile(settingsPath, JsonUtility.ToJson(aaContext.runtimeData), context.Registry);
//save catalog
var catalogData = new ContentCatalogData(aaContext.locations);
if (m_NeedsLegacyProvider)
catalogData.ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(typeof(LegacyResourcesProvider)));
catalogData.ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData<AssetDatabaseProvider>());
catalogData.InstanceProviderData = ObjectInitializationData.CreateSerializedInitializationData(instanceProviderType.Value);
catalogData.SceneProviderData = ObjectInitializationData.CreateSerializedInitializationData(sceneProviderType.Value);
WriteFile(string.Format(PathFormat, "", "catalog"), JsonUtility.ToJson(catalogData), context.Registry);
//inform runtime of the init data path
var runtimeSettingsPath = string.Format(PathFormat, "file://{UnityEngine.Application.dataPath}/../", "settings");
PlayerPrefs.SetString(Addressables.kAddressablesRuntimeDataPath, runtimeSettingsPath);
result = AddressableAssetBuildResult.CreateResult<TResult>(settingsPath, aaContext.locations.Count);
}
if(result != null)
result.Duration = timer.Elapsed.TotalSeconds;
return result;
}
/// <inheritdoc />
protected override string ProcessGroup(AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext)
{
var errorString = string.Empty;
PlayerDataGroupSchema playerSchema = assetGroup.GetSchema<PlayerDataGroupSchema>();
if (playerSchema != null)
{
m_NeedsLegacyProvider = CreateLocationsForPlayerData(playerSchema, assetGroup, aaContext.locations);
return errorString;
}
var allEntries = new List<AddressableAssetEntry>();
foreach (var a in assetGroup.entries)
a.GatherAllAssets(allEntries, true, true);
var providerType = typeof(AssetDatabaseProvider).FullName;
foreach (var a in allEntries)
a.CreateCatalogEntries(aaContext.locations, false, providerType, null, null);
return errorString;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 88d21199f5d473f4db36845f2318f180
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,605 @@
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 UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.Initialization;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.AddressableAssets.ResourceProviders;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.ResourceManagement.Util;
namespace UnityEditor.AddressableAssets.Build.DataBuilders
{
using Debug = UnityEngine.Debug;
/// <summary>
/// Build scripts used for player builds and running with bundles in the editor.
/// </summary>
[CreateAssetMenu(fileName = "BuildScriptPacked.asset", menuName = "Addressable Assets/Data Builders/Packed Mode")]
public class BuildScriptPackedMode : BuildScriptBase
{
/// <inheritdoc />
public override string Name
{
get
{
return "Packed Mode";
}
}
List<ObjectInitializationData> m_ResourceProviderData;
List<AssetBundleBuild> m_AllBundleInputDefs;
HashSet<string> m_CreatedProviderIds;
LinkXmlGenerator m_Linker;
/// <inheritdoc />
public override bool CanBuildData<T>()
{
return typeof(T).IsAssignableFrom(typeof(AddressablesPlayerBuildResult));
}
/// <inheritdoc />
protected override TResult BuildDataImplementation<TResult>(AddressablesDataBuilderInput builderInput)
{
TResult result = default(TResult);
var timer = new Stopwatch();
timer.Start();
var aaSettings = builderInput.AddressableSettings;
var locations = new List<ContentCatalogDataEntry>();
m_AllBundleInputDefs = new List<AssetBundleBuild>();
var bundleToAssetGroup = new Dictionary<string, string>();
var runtimeData = new ResourceManagerRuntimeData();
runtimeData.CertificateHandlerType = aaSettings.CertificateHandlerType;
runtimeData.BuildTarget = builderInput.Target.ToString();
runtimeData.ProfileEvents = builderInput.ProfilerEventsEnabled;
runtimeData.LogResourceManagerExceptions = aaSettings.buildSettings.LogResourceManagerExceptions;
m_Linker = new LinkXmlGenerator();
m_Linker.SetTypeConversion(typeof(UnityEditor.Animations.AnimatorController), typeof(RuntimeAnimatorController));
m_Linker.AddTypes(runtimeData.CertificateHandlerType);
m_ResourceProviderData = new List<ObjectInitializationData>();
var aaContext = new AddressableAssetsBuildContext
{
settings = aaSettings,
runtimeData = runtimeData,
bundleToAssetGroup = bundleToAssetGroup,
locations = locations
};
m_CreatedProviderIds = new HashSet<string>();
var errorString = ProcessAllGroups(aaContext);
if(!string.IsNullOrEmpty(errorString))
result = AddressableAssetBuildResult.CreateResult<TResult>(null, 0, errorString);
if (result == null)
{
result = DoBuild<TResult>(builderInput, aaContext);
}
if(result != null)
result.Duration = timer.Elapsed.TotalSeconds;
return result;
}
/// <summary>
/// The method that does the actual building after all the groups have been processed.
/// </summary>
/// <param name="builderInput">The generic builderInput of the</param>
/// <param name="aaContext"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
protected virtual TResult DoBuild<TResult>(AddressablesDataBuilderInput builderInput, AddressableAssetsBuildContext aaContext) where TResult : IDataBuilderResult
{
ExtractDataTask extractData = new ExtractDataTask();
var playerBuildVersion = builderInput.PlayerVersion;
if (m_AllBundleInputDefs.Count > 0)
{
if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
return AddressableAssetBuildResult.CreateResult<TResult>(null, 0, "Unsaved scenes");
var buildTarget = builderInput.Target;
var buildTargetGroup = builderInput.TargetGroup;
var buildParams = new AddressableAssetsBundleBuildParameters(
aaContext.settings,
aaContext.bundleToAssetGroup,
buildTarget,
buildTargetGroup,
aaContext.settings.buildSettings.bundleBuildPath);
var builtinShaderBundleName = aaContext.settings.DefaultGroup.Name.ToLower().Replace(" ", "").Replace('\\', '/').Replace("//", "/") + "_unitybuiltinshaders.bundle";
var buildTasks = RuntimeDataBuildTasks(builtinShaderBundleName);
buildTasks.Add(extractData);
string aaPath = aaContext.settings.AssetPath;
IBundleBuildResults results;
var exitCode = ContentPipeline.BuildAssetBundles(buildParams, new BundleBuildContent(m_AllBundleInputDefs), out results, buildTasks, aaContext);
if (exitCode < ReturnCode.Success)
return AddressableAssetBuildResult.CreateResult<TResult>(null, 0, "SBP Error" + exitCode);
if (aaContext.settings == null && !string.IsNullOrEmpty(aaPath))
aaContext.settings = AssetDatabase.LoadAssetAtPath<AddressableAssetSettings>(aaPath);
GenerateLocationListsTask.Run(aaContext, extractData.WriteData);
foreach (var assetGroup in aaContext.settings.groups)
{
List<string> bundles;
if (aaContext.assetGroupToBundles.TryGetValue(assetGroup, out bundles))
PostProcessBundles(assetGroup, bundles, results, extractData.WriteData, aaContext.runtimeData, aaContext.locations, builderInput.Registry);
}
foreach (var r in results.WriteResults)
m_Linker.AddTypes(r.Value.includedTypes);
}
//save catalog
var contentCatalog = new ContentCatalogData(aaContext.locations);
contentCatalog.ResourceProviderData.AddRange(m_ResourceProviderData);
contentCatalog.InstanceProviderData = ObjectInitializationData.CreateSerializedInitializationData(instanceProviderType.Value);
contentCatalog.SceneProviderData = ObjectInitializationData.CreateSerializedInitializationData(sceneProviderType.Value);
CreateCatalog(aaContext.settings, contentCatalog, aaContext.runtimeData.CatalogLocations, playerBuildVersion, builderInput.RuntimeCatalogFilename, builderInput.Registry);
m_Linker.AddTypes(instanceProviderType.Value);
foreach (var io in aaContext.settings.InitializationObjects)
{
var provider = io as IObjectInitializationDataProvider;
if (provider != null)
{
var id = provider.CreateObjectInitializationData();
aaContext.runtimeData.InitializationObjects.Add(id);
m_Linker.AddTypes(id.ObjectType.Value);
m_Linker.AddTypes(id.GetRuntimeTypes());
}
}
m_Linker.AddTypes(typeof(Addressables));
m_Linker.Save(Addressables.BuildPath + "/link.xml");
var settingsPath = Addressables.BuildPath + "/" + builderInput.RuntimeSettingsFilename;
WriteFile(settingsPath, JsonUtility.ToJson(aaContext.runtimeData), builderInput.Registry);
var opResult = AddressableAssetBuildResult.CreateResult<TResult>(settingsPath, aaContext.locations.Count);
//save content update data if building for the player
var allEntries = new List<AddressableAssetEntry>();
aaContext.settings.GetAllAssets(allEntries, g => g.HasSchema<ContentUpdateGroupSchema>() && g.GetSchema<ContentUpdateGroupSchema>().StaticContent);
var tempPath = Path.GetDirectoryName(Application.dataPath) + "/Library/com.unity.addressables/StreamingAssetsCopy/" + PlatformMappingService.GetPlatform() + "/addressables_content_state.bin";
var remoteCatalogLoadPath = aaContext.settings.BuildRemoteCatalog ? aaContext.settings.RemoteCatalogLoadPath.GetValue(aaContext.settings) : string.Empty;
if (extractData.BuildCache != null && ContentUpdateScript.SaveContentState(tempPath, allEntries, extractData.DependencyData, playerBuildVersion, remoteCatalogLoadPath))
{
try
{
File.Copy(tempPath, ContentUpdateScript.GetContentStateDataPath(false), true);
}
catch (Exception e)
{
Debug.LogException(e);
}
}
return opResult;
}
/// <inheritdoc />
protected override string ProcessGroup(AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext)
{
foreach (var schema in assetGroup.Schemas)
{
var errorString = ProcessGroupSchema(schema, assetGroup, aaContext);
if(!string.IsNullOrEmpty(errorString))
return errorString;
}
return string.Empty;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="schema">The schema to process</param>
/// <param name="assetGroup">The group this schema was pulled from</param>
/// <param name="aaContext">The general Addressables build builderInput</param>
/// <returns></returns>
protected virtual string ProcessGroupSchema(AddressableAssetGroupSchema schema, AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext)
{
var playerDataSchema = schema as PlayerDataGroupSchema;
if (playerDataSchema != null)
return ProcessPlayerDataSchema(playerDataSchema, assetGroup, aaContext);
var bundledAssetSchema = schema as BundledAssetGroupSchema;
if (bundledAssetSchema != null)
return ProcessBundledAssetSchema(bundledAssetSchema, assetGroup, aaContext);
return string.Empty;
}
string ProcessPlayerDataSchema(
PlayerDataGroupSchema schema,
AddressableAssetGroup assetGroup,
AddressableAssetsBuildContext aaContext)
{
if (CreateLocationsForPlayerData(schema, assetGroup, aaContext.locations))
{
if (!m_CreatedProviderIds.Contains(typeof(LegacyResourcesProvider).Name))
{
m_CreatedProviderIds.Add(typeof(LegacyResourcesProvider).Name);
m_ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(typeof(LegacyResourcesProvider)));
m_Linker.AddTypes(typeof(LegacyResourcesProvider));
}
}
return string.Empty;
}
/// <summary>
/// The processing of the bundled asset schema. This is where the bundle(s) for a given group are actually setup.
/// </summary>
/// <param name="schema">The BundledAssetGroupSchema to process</param>
/// <param name="assetGroup">The group this schema was pulled from</param>
/// <param name="aaContext">The general Addressables build builderInput</param>
/// <returns>The error string, if any.</returns>
protected virtual string ProcessBundledAssetSchema(
BundledAssetGroupSchema schema,
AddressableAssetGroup assetGroup,
AddressableAssetsBuildContext aaContext)
{
if (schema == null || !schema.IncludeInBuild)
return string.Empty;
var errorStr = ErrorCheckBundleSettings(schema,assetGroup, aaContext.settings);
if (!string.IsNullOrEmpty(errorStr))
return errorStr;
var bundledProviderId = schema.GetBundleCachedProviderId();
var assetProviderId = schema.GetAssetCachedProviderId();
if (!m_CreatedProviderIds.Contains(bundledProviderId))
{
m_CreatedProviderIds.Add(bundledProviderId);
var bundleProviderType = schema.AssetBundleProviderType.Value;
m_Linker.AddTypes(bundleProviderType);
var bundleProviderData = ObjectInitializationData.CreateSerializedInitializationData(bundleProviderType, bundledProviderId);
m_Linker.AddTypes(bundleProviderData.GetRuntimeTypes());
m_ResourceProviderData.Add(bundleProviderData);
}
if (!m_CreatedProviderIds.Contains(assetProviderId))
{
m_CreatedProviderIds.Add(assetProviderId);
var assetProviderType = schema.BundledAssetProviderType.Value;
m_Linker.AddTypes(assetProviderType);
var assetProviderData = ObjectInitializationData.CreateSerializedInitializationData(assetProviderType, assetProviderId);
m_ResourceProviderData.Add(assetProviderData);
m_Linker.AddTypes(assetProviderData.GetRuntimeTypes());
}
var bundleInputDefs = new List<AssetBundleBuild>();
PrepGroupBundlePacking(assetGroup, bundleInputDefs, aaContext.locations, schema.BundleMode);
for (int i = 0; i < bundleInputDefs.Count; i++)
{
if (aaContext.bundleToAssetGroup.ContainsKey(bundleInputDefs[i].assetBundleName))
{
var bid = bundleInputDefs[i];
int count = 1;
var newName = bid.assetBundleName;
while (aaContext.bundleToAssetGroup.ContainsKey(newName) && count < 1000)
newName = bid.assetBundleName.Replace(".bundle", string.Format("{0}.bundle", count++));
bundleInputDefs[i] = new AssetBundleBuild { assetBundleName = newName, addressableNames = bid.addressableNames, assetBundleVariant = bid.assetBundleVariant, assetNames = bid.assetNames };
}
aaContext.bundleToAssetGroup.Add(bundleInputDefs[i].assetBundleName, assetGroup.Guid);
}
m_AllBundleInputDefs.AddRange(bundleInputDefs);
return string.Empty;
}
internal static string ErrorCheckBundleSettings(BundledAssetGroupSchema schema, AddressableAssetGroup assetGroup, AddressableAssetSettings settings)
{
var message = string.Empty;
var buildPath = settings.profileSettings.GetValueById(settings.activeProfileId, schema.BuildPath.Id);
var loadPath = settings.profileSettings.GetValueById(settings.activeProfileId, schema.LoadPath.Id);
var buildLocal = buildPath.Contains("[UnityEngine.AddressableAssets.Addressables.BuildPath]");
var loadLocal = loadPath.Contains("{UnityEngine.AddressableAssets.Addressables.RuntimePath}");
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 + "'";
}
return message;
}
internal static void PrepGroupBundlePacking(AddressableAssetGroup assetGroup, List<AssetBundleBuild> bundleInputDefs, List<ContentCatalogDataEntry> locationData, BundledAssetGroupSchema.BundlePackingMode packingMode)
{
if (packingMode == BundledAssetGroupSchema.BundlePackingMode.PackTogether)
{
var allEntries = new List<AddressableAssetEntry>();
foreach (var a in assetGroup.entries)
a.GatherAllAssets(allEntries, true, true);
GenerateBuildInputDefinitions(allEntries, bundleInputDefs, assetGroup.Name, "all");
}
else
{
if (packingMode == BundledAssetGroupSchema.BundlePackingMode.PackSeparately)
{
foreach (var a in assetGroup.entries)
{
var allEntries = new List<AddressableAssetEntry>();
a.GatherAllAssets(allEntries, true, true);
GenerateBuildInputDefinitions(allEntries, bundleInputDefs, assetGroup.Name, a.address);
}
}
else
{
var labelTable = new Dictionary<string, List<AddressableAssetEntry>>();
foreach (var a in assetGroup.entries)
{
var sb = new StringBuilder();
foreach (var l in a.labels)
sb.Append(l);
var key = sb.ToString();
List<AddressableAssetEntry> entries;
if (!labelTable.TryGetValue(key, out entries))
labelTable.Add(key, entries = new List<AddressableAssetEntry>());
entries.Add(a);
}
foreach (var entryGroup in labelTable)
{
var allEntries = new List<AddressableAssetEntry>();
foreach (var a in entryGroup.Value)
a.GatherAllAssets(allEntries, true, true);
GenerateBuildInputDefinitions(allEntries, bundleInputDefs, assetGroup.Name, entryGroup.Key);
}
}
}
}
static void GenerateBuildInputDefinitions(List<AddressableAssetEntry> allEntries, List<AssetBundleBuild> buildInputDefs, string groupName, string address)
{
var scenes = new List<AddressableAssetEntry>();
var assets = new List<AddressableAssetEntry>();
foreach (var e in allEntries)
{
if (e.AssetPath.EndsWith(".unity"))
scenes.Add(e);
else
assets.Add(e);
}
if (assets.Count > 0)
buildInputDefs.Add(GenerateBuildInputDefinition(assets, groupName + "_assets_" + address + ".bundle"));
if (scenes.Count > 0)
buildInputDefs.Add(GenerateBuildInputDefinition(scenes, groupName + "_scenes_" + address + ".bundle"));
}
static AssetBundleBuild GenerateBuildInputDefinition(List<AddressableAssetEntry> assets, string name)
{
var assetsInputDef = new AssetBundleBuild();
assetsInputDef.assetBundleName = name.ToLower().Replace(" ", "").Replace('\\', '/').Replace("//", "/");
var assetIds = new List<string>(assets.Count);
foreach (var a in assets)
{
assetIds.Add(a.AssetPath);
}
assetsInputDef.assetNames = assetIds.ToArray();
assetsInputDef.addressableNames = new string[0];
return assetsInputDef;
}
static void CreateCatalog(AddressableAssetSettings aaSettings, ContentCatalogData contentCatalog, List<ResourceLocationData> locations, string playerVersion, string localCatalogFilename, FileRegistry registry)
{
var localBuildPath = Addressables.BuildPath + "/" + localCatalogFilename;
var localLoadPath = "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/" + localCatalogFilename;
var jsonText = JsonUtility.ToJson(contentCatalog);
WriteFile(localBuildPath, jsonText, registry);
string[] dependencyHashes = null;
if (aaSettings.BuildRemoteCatalog)
{
var contentHash = HashingMethods.Calculate(jsonText).ToString();
var versionedFileName = aaSettings.profileSettings.EvaluateString(aaSettings.activeProfileId, "/catalog_" + 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, registry);
WriteFile(remoteHashBuildPath, contentHash, registry);
dependencyHashes = new string[((int)ContentCatalogProvider.DependencyHashIndex.Count)];
dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Remote] = ResourceManagerRuntimeData.kCatalogAddress + "RemoteHash";
dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Cache] = ResourceManagerRuntimeData.kCatalogAddress + "CacheHash";
var remoteHashLoadPath = remoteLoadFolder + versionedFileName + ".hash";
locations.Add(new ResourceLocationData(
new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Remote] },
remoteHashLoadPath,
typeof(TextDataProvider), typeof(string)));
var cacheLoadPath = "{UnityEngine.Application.persistentDataPath}/com.unity.addressables" + versionedFileName + ".hash";
locations.Add(new ResourceLocationData(
new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Cache] },
cacheLoadPath,
typeof(TextDataProvider), typeof(string)));
}
}
locations.Add(new ResourceLocationData(
new []{ ResourceManagerRuntimeData.kCatalogAddress },
localLoadPath,
typeof(ContentCatalogProvider),
typeof(ContentCatalogData),
dependencyHashes));
}
static IList<IBuildTask> RuntimeDataBuildTasks(string builtinShaderBundleName)
{
var buildTasks = new List<IBuildTask>();
// Setup
buildTasks.Add(new SwitchToBuildPlatform());
buildTasks.Add(new RebuildSpriteAtlasCache());
// Player Scripts
buildTasks.Add(new BuildPlayerScripts());
// Dependency
buildTasks.Add(new CalculateSceneDependencyData());
buildTasks.Add(new CalculateAssetDependencyData());
buildTasks.Add(new StripUnusedSpriteSources());
buildTasks.Add(new CreateBuiltInShadersBundle(builtinShaderBundleName));
// Packing
buildTasks.Add(new GenerateBundlePacking());
buildTasks.Add(new UpdateBundleObjectLayout());
buildTasks.Add(new GenerateBundleCommands());
buildTasks.Add(new GenerateSubAssetPathMaps());
buildTasks.Add(new GenerateBundleMaps());
// Writing
buildTasks.Add(new WriteSerializedFiles());
buildTasks.Add(new ArchiveAndCompressBundles());
// buildTasks.Add(new PostProcessBundlesTask());
return buildTasks;
}
static bool IsInternalIdLocal(string path)
{
return path.StartsWith("{UnityEngine.AddressableAssets.Addressables.RuntimePath}");
}
static void PostProcessBundles(AddressableAssetGroup assetGroup, List<string> bundles, IBundleBuildResults buildResult, IWriteData writeData, ResourceManagerRuntimeData runtimeData, List<ContentCatalogDataEntry> locations, FileRegistry registry)
{
var schema = assetGroup.GetSchema<BundledAssetGroupSchema>();
if (schema == null)
return;
var path = schema.BuildPath.GetValue(assetGroup.Settings);
if (string.IsNullOrEmpty(path))
return;
foreach (var originalBundleName in bundles)
{
var newBundleName = originalBundleName;
var info = buildResult.BundleInfos[newBundleName];
ContentCatalogDataEntry dataEntry = locations.First(s => newBundleName == (string)s.Keys[0]);
if (dataEntry != null)
{
var requestOptions = new AssetBundleRequestOptions
{
Crc = schema.UseAssetBundleCrc ? info.Crc : 0,
Hash = schema.UseAssetBundleCache ? info.Hash.ToString() : "",
ChunkedTransfer = schema.ChunkedTransfer,
RedirectLimit = schema.RedirectLimit,
RetryCount = schema.RetryCount,
Timeout = schema.Timeout,
BundleName = Path.GetFileName(info.FileName),
BundleSize = GetFileSize(info.FileName)
};
dataEntry.Data = requestOptions;
dataEntry.InternalId = BuildUtility.GetNameWithHashNaming(schema.BundleNaming, info.Hash.ToString(), dataEntry.InternalId);
newBundleName = BuildUtility.GetNameWithHashNaming(schema.BundleNaming, info.Hash.ToString(), newBundleName);
}
else
{
Debug.LogWarningFormat("Unable to find ContentCatalogDataEntry for bundle {0}.", newBundleName);
}
var targetPath = Path.Combine(path, newBundleName);
if (!Directory.Exists(Path.GetDirectoryName(targetPath)))
Directory.CreateDirectory(Path.GetDirectoryName(targetPath));
File.Copy(Path.Combine(assetGroup.Settings.buildSettings.bundleBuildPath, originalBundleName), targetPath, true);
registry.AddFile(targetPath);
}
}
private static long GetFileSize(string fileName)
{
try
{
return new FileInfo(fileName).Length;
}
catch (Exception e)
{
Debug.LogException(e);
return 0;
}
}
/// <inheritdoc />
public override void ClearCachedData()
{
if (Directory.Exists(Addressables.BuildPath))
{
try
{
var catalogPath = Addressables.BuildPath + "/catalog.json";
var settingsPath = Addressables.BuildPath + "/settings.json";
DeleteFile(catalogPath);
DeleteFile(settingsPath);
Directory.Delete(Addressables.BuildPath, true);
}
catch (Exception e)
{
Debug.LogException(e);
}
}
}
/// <inheritdoc />
public override bool IsDataBuilt()
{
var catalogPath = Addressables.BuildPath + "/catalog.json";
var settingsPath = Addressables.BuildPath + "/settings.json";
return File.Exists(catalogPath) &&
File.Exists(settingsPath);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3e2e0ffa088c91d41a086d0b8cb16bdc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,76 @@
using System;
using System.IO;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.Initialization;
namespace UnityEditor.AddressableAssets.Build.DataBuilders
{
/// <summary>
/// Uses data built by BuildScriptPacked class. This script just sets up the correct variables and runs.
/// </summary>
[CreateAssetMenu(fileName = "BuildScriptPackedPlayMode.asset", menuName = "Addressable Assets/Data Builders/Packed Play Mode")]
public class BuildScriptPackedPlayMode : BuildScriptBase
{
/// <inheritdoc />
public override string Name
{
get
{
return "Packed Play Mode";
}
}
private bool m_DataBuilt;
public override void ClearCachedData()
{
m_DataBuilt = false;
}
/// <inheritdoc />
public override bool IsDataBuilt()
{
return m_DataBuilt;
}
/// <inheritdoc />
public override bool CanBuildData<T>()
{
return typeof(T).IsAssignableFrom(typeof(AddressablesPlayModeBuildResult));
}
/// <inheritdoc />
protected override TResult BuildDataImplementation<TResult>(AddressablesDataBuilderInput builderInput)
{
var timer = new System.Diagnostics.Stopwatch();
timer.Start();
var settingsPath = Addressables.BuildPath + "/settings.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 Addressable Assets window in the Build->Build Player Content menu command." };
return (TResult)resE;
}
var rtd = JsonUtility.FromJson<ResourceManagerRuntimeData>(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 Addressable Assets window in the Build->Build Player Content menu command.", settingsPath) };
return (TResult)resE;
}
BuildTarget dataBuildTarget = BuildTarget.NoTarget;
if (!Enum.TryParse(rtd.BuildTarget, out dataBuildTarget))
Debug.LogWarningFormat("Unable to parse build target from initialization data: '{0}'.", rtd.BuildTarget);
if (BuildPipeline.GetBuildTargetGroup(dataBuildTarget) != BuildTargetGroup.Standalone)
Debug.LogWarningFormat("Asset bundles built with build target {0} may not be compatible with running in the Editor.", dataBuildTarget);
//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);
IDataBuilderResult res = new AddressablesPlayModeBuildResult() { OutputPath = settingsPath, Duration = timer.Elapsed.TotalSeconds };
m_DataBuilt = true;
return (TResult)res;
}
}
}

Some files were not shown because too many files have changed in this diff Show More