DGJ 1 year ago
commit
cf9ea69615
100 changed files with 8029 additions and 0 deletions
  1. 42 0
      .gitignore
  2. 8 0
      Assets/AssetBundles-Browser-1.7.0.meta
  3. 5 0
      Assets/AssetBundles-Browser-1.7.0/.gitignore
  4. 8 0
      Assets/AssetBundles-Browser-1.7.0/.npmignore
  5. 32 0
      Assets/AssetBundles-Browser-1.7.0/CHANGELOG.md
  6. 7 0
      Assets/AssetBundles-Browser-1.7.0/CHANGELOG.md.meta
  7. 8 0
      Assets/AssetBundles-Browser-1.7.0/Documentation.meta
  8. 167 0
      Assets/AssetBundles-Browser-1.7.0/Documentation/com.unity.assetbundlebrowser.md
  9. 7 0
      Assets/AssetBundles-Browser-1.7.0/Documentation/com.unity.assetbundlebrowser.md.meta
  10. 8 0
      Assets/AssetBundles-Browser-1.7.0/Documentation/images.meta
  11. BIN
      Assets/AssetBundles-Browser-1.7.0/Documentation/images/ABundleBrowserIconY1756Basic.png
  12. 83 0
      Assets/AssetBundles-Browser-1.7.0/Documentation/images/ABundleBrowserIconY1756Basic.png.meta
  13. BIN
      Assets/AssetBundles-Browser-1.7.0/Documentation/images/ABundleBrowserIconY1756Scene.png
  14. 83 0
      Assets/AssetBundles-Browser-1.7.0/Documentation/images/ABundleBrowserIconY1756Scene.png.meta
  15. BIN
      Assets/AssetBundles-Browser-1.7.0/Documentation/images/browser_configure2.png
  16. 77 0
      Assets/AssetBundles-Browser-1.7.0/Documentation/images/browser_configure2.png.meta
  17. BIN
      Assets/AssetBundles-Browser-1.7.0/Documentation/images/browser_header.png
  18. 77 0
      Assets/AssetBundles-Browser-1.7.0/Documentation/images/browser_header.png.meta
  19. 9 0
      Assets/AssetBundles-Browser-1.7.0/Editor.meta
  20. 251 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleBrowserMain.cs
  21. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleBrowserMain.cs.meta
  22. 461 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleBuildTab.cs
  23. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleBuildTab.cs.meta
  24. 9 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource.meta
  25. 126 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource/ABDataSource.cs
  26. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource/ABDataSource.cs.meta
  27. 55 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource/ABDataSourceProvider.cs
  28. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource/ABDataSourceProvider.cs.meta
  29. 104 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource/AssetDatabaseABDataSource.cs
  30. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource/AssetDatabaseABDataSource.cs.meta
  31. 274 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleManageTab.cs
  32. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleManageTab.cs.meta
  33. 9 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel.meta
  34. 795 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel/ABModel.cs
  35. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel/ABModel.cs.meta
  36. 246 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel/ABModelAssetInfo.cs
  37. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel/ABModelAssetInfo.cs.meta
  38. 1011 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel/ABModelBundleInfo.cs
  39. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel/ABModelBundleInfo.cs.meta
  40. 647 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleTree.cs
  41. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleTree.cs.meta
  42. 447 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetListTree.cs
  43. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/AssetListTree.cs.meta
  44. 170 0
      Assets/AssetBundles-Browser-1.7.0/Editor/BundleDetailList.cs
  45. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/BundleDetailList.cs.meta
  46. 9 0
      Assets/AssetBundles-Browser-1.7.0/Editor/Icons.meta
  47. BIN
      Assets/AssetBundles-Browser-1.7.0/Editor/Icons/ABundleBrowserIconY1756Basic(1).png
  48. 147 0
      Assets/AssetBundles-Browser-1.7.0/Editor/Icons/ABundleBrowserIconY1756Basic(1).png.meta
  49. BIN
      Assets/AssetBundles-Browser-1.7.0/Editor/Icons/ABundleBrowserIconY1756Scene.png
  50. 77 0
      Assets/AssetBundles-Browser-1.7.0/Editor/Icons/ABundleBrowserIconY1756Scene.png.meta
  51. 9 0
      Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab.meta
  52. 514 0
      Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/AssetBundleInspectTab.cs
  53. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/AssetBundleInspectTab.cs.meta
  54. 60 0
      Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/AssetBundleRecord.cs
  55. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/AssetBundleRecord.cs.meta
  56. 129 0
      Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/InspectSingleBundle.cs
  57. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/InspectSingleBundle.cs.meta
  58. 133 0
      Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/InspectTreeView.cs
  59. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/InspectTreeView.cs.meta
  60. 116 0
      Assets/AssetBundles-Browser-1.7.0/Editor/MessageList.cs
  61. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/MessageList.cs.meta
  62. 198 0
      Assets/AssetBundles-Browser-1.7.0/Editor/MessageSystem.cs
  63. 11 0
      Assets/AssetBundles-Browser-1.7.0/Editor/MessageSystem.cs.meta
  64. 9 0
      Assets/AssetBundles-Browser-1.7.0/Editor/Unity.AssetBundleBrowser.Editor.asmdef
  65. 7 0
      Assets/AssetBundles-Browser-1.7.0/Editor/Unity.AssetBundleBrowser.Editor.asmdef.meta
  66. 18 0
      Assets/AssetBundles-Browser-1.7.0/QAReport.md
  67. 8 0
      Assets/AssetBundles-Browser-1.7.0/QAReport.md.meta
  68. 10 0
      Assets/AssetBundles-Browser-1.7.0/README.md
  69. 8 0
      Assets/AssetBundles-Browser-1.7.0/README.md.meta
  70. 5 0
      Assets/AssetBundles-Browser-1.7.0/license.md
  71. 7 0
      Assets/AssetBundles-Browser-1.7.0/license.md.meta
  72. 12 0
      Assets/AssetBundles-Browser-1.7.0/package.json
  73. 7 0
      Assets/AssetBundles-Browser-1.7.0/package.json.meta
  74. 8 0
      Assets/Editor.meta
  75. 8 0
      Assets/Editor/HybridCLR.meta
  76. 146 0
      Assets/Editor/HybridCLR/BuildAssetsCommand.cs
  77. 11 0
      Assets/Editor/HybridCLR/BuildAssetsCommand.cs.meta
  78. 85 0
      Assets/Editor/HybridCLR/BuildPlayerCommand.cs
  79. 11 0
      Assets/Editor/HybridCLR/BuildPlayerCommand.cs.meta
  80. 8 0
      Assets/HotUpdate.meta
  81. 40 0
      Assets/HotUpdate/Entry.cs
  82. 11 0
      Assets/HotUpdate/Entry.cs.meta
  83. 3 0
      Assets/HotUpdate/HotUpdate.asmdef
  84. 7 0
      Assets/HotUpdate/HotUpdate.asmdef.meta
  85. 14 0
      Assets/HotUpdate/InstantiateByAddComponent.cs
  86. 11 0
      Assets/HotUpdate/InstantiateByAddComponent.cs.meta
  87. 15 0
      Assets/HotUpdate/InstantiateByAsset.cs
  88. 11 0
      Assets/HotUpdate/InstantiateByAsset.cs.meta
  89. 75 0
      Assets/HotUpdate/LoadDLL2.cs
  90. 11 0
      Assets/HotUpdate/LoadDLL2.cs.meta
  91. 8 0
      Assets/HotUpdate/Scripts.meta
  92. 550 0
      Assets/HotUpdate/Scripts/AudioManager.cs
  93. 11 0
      Assets/HotUpdate/Scripts/AudioManager.cs.meta
  94. 8 0
      Assets/HotUpdate/Scripts/Entity.meta
  95. 8 0
      Assets/HotUpdate/Scripts/Entity/ContentInfo.cs
  96. 11 0
      Assets/HotUpdate/Scripts/Entity/ContentInfo.cs.meta
  97. 19 0
      Assets/HotUpdate/Scripts/Entity/FunctionInfo.cs
  98. 11 0
      Assets/HotUpdate/Scripts/Entity/FunctionInfo.cs.meta
  99. 10 0
      Assets/HotUpdate/Scripts/Entity/FunctionValue.cs
  100. 11 0
      Assets/HotUpdate/Scripts/Entity/FunctionValue.cs.meta

+ 42 - 0
.gitignore

@@ -0,0 +1,42 @@
+/*.csproj
+/Library
+/Logs
+/obj
+/Temp
+/UserSettings
+/AssetBundles
+/HybridCLRData
+/vrlauncher.sln
+/Assembly-CSharp.csproj
+/Assembly-CSharp-Editor.csproj
+/Assembly-CSharp-Editor-firstpass.csproj
+/Assembly-CSharp-firstpass.csproj
+/ControllerSample.csproj
+/Demos.StandardShader.Inspectors.csproj
+/Lenovo.XR.OSK.csproj
+/Lenovo.XR.OSK.Sample.csproj
+/Pico.Platform.csproj
+/Pico.Spatializer.csproj
+/Pico.Spatializer.Editor.csproj
+/Pico.Spatializer.Example.csproj
+/QCHT.Core.csproj
+/QCHT.Core.Editor.csproj
+/QCHT.Interactions.csproj
+/QCHT.Interactions.Editor.csproj
+/Snapdragon.Spaces.Editor.csproj
+/Snapdragon.Spaces.Runtime.csproj
+/Unity.XR.PICO.csproj
+/Unity.XR.PICO.Editor.csproj
+/.vsconfig
+/*.apk
+/libc++_shared.so
+/libc++_shared.so.meta
+/libopenxr_loader.so
+/libopenxr_loader.so.meta
+/QCAR
+/*.sln
+/.vs
+/.vscode
+/Assets/Samples/*
+/Assets/Samples.meta
+/Build/*

+ 8 - 0
Assets/AssetBundles-Browser-1.7.0.meta

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

+ 5 - 0
Assets/AssetBundles-Browser-1.7.0/.gitignore

@@ -0,0 +1,5 @@
+artifacts/**
+build/**
+Documentation/ApiDocs/**
+.DS_Store
+.npmrc

+ 8 - 0
Assets/AssetBundles-Browser-1.7.0/.npmignore

@@ -0,0 +1,8 @@
+artifacts/**
+build/**
+Documentation/ApiDocs/**
+.npmrc
+.npmignore
+.gitignore
+QAReport.md
+QAReport.md.meta

+ 32 - 0
Assets/AssetBundles-Browser-1.7.0/CHANGELOG.md

@@ -0,0 +1,32 @@
+# 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.7.0] - 2018-07-23
+- Sorting dependencies for easier identification.
+- fix to windows file sharing violation error.
+- minor bug fixes.
+
+## [1.6.0] - 2018-04-25
+- Stopped altering global styles.
+
+## [1.5.0] - 2018-02-28
+- Code static analysis cleanup.
+- Documentation updates.
+- fix to missing bundle-icon bug.
+
+## [1.4.0] - 2018-02-23
+- Added a search bar to the main tab.  Searches based on asset name.
+
+## [1.3.0] - 2018-01-08
+- serialization fix for inspect tab (was causing entire window to potentially be blank).
+- documentation fix
+
+## [1.2.0] - 2017-12-08
+- Added asmdef to keep browser in its own assembly
+- minor null check fixes
+
+## [1.1.4] - 2017-11-09
+- Initial submission for package distribution

+ 7 - 0
Assets/AssetBundles-Browser-1.7.0/CHANGELOG.md.meta

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

+ 8 - 0
Assets/AssetBundles-Browser-1.7.0/Documentation.meta

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

+ 167 - 0
Assets/AssetBundles-Browser-1.7.0/Documentation/com.unity.assetbundlebrowser.md

@@ -0,0 +1,167 @@
+# Unity Asset Bundle Browser tool
+
+This tool enables the user to view and edit the configuration of asset bundles for their Unity project. It will block editing that would create invalid bundles, and inform you of any issues with existing bundles. It also provides basic build functionality.
+
+Use this tool as an alternative to selecting assets and setting their asset bundle manually in the inspector. It can be dropped into any Unity project with a version of 5.6 or greater. It will create a new menu item in __Window__ > __AssetBundle Browser__. The bundle configuration, build functionality, and build-bundle inspection are split into three tabs within the new window.
+
+![BrowserHeader](images/browser_header.png)
+
+### Requires Unity 5.6+
+
+# Usage - Configure
+
+This window provides an explorer like interface to managing and modifying asset bundles in your project. When first opened, the tool will parse all bundle data in the background, slowly marking warnings or errors it detects. It does what it can to stay in sync with the project, but cannot always be aware of activity outside the tool. To force a quick pass at error detection, or to update the tool with changes made externally, hit the Refresh button in the upper left.
+
+The window is broken into four sections: Bundle List, Bundle Details, Asset List, and Asset Details. 
+![BroserConfigure](images/browser_configure2.png)
+
+### Bundle List
+
+Left hand pane showing a list of all bundles in the project. Available functionality:
+
+* Select a bundle or set of bundles to see a list of the assets that will be in the bundle in the Asset List pane.
+
+* Bundles with variants are a darker grey and can be expanded to show the list of variants.
+
+* Right-click or slow-double-click to rename bundle or bundle folder.
+
+* If a bundle has any error, warning, or info message, an icon will appear on the right side. Mouse over the icon for more information.
+
+* If a bundle has at least one scene in it (making it a scene bundle) and non-scene assets explicitly included, it will be marked as having an error. This bundle will not build until fixed.
+
+* Bundles with duplicated assets will be marked with a warning (more information on duplication in Asset List section below)
+
+* Empty bundles will be marked with an info message. For a number of reasons, empty bundles are not very stable and can dissapear from this list at times.
+
+* Folders of bundles will be marked with the highest message from the contained bundles.
+
+* To fix the duplicated inclusion of assets in bundles, you can:
+
+    * Right click on a single bundle to move all assets determined to be duplicates into a new bundle.
+
+    * Right click on multiple bundles to either move the assets from all selected bundles that are duplicates into a new bundle, or only those that are shared within the selection.
+
+    * You can also drag duplicate assets out of the Asset List pane into the Bundle List to explicitly include them in a bundle. More info on this in the Asset List feature set below.
+
+* Right click or hit DEL to delete bundles.
+
+* Drag bundles around to move them into and out of folders, or merge them.
+
+* Drag assets from the Project Explorer onto bundels to add them.
+
+* Drag assets onto empty space to create a new bundle.
+
+* Right click to create new bundles or bundle folders.
+
+* Right click to "Convert to Variant"
+
+    * This will add a variant (initially called "newvariant") to the selected bundle.
+
+    * All assets currently in selected bundle will be moved into the new variant
+
+    * ComingSoon: Mismatch detection between variants.
+    
+Icons indicate if the bundle is a standard or a scene bundle. 
+
+![Icon for standard bundle](images/ABundleBrowserIconY1756Basic.png)
+
+![Icon for scene bundle](images/ABundleBrowserIconY1756Scene.png)
+
+### Bundle Details
+
+Lower left hand pane showing details of the bundles(s) selected in the Bundle List pane. This pane will show the following information if it is available:
+
+* Total bundle size. This is a sum of the on-disk size of all assets.
+
+* Bundles that the current bundle depends on
+
+* Any messages (error/warning/info) associated with the current bundle.
+
+### Asset List
+
+Upper right hand pane providing a list of assets contained in whichever bundles are selected in the Bundle List.  The search field above this list will match with assets in any bundle. The Asset List will only display matching assets, and the Bundle List will only display bundles that contain matching assets.  Available functionality:
+
+* View all assets anticipated to be included in bundle. Sort asset list by any column header.
+
+* View assets explicitly included in bundle. These are assets that have been assigned a bundle explicitly. The inspector will reflect the bundle inclusion, and in this view they will say the bundle name next to the asset name.
+
+* View assets implicitly included in bundle. These assets will say *auto* as the name of the bundle next to the asset name. If looking at these assets in the inspector they will say *None* as the assigned bundle.
+
+    * These assets have been added to the selected bundle(s) due to a dependency on another included asset. Only assets that are not explicitly assigned to a bundle will be implicitly included in any bundles.
+
+    * Note that this list of implicit includes can be incomplete. There are known issues with materials and textures not always showing up correctly.
+
+    * As multiple assets can share dependencies, it is common for a given asset to be implicitly included in multiple bundles. If the tool detects this case, it will mark both the bundle and the asset in question with a warning icon.
+
+    * To fix the duplicate-inclusion warnings, you can manually move assets into a new bundle or right click the bundle and selecting one of the "Move duplicate" options.
+
+* Drag assets from the Project Explorer into this view to add them to the selected bundle. This is only valid if only one bundle is selected, and the asset type is compatable (scenes onto scene bundles, etc.) 
+
+* Drag assets (explicit or implicit) from the Asset List into the Bundle List (to add them to different bundles, or a newly created bundle).
+
+* Right click or hit DEL to remove assets from bundles (does not remove assets from project).
+
+* Select or double-click assets to reveal them in the Project Explorer.
+
+A note on including folders in bundles. It is possible to assign an asset folder (from the Project Explorer) to a bundle. When viewing this in the browser, the folder itself will be listed as explicit and the contents implicit. This reflects the priority system used to assign assets to bundles. For example, say your game had five prefabs in Assets/Prefabs, and you marked the folder "Prefabs" as being in one bundle, and one of the actual prefabs ("PrefabA") as being in another. Once built, "PrefabA" would be in one bundle, and the other four prefabs would be in the other.
+
+### Asset Details
+
+Lower right hand pane showing details of the asset(s) selected in the Asset List pane. This pane cannot be interacted with, but will show the following information if it is available:
+
+* Full path of asset
+
+* Reason for implicit inclusion in bundles if it is implicit.
+
+* Reason for warning if any.
+
+* Reason for error if any.
+
+### Troubleshooting
+
+* *Can't rename or delet a specific bundle.* This is occasionally caused when first adding this tool to an existing project. Please force a reimport of your assets through the Unity menu system to refresh the data.
+
+### External Tool Integration
+Other tools that generate asset bundle data can choose to integrate with the browser. Currently the primary example is the [Asset Bundle Graph Tool](https://bitbucket.org/Unity-Technologies/assetbundlegraphtool).  If integrations are detected, then a selection bar will appear near the top of the browser.  It will allow you to select the Default data source (Unity's AssetDatabase) or an integrated tool. If none are detected, the selector is not present, though you can add it by right-clicking on the tab header and selecting "Custom Sources".  
+
+# Usage - Build
+
+The Build tab provides basic build functionality to get you started using asset bundles. In most profressional scenarios, users will end up needing a more advanced build setup. All are welcome to use the build code in this tool as a starting point for writing their own once this no longer meets their needs. For the most part, the options here are directly tied to the options the engine expects in [BuildAssetBundleOptions](https://docs.unity3d.com/ScriptReference/BuildAssetBundleOptions.html). Interface:
+
+* *Build Target* - Platform the bundles will be built for
+
+* *Output Path* - Path for saving built bundles. By default this is AssetBundles/. You can edit the path manually, or by selecting "Browse". To return to the default naming convention, hit "Reset".
+
+* *Clear Folders* - This will delete all data from the build path folder prior to building.
+
+* *Copy to StreamingAssets* - After the build is complete, this will copy the results to Assets/StreamingAssets. This can be useful for testing, but would not be used in production.
+
+* *Advanced Settings*
+
+    * *Compression* - Choose between no compression, standard LZMA, or chunk-based LZ4 compression.
+
+    * *Exclude Type Information* - Do not include type information within the asset bundle
+
+    * *Force Rebuild* - Rebuild bundles needing to be built. This is different than "Clear Folders" as this option will not delete bundles that no longer exist.
+
+    * *Ignore Type Tree Changes* - Ignore the type tree changes when doing the incremental build check.
+
+    * *Append Hash* - Append the hash to the asset bundle name.
+
+    * *Strict Mode* - Do not allow the build to succeed if any errors are reporting during it.
+
+    * *Dry Run Build* - Do a dry run build.
+
+* *Build* - Executes build.
+
+# Usage - Inspect
+This tab enables you to inspect the contents of bundles that have already been built. 
+### Usage
+* If you use the Browser to build, then the path you built to will automatically be added here.
+* Click "Add File" or "Add Folder" to add bundles to inspect.  
+* Click the "-" next to each row to remove that file or folder. Note, you cannot remove individual files that were added by adding a folder.  
+* Select any bundle listed to see details:
+  * Name
+  * Size on disk
+  * Source Asset Paths - the assets explicitly added to this bundle. Note this list is incomplete for scene bundles.
+  * Advanced Data - includes information on the Preload Table, Container (explicit assets) and Dependencies.

+ 7 - 0
Assets/AssetBundles-Browser-1.7.0/Documentation/com.unity.assetbundlebrowser.md.meta

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

+ 8 - 0
Assets/AssetBundles-Browser-1.7.0/Documentation/images.meta

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

BIN
Assets/AssetBundles-Browser-1.7.0/Documentation/images/ABundleBrowserIconY1756Basic.png


+ 83 - 0
Assets/AssetBundles-Browser-1.7.0/Documentation/images/ABundleBrowserIconY1756Basic.png.meta

@@ -0,0 +1,83 @@
+fileFormatVersion: 2
+guid: 521ac7d05d42f41408ec95eaedef87cd
+TextureImporter:
+  fileIDToRecycleName: {}
+  externalObjects: {}
+  serializedVersion: 5
+  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
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    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}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  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: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/AssetBundles-Browser-1.7.0/Documentation/images/ABundleBrowserIconY1756Scene.png


+ 83 - 0
Assets/AssetBundles-Browser-1.7.0/Documentation/images/ABundleBrowserIconY1756Scene.png.meta

@@ -0,0 +1,83 @@
+fileFormatVersion: 2
+guid: 63255dcf53aebf34a8b1162ee502ebe1
+TextureImporter:
+  fileIDToRecycleName: {}
+  externalObjects: {}
+  serializedVersion: 5
+  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
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    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}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  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: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/AssetBundles-Browser-1.7.0/Documentation/images/browser_configure2.png


+ 77 - 0
Assets/AssetBundles-Browser-1.7.0/Documentation/images/browser_configure2.png.meta

@@ -0,0 +1,77 @@
+fileFormatVersion: 2
+guid: e3aa429e1ebaddb41ad13211560ea5e8
+TextureImporter:
+  fileIDToRecycleName: {}
+  externalObjects: {}
+  serializedVersion: 5
+  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
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    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}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  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: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/AssetBundles-Browser-1.7.0/Documentation/images/browser_header.png


+ 77 - 0
Assets/AssetBundles-Browser-1.7.0/Documentation/images/browser_header.png.meta

@@ -0,0 +1,77 @@
+fileFormatVersion: 2
+guid: 18223d49715730347b997e6682fe49e5
+TextureImporter:
+  fileIDToRecycleName: {}
+  externalObjects: {}
+  serializedVersion: 5
+  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
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    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}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  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: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/AssetBundles-Browser-1.7.0/Editor.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 946ae3b25c7026b49b4fc66e969e5475
+folderAsset: yes
+timeCreated: 1507818222
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 251 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleBrowserMain.cs

@@ -0,0 +1,251 @@
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEngine;
+
+[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("Unity.AssetBundleBrowser.Editor.Tests")]
+
+namespace AssetBundleBrowser
+{
+
+    public class AssetBundleBrowserMain : EditorWindow, IHasCustomMenu, ISerializationCallbackReceiver
+    {
+
+        private static AssetBundleBrowserMain s_instance = null;
+        internal static AssetBundleBrowserMain instance
+        {
+            get
+            {
+                if (s_instance == null)
+                    s_instance = GetWindow<AssetBundleBrowserMain>();
+                return s_instance;
+            }
+        }
+
+        internal const float kButtonWidth = 150;
+
+        enum Mode
+        {
+            Browser,
+            Builder,
+            Inspect,
+        }
+        [SerializeField]
+        Mode m_Mode;
+
+        [SerializeField]
+        int m_DataSourceIndex;
+
+        [SerializeField]
+        internal AssetBundleManageTab m_ManageTab;
+
+        [SerializeField]
+        internal AssetBundleBuildTab m_BuildTab;
+
+        [SerializeField]
+        internal AssetBundleInspectTab m_InspectTab;
+
+        private Texture2D m_RefreshTexture;
+
+        const float k_ToolbarPadding = 15;
+        const float k_MenubarPadding = 32;
+
+        [MenuItem("Window/AssetBundle Browser", priority = 2050)]
+        static void ShowWindow()
+        {
+            s_instance = null;
+            instance.titleContent = new GUIContent("AssetBundles");
+            instance.Show();
+        }
+
+        [SerializeField]
+        internal bool multiDataSource = false;
+        List<AssetBundleDataSource.ABDataSource> m_DataSourceList = null;
+        public virtual void AddItemsToMenu(GenericMenu menu)
+        {
+            if(menu != null)
+               menu.AddItem(new GUIContent("Custom Sources"), multiDataSource, FlipDataSource);
+        }
+        internal void FlipDataSource()
+        {
+            multiDataSource = !multiDataSource;
+        }
+
+        private void OnEnable()
+        {
+
+            Rect subPos = GetSubWindowArea();
+            if(m_ManageTab == null)
+                m_ManageTab = new AssetBundleManageTab();
+            m_ManageTab.OnEnable(subPos, this);
+            if(m_BuildTab == null)
+                m_BuildTab = new AssetBundleBuildTab();
+            m_BuildTab.OnEnable(this);
+            if (m_InspectTab == null)
+                m_InspectTab = new AssetBundleInspectTab();
+            m_InspectTab.OnEnable(subPos);
+
+            m_RefreshTexture = EditorGUIUtility.FindTexture("Refresh");
+
+            InitDataSources();
+        } 
+        private void InitDataSources()
+        {
+            //determine if we are "multi source" or not...
+            multiDataSource = false;
+            m_DataSourceList = new List<AssetBundleDataSource.ABDataSource>();
+            foreach (var info in AssetBundleDataSource.ABDataSourceProviderUtility.CustomABDataSourceTypes)
+            {
+                m_DataSourceList.AddRange(info.GetMethod("CreateDataSources").Invoke(null, null) as List<AssetBundleDataSource.ABDataSource>);
+            }
+             
+            if (m_DataSourceList.Count > 1)
+            {
+                multiDataSource = true;
+                if (m_DataSourceIndex >= m_DataSourceList.Count)
+                    m_DataSourceIndex = 0;
+                AssetBundleModel.Model.DataSource = m_DataSourceList[m_DataSourceIndex];
+            }
+        }
+        private void OnDisable()
+        {
+            if (m_BuildTab != null)
+                m_BuildTab.OnDisable();
+            if (m_InspectTab != null)
+                m_InspectTab.OnDisable();
+        }
+
+        public void OnBeforeSerialize()
+        {
+        }
+        public void OnAfterDeserialize()
+        {
+        }
+
+        private Rect GetSubWindowArea()
+        {
+            float padding = k_MenubarPadding;
+            if (multiDataSource)
+                padding += k_MenubarPadding * 0.5f;
+            Rect subPos = new Rect(0, padding, position.width, position.height - padding);
+            return subPos;
+        }
+
+        private void Update()
+        {
+            switch (m_Mode)
+            {
+                case Mode.Builder:
+                    break;
+                case Mode.Inspect:
+                    break;
+                case Mode.Browser:
+                default:
+                    m_ManageTab.Update();
+                    break;
+            }
+        }
+
+        private void OnGUI()
+        {
+            ModeToggle();
+
+            switch(m_Mode)
+            {
+                case Mode.Builder:
+                    m_BuildTab.OnGUI();
+                    break;
+                case Mode.Inspect:
+                    m_InspectTab.OnGUI(GetSubWindowArea());
+                    break;
+                case Mode.Browser:
+                default:
+                    m_ManageTab.OnGUI(GetSubWindowArea());
+                    break;
+            }
+        }
+
+        void ModeToggle()
+        {
+            GUILayout.BeginHorizontal();
+            GUILayout.Space(k_ToolbarPadding);
+            bool clicked = false;
+            switch(m_Mode)
+            {
+                case Mode.Browser:
+                    clicked = GUILayout.Button(m_RefreshTexture);
+                    if (clicked)
+                        m_ManageTab.ForceReloadData();
+                    break;
+                case Mode.Builder:
+                    GUILayout.Space(m_RefreshTexture.width + k_ToolbarPadding);
+                    break;
+                case Mode.Inspect:
+                    clicked = GUILayout.Button(m_RefreshTexture);
+                    if (clicked)
+                        m_InspectTab.RefreshBundles();
+                    break;
+            }
+
+            float toolbarWidth = position.width - k_ToolbarPadding * 4 - m_RefreshTexture.width;
+            //string[] labels = new string[2] { "Configure", "Build"};
+            string[] labels = new string[3] { "Configure", "Build", "Inspect" };
+            m_Mode = (Mode)GUILayout.Toolbar((int)m_Mode, labels, "LargeButton", GUILayout.Width(toolbarWidth) );
+            GUILayout.FlexibleSpace();
+            GUILayout.EndHorizontal();
+            if(multiDataSource)
+            {
+                //GUILayout.BeginArea(r);
+                GUILayout.BeginHorizontal();
+
+                using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
+                {
+                    GUILayout.Label("Bundle Data Source:");
+                    GUILayout.FlexibleSpace();
+                    var c = new GUIContent(string.Format("{0} ({1})", AssetBundleModel.Model.DataSource.Name, AssetBundleModel.Model.DataSource.ProviderName), "Select Asset Bundle Set");
+                    if (GUILayout.Button(c , EditorStyles.toolbarPopup) )
+                    {
+                        GenericMenu menu = new GenericMenu();
+
+                        for (int index = 0; index < m_DataSourceList.Count; index++)
+                        {
+                            var ds = m_DataSourceList[index];
+                            if (ds == null)
+                                continue;
+
+                            if (index > 0)
+                                menu.AddSeparator("");
+                             
+                            var counter = index;
+                            menu.AddItem(new GUIContent(string.Format("{0} ({1})", ds.Name, ds.ProviderName)), false,
+                                () =>
+                                {
+                                    m_DataSourceIndex = counter;
+                                    var thisDataSource = ds;
+                                    AssetBundleModel.Model.DataSource = thisDataSource;
+                                    m_ManageTab.ForceReloadData();
+                                }
+                            );
+
+                        }
+
+                        menu.ShowAsContext();
+                    }
+
+                    GUILayout.FlexibleSpace();
+                    if (AssetBundleModel.Model.DataSource.IsReadOnly())
+                    {
+                        GUIStyle tbLabel = new GUIStyle(EditorStyles.toolbar);
+                        tbLabel.alignment = TextAnchor.MiddleRight;
+
+                        GUILayout.Label("Read Only", tbLabel);
+                    }
+                }
+
+                GUILayout.EndHorizontal();
+                //GUILayout.EndArea();
+            }
+        }
+
+
+    }
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleBrowserMain.cs.meta

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

+ 461 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleBuildTab.cs

@@ -0,0 +1,461 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.Serialization.Formatters.Binary;
+
+using AssetBundleBrowser.AssetBundleDataSource;
+
+namespace AssetBundleBrowser
+{
+    [System.Serializable]
+    internal class AssetBundleBuildTab
+    {
+        const string k_BuildPrefPrefix = "ABBBuild:";
+
+        private string m_streamingPath = "Assets/StreamingAssets";
+
+        [SerializeField]
+        private bool m_AdvancedSettings;
+
+        [SerializeField]
+        private Vector2 m_ScrollPosition;
+
+
+        class ToggleData
+        {
+            internal ToggleData(bool s, 
+                string title, 
+                string tooltip,
+                List<string> onToggles,
+                BuildAssetBundleOptions opt = BuildAssetBundleOptions.None)
+            {
+                if (onToggles.Contains(title))
+                    state = true;
+                else
+                    state = s;
+                content = new GUIContent(title, tooltip);
+                option = opt;
+            }
+            //internal string prefsKey
+            //{ get { return k_BuildPrefPrefix + content.text; } }
+            internal bool state;
+            internal GUIContent content;
+            internal BuildAssetBundleOptions option;
+        }
+
+        private AssetBundleInspectTab m_InspectTab;
+
+        [SerializeField]
+        private BuildTabData m_UserData;
+
+        List<ToggleData> m_ToggleData;
+        ToggleData m_ForceRebuild;
+        ToggleData m_CopyToStreaming;
+        GUIContent m_TargetContent;
+        GUIContent m_CompressionContent;
+        internal enum CompressOptions
+        {
+            Uncompressed = 0,
+            StandardCompression,
+            ChunkBasedCompression,
+        }
+        GUIContent[] m_CompressionOptions =
+        {
+            new GUIContent("No Compression"),
+            new GUIContent("Standard Compression (LZMA)"),
+            new GUIContent("Chunk Based Compression (LZ4)")
+        };
+        int[] m_CompressionValues = { 0, 1, 2 };
+
+
+        internal AssetBundleBuildTab()
+        {
+            m_AdvancedSettings = false;
+            m_UserData = new BuildTabData();
+            m_UserData.m_OnToggles = new List<string>();
+            m_UserData.m_UseDefaultPath = true;
+        }
+
+        internal void OnDisable()
+        {
+            var dataPath = System.IO.Path.GetFullPath(".");
+            dataPath = dataPath.Replace("\\", "/");
+            dataPath += "/Library/AssetBundleBrowserBuild.dat";
+
+            BinaryFormatter bf = new BinaryFormatter();
+            FileStream file = File.Create(dataPath);
+
+            bf.Serialize(file, m_UserData);
+            file.Close();
+
+        }
+        internal void OnEnable(EditorWindow parent)
+        {
+            m_InspectTab = (parent as AssetBundleBrowserMain).m_InspectTab;
+
+            //LoadData...
+            var dataPath = System.IO.Path.GetFullPath(".");
+            dataPath = dataPath.Replace("\\", "/");
+            dataPath += "/Library/AssetBundleBrowserBuild.dat";
+
+            if (File.Exists(dataPath))
+            {
+                BinaryFormatter bf = new BinaryFormatter();
+                FileStream file = File.Open(dataPath, FileMode.Open);
+                var data = bf.Deserialize(file) as BuildTabData;
+                if (data != null)
+                    m_UserData = data;
+                file.Close();
+            }
+            
+            m_ToggleData = new List<ToggleData>();
+            m_ToggleData.Add(new ToggleData(
+                false,
+                "Exclude Type Information",
+                "Do not include type information within the asset bundle (don't write type tree).",
+                m_UserData.m_OnToggles,
+                BuildAssetBundleOptions.DisableWriteTypeTree));
+            m_ToggleData.Add(new ToggleData(
+                false,
+                "Force Rebuild",
+                "Force rebuild the asset bundles",
+                m_UserData.m_OnToggles,
+                BuildAssetBundleOptions.ForceRebuildAssetBundle));
+            m_ToggleData.Add(new ToggleData(
+                false,
+                "Ignore Type Tree Changes",
+                "Ignore the type tree changes when doing the incremental build check.",
+                m_UserData.m_OnToggles,
+                BuildAssetBundleOptions.IgnoreTypeTreeChanges));
+            m_ToggleData.Add(new ToggleData(
+                false,
+                "Append Hash",
+                "Append the hash to the assetBundle name.",
+                m_UserData.m_OnToggles,
+                BuildAssetBundleOptions.AppendHashToAssetBundleName));
+            m_ToggleData.Add(new ToggleData(
+                false,
+                "Strict Mode",
+                "Do not allow the build to succeed if any errors are reporting during it.",
+                m_UserData.m_OnToggles,
+                BuildAssetBundleOptions.StrictMode));
+            m_ToggleData.Add(new ToggleData(
+                false,
+                "Dry Run Build",
+                "Do a dry run build.",
+                m_UserData.m_OnToggles,
+                BuildAssetBundleOptions.DryRunBuild));
+
+
+            m_ForceRebuild = new ToggleData(
+                false,
+                "Clear Folders",
+                "Will wipe out all contents of build directory as well as StreamingAssets/AssetBundles if you are choosing to copy build there.",
+                m_UserData.m_OnToggles);
+            m_CopyToStreaming = new ToggleData(
+                false,
+                "Copy to StreamingAssets",
+                "After build completes, will copy all build content to " + m_streamingPath + " for use in stand-alone player.",
+                m_UserData.m_OnToggles);
+
+            m_TargetContent = new GUIContent("Build Target", "Choose target platform to build for.");
+            m_CompressionContent = new GUIContent("Compression", "Choose no compress, standard (LZMA), or chunk based (LZ4)");
+
+            if(m_UserData.m_UseDefaultPath)
+            {
+                ResetPathToDefault();
+            }
+        }
+
+        internal void OnGUI()
+        {
+            m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition);
+            bool newState = false;
+            var centeredStyle = new GUIStyle(GUI.skin.GetStyle("Label"));
+            centeredStyle.alignment = TextAnchor.UpperCenter;
+            GUILayout.Label(new GUIContent("Example build setup"), centeredStyle);
+            //basic options
+            EditorGUILayout.Space();
+            GUILayout.BeginVertical();
+
+            // build target
+            using (new EditorGUI.DisabledScope (!AssetBundleModel.Model.DataSource.CanSpecifyBuildTarget)) {
+                ValidBuildTarget tgt = (ValidBuildTarget)EditorGUILayout.EnumPopup(m_TargetContent, m_UserData.m_BuildTarget);
+                if (tgt != m_UserData.m_BuildTarget)
+                {
+                    m_UserData.m_BuildTarget = tgt;
+                    if(m_UserData.m_UseDefaultPath)
+                    {
+                        m_UserData.m_OutputPath = "AssetBundles/";
+                        m_UserData.m_OutputPath += m_UserData.m_BuildTarget.ToString();
+                        //EditorUserBuildSettings.SetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString(), "AssetBundleOutputPath", m_OutputPath);
+                    }
+                }
+            }
+
+
+            ////output path
+            using (new EditorGUI.DisabledScope (!AssetBundleModel.Model.DataSource.CanSpecifyBuildOutputDirectory)) {
+                EditorGUILayout.Space();
+                GUILayout.BeginHorizontal();
+                var newPath = EditorGUILayout.TextField("Output Path", m_UserData.m_OutputPath);
+                if (!System.String.IsNullOrEmpty(newPath) && newPath != m_UserData.m_OutputPath)
+                {
+                    m_UserData.m_UseDefaultPath = false;
+                    m_UserData.m_OutputPath = newPath;
+                    //EditorUserBuildSettings.SetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString(), "AssetBundleOutputPath", m_OutputPath);
+                }
+                GUILayout.EndHorizontal();
+                GUILayout.BeginHorizontal();
+                GUILayout.FlexibleSpace();
+                if (GUILayout.Button("Browse", GUILayout.MaxWidth(75f)))
+                    BrowseForFolder();
+                if (GUILayout.Button("Reset", GUILayout.MaxWidth(75f)))
+                    ResetPathToDefault();
+                //if (string.IsNullOrEmpty(m_OutputPath))
+                //    m_OutputPath = EditorUserBuildSettings.GetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString(), "AssetBundleOutputPath");
+                GUILayout.EndHorizontal();
+                EditorGUILayout.Space();
+
+                newState = GUILayout.Toggle(
+                    m_ForceRebuild.state,
+                    m_ForceRebuild.content);
+                if (newState != m_ForceRebuild.state)
+                {
+                    if (newState)
+                        m_UserData.m_OnToggles.Add(m_ForceRebuild.content.text);
+                    else
+                        m_UserData.m_OnToggles.Remove(m_ForceRebuild.content.text);
+                    m_ForceRebuild.state = newState;
+                }
+                newState = GUILayout.Toggle(
+                    m_CopyToStreaming.state,
+                    m_CopyToStreaming.content);
+                if (newState != m_CopyToStreaming.state)
+                {
+                    if (newState)
+                        m_UserData.m_OnToggles.Add(m_CopyToStreaming.content.text);
+                    else
+                        m_UserData.m_OnToggles.Remove(m_CopyToStreaming.content.text);
+                    m_CopyToStreaming.state = newState;
+                }
+            }
+
+            // advanced options
+            using (new EditorGUI.DisabledScope (!AssetBundleModel.Model.DataSource.CanSpecifyBuildOptions)) {
+                EditorGUILayout.Space();
+                m_AdvancedSettings = EditorGUILayout.Foldout(m_AdvancedSettings, "Advanced Settings");
+                if(m_AdvancedSettings)
+                {
+                    var indent = EditorGUI.indentLevel;
+                    EditorGUI.indentLevel = 1;
+                    CompressOptions cmp = (CompressOptions)EditorGUILayout.IntPopup(
+                        m_CompressionContent, 
+                        (int)m_UserData.m_Compression,
+                        m_CompressionOptions,
+                        m_CompressionValues);
+
+                    if (cmp != m_UserData.m_Compression)
+                    {
+                        m_UserData.m_Compression = cmp;
+                    }
+                    foreach (var tog in m_ToggleData)
+                    {
+                        newState = EditorGUILayout.ToggleLeft(
+                            tog.content,
+                            tog.state);
+                        if (newState != tog.state)
+                        {
+
+                            if (newState)
+                                m_UserData.m_OnToggles.Add(tog.content.text);
+                            else
+                                m_UserData.m_OnToggles.Remove(tog.content.text);
+                            tog.state = newState;
+                        }
+                    }
+                    EditorGUILayout.Space();
+                    EditorGUI.indentLevel = indent;
+                }
+            }
+
+            // build.
+            EditorGUILayout.Space();
+            if (GUILayout.Button("Build") )
+            {
+                EditorApplication.delayCall += ExecuteBuild;
+            }
+            GUILayout.EndVertical();
+            EditorGUILayout.EndScrollView();
+        }
+
+        private void ExecuteBuild()
+        {
+            if (AssetBundleModel.Model.DataSource.CanSpecifyBuildOutputDirectory) {
+                if (string.IsNullOrEmpty(m_UserData.m_OutputPath))
+                    BrowseForFolder();
+
+                if (string.IsNullOrEmpty(m_UserData.m_OutputPath)) //in case they hit "cancel" on the open browser
+                {
+                    Debug.LogError("AssetBundle Build: No valid output path for build.");
+                    return;
+                }
+
+                if (m_ForceRebuild.state)
+                {
+                    string message = "Do you want to delete all files in the directory " + m_UserData.m_OutputPath;
+                    if (m_CopyToStreaming.state)
+                        message += " and " + m_streamingPath;
+                    message += "?";
+                    if (EditorUtility.DisplayDialog("File delete confirmation", message, "Yes", "No"))
+                    {
+                        try
+                        {
+                            if (Directory.Exists(m_UserData.m_OutputPath))
+                                Directory.Delete(m_UserData.m_OutputPath, true);
+
+                            if (m_CopyToStreaming.state)
+                            if (Directory.Exists(m_streamingPath))
+                                Directory.Delete(m_streamingPath, true);
+                        }
+                        catch (System.Exception e)
+                        {
+                            Debug.LogException(e);
+                        }
+                    }
+                }
+                if (!Directory.Exists(m_UserData.m_OutputPath))
+                    Directory.CreateDirectory(m_UserData.m_OutputPath);
+            }
+
+            BuildAssetBundleOptions opt = BuildAssetBundleOptions.None;
+
+            if (AssetBundleModel.Model.DataSource.CanSpecifyBuildOptions) {
+                if (m_UserData.m_Compression == CompressOptions.Uncompressed)
+                    opt |= BuildAssetBundleOptions.UncompressedAssetBundle;
+                else if (m_UserData.m_Compression == CompressOptions.ChunkBasedCompression)
+                    opt |= BuildAssetBundleOptions.ChunkBasedCompression;
+                foreach (var tog in m_ToggleData)
+                {
+                    if (tog.state)
+                        opt |= tog.option;
+                }
+            }
+
+            ABBuildInfo buildInfo = new ABBuildInfo();
+
+            buildInfo.outputDirectory = m_UserData.m_OutputPath;
+            buildInfo.options = opt;
+            buildInfo.buildTarget = (BuildTarget)m_UserData.m_BuildTarget;
+            buildInfo.onBuild = (assetBundleName) =>
+            {
+                if (m_InspectTab == null)
+                    return;
+                m_InspectTab.AddBundleFolder(buildInfo.outputDirectory);
+                m_InspectTab.RefreshBundles();
+            };
+
+            AssetBundleModel.Model.DataSource.BuildAssetBundles (buildInfo);
+
+            AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
+
+            if(m_CopyToStreaming.state)
+                DirectoryCopy(m_UserData.m_OutputPath, m_streamingPath);
+        }
+
+        private static void DirectoryCopy(string sourceDirName, string destDirName)
+        {
+            // If the destination directory doesn't exist, create it.
+            if (!Directory.Exists(destDirName))
+            {
+                Directory.CreateDirectory(destDirName);
+            }
+
+            foreach (string folderPath in Directory.GetDirectories(sourceDirName, "*", SearchOption.AllDirectories))
+            {
+                if (!Directory.Exists(folderPath.Replace(sourceDirName, destDirName)))
+                    Directory.CreateDirectory(folderPath.Replace(sourceDirName, destDirName));
+            }
+
+            foreach (string filePath in Directory.GetFiles(sourceDirName, "*.*", SearchOption.AllDirectories))
+            {
+                var fileDirName = Path.GetDirectoryName(filePath).Replace("\\", "/");
+                var fileName = Path.GetFileName(filePath);
+                string newFilePath = Path.Combine(fileDirName.Replace(sourceDirName, destDirName), fileName);
+
+                File.Copy(filePath, newFilePath, true);
+            }
+        }
+
+        private void BrowseForFolder()
+        {
+            m_UserData.m_UseDefaultPath = false;
+            var newPath = EditorUtility.OpenFolderPanel("Bundle Folder", m_UserData.m_OutputPath, string.Empty);
+            if (!string.IsNullOrEmpty(newPath))
+            {
+                var gamePath = System.IO.Path.GetFullPath(".");
+                gamePath = gamePath.Replace("\\", "/");
+                if (newPath.StartsWith(gamePath) && newPath.Length > gamePath.Length)
+                    newPath = newPath.Remove(0, gamePath.Length+1);
+                m_UserData.m_OutputPath = newPath;
+                //EditorUserBuildSettings.SetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString(), "AssetBundleOutputPath", m_OutputPath);
+            }
+        }
+        private void ResetPathToDefault()
+        {
+            m_UserData.m_UseDefaultPath = true;
+            m_UserData.m_OutputPath = "AssetBundles/";
+            m_UserData.m_OutputPath += m_UserData.m_BuildTarget.ToString();
+            //EditorUserBuildSettings.SetPlatformSettings(EditorUserBuildSettings.activeBuildTarget.ToString(), "AssetBundleOutputPath", m_OutputPath);
+        }
+
+        //Note: this is the provided BuildTarget enum with some entries removed as they are invalid in the dropdown
+        internal enum ValidBuildTarget
+        {
+            //NoTarget = -2,        --doesn't make sense
+            //iPhone = -1,          --deprecated
+            //BB10 = -1,            --deprecated
+            //MetroPlayer = -1,     --deprecated
+            StandaloneOSXUniversal = 2,
+            StandaloneOSXIntel = 4,
+            StandaloneWindows = 5,
+            WebPlayer = 6,
+            WebPlayerStreamed = 7,
+            iOS = 9,
+            PS3 = 10,
+            XBOX360 = 11,
+            Android = 13,
+            StandaloneLinux = 17,
+            StandaloneWindows64 = 19,
+            WebGL = 20,
+            WSAPlayer = 21,
+            StandaloneLinux64 = 24,
+            StandaloneLinuxUniversal = 25,
+            WP8Player = 26,
+            StandaloneOSXIntel64 = 27,
+            BlackBerry = 28,
+            Tizen = 29,
+            PSP2 = 30,
+            PS4 = 31,
+            PSM = 32,
+            XboxOne = 33,
+            SamsungTV = 34,
+            N3DS = 35,
+            WiiU = 36,
+            tvOS = 37,
+            Switch = 38
+        }
+
+        [System.Serializable]
+        internal class BuildTabData
+        {
+            internal List<string> m_OnToggles;
+            internal ValidBuildTarget m_BuildTarget = ValidBuildTarget.StandaloneWindows;
+            internal CompressOptions m_Compression = CompressOptions.StandardCompression;
+            internal string m_OutputPath = string.Empty;
+            internal bool m_UseDefaultPath = true;
+        }
+    }
+
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleBuildTab.cs.meta

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

+ 9 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 37cf1ee934b7c254e92e69eb6f19f186
+folderAsset: yes
+timeCreated: 1497630438
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 126 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource/ABDataSource.cs

@@ -0,0 +1,126 @@
+using UnityEditor;
+using System;
+
+namespace AssetBundleBrowser.AssetBundleDataSource
+{
+    /// <summary>
+    /// Build Info struct used by ABDataSource to pass needed build data around.
+    /// </summary>
+    public partial class ABBuildInfo
+    {
+        /// <summary>
+        /// Directory to place build result
+        /// </summary>
+        public string outputDirectory
+        {
+            get { return m_outputDirectory; }
+            set { m_outputDirectory = value; }
+        }
+        private string m_outputDirectory;
+        /// <summary>
+        /// Standard asset bundle build options.
+        /// </summary>
+        public BuildAssetBundleOptions options
+        {
+            get { return m_options; }
+            set { m_options = value; }
+        }
+        private BuildAssetBundleOptions m_options;
+        /// <summary>
+        /// Target platform for build.
+        /// </summary>
+        public BuildTarget buildTarget
+        {
+            get { return m_buildTarget; }
+            set { m_buildTarget = value; }
+        }
+        private BuildTarget m_buildTarget;
+        /// <summary>
+        /// Callback for build event.
+        /// </summary>
+        public Action<string> onBuild
+        {
+            get { return m_onBuild; }
+            set { m_onBuild = value; }
+        }
+        private Action<string> m_onBuild;
+    }
+
+    /// <summary>
+    /// Interface class used by browser. It is expected to contain all information needed to display predicted bundle layout.
+    ///  Any class deriving from this interface AND imlementing CreateDataSources() will be picked up by the browser automatically
+    ///  and displayed in an in-tool dropdown.  By default, that dropdown is hidden if the browser detects no external data sources.
+    ///  To turn it on, right click on tab header "AssetBUndles" and enable "Custom Sources"
+    ///  
+    /// Must implement CreateDataSources() to be picked up by the browser.
+    ///   public static List<ABDataSource> CreateDataSources();
+    /// 
+    /// </summary>
+    public partial interface ABDataSource
+    {
+        //// all derived classes must implement the following interface in order to be picked up by the browser.
+        //public static List<ABDataSource> CreateDataSources();
+
+        /// <summary>
+        /// Name of DataSource. Displayed in menu as "Name (ProvidorName)"
+        /// </summary>
+        string Name { get; }
+        /// <summary>
+        /// Name of provider for DataSource. Displayed in menu as "Name (ProvidorName)"
+        /// </summary>
+        string ProviderName { get; }
+
+        /// <summary>
+        /// Array of paths in bundle.
+        /// </summary>
+        string[] GetAssetPathsFromAssetBundle (string assetBundleName);
+        /// <summary>
+        /// Name of bundle explicitly associated with asset at path.  
+        /// </summary>
+        string GetAssetBundleName(string assetPath);
+        /// <summary>
+        /// Name of bundle associated with asset at path.  
+        ///  The difference between this and GetAssetBundleName() is for assets unassigned to a bundle, but
+        ///  residing inside a folder that is assigned to a bundle.  Those assets will implicilty associate
+        ///  with the bundle associated with the parent folder.
+        /// </summary>
+        string GetImplicitAssetBundleName(string assetPath);
+        /// <summary>
+        /// Array of asset bundle names in project
+        /// </summary>
+        string[] GetAllAssetBundleNames();
+        /// <summary>
+        /// If this data source is read only. 
+        ///  If this returns true, much of the Browsers's interface will be diabled (drag&drop, etc.)
+        /// </summary>
+        bool IsReadOnly();
+
+        /// <summary>
+        /// Sets the asset bundle name (and variant) on a given asset
+        /// </summary>
+        void SetAssetBundleNameAndVariant (string assetPath, string bundleName, string variantName);
+        /// <summary>
+        /// Clears out any asset bundle names that do not have assets associated with them.
+        /// </summary>
+        void RemoveUnusedAssetBundleNames();
+
+        /// <summary>
+        /// Signals if this data source can have build target set by tool
+        /// </summary>
+        bool CanSpecifyBuildTarget { get; }
+        /// <summary>
+        /// Signals if this data source can have output directory set by tool
+        /// </summary>
+        bool CanSpecifyBuildOutputDirectory { get; }
+        /// <summary>
+        /// Signals if this data source can have build options set by tool
+        /// </summary>
+        bool CanSpecifyBuildOptions { get; }
+
+        /// <summary>
+        /// Executes data source's implementation of asset bundle building.
+        ///   Called by "build" button in build tab of tool.
+        /// </summary>
+        bool BuildAssetBundles (ABBuildInfo info);
+    }
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource/ABDataSource.cs.meta

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

+ 55 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource/ABDataSourceProvider.cs

@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace AssetBundleBrowser.AssetBundleDataSource
+{
+    internal class ABDataSourceProviderUtility {
+
+        private static List<Type> s_customNodes;
+
+        internal static List<Type> CustomABDataSourceTypes {
+            get {
+                if(s_customNodes == null) {
+                    s_customNodes = BuildCustomABDataSourceList();
+                }
+                return s_customNodes;
+            }
+        }
+
+        private static List<Type> BuildCustomABDataSourceList()
+        {
+            var properList = new List<Type>();
+            properList.Add(null); //empty spot for "default" 
+            var x = AppDomain.CurrentDomain.GetAssemblies();
+            foreach (var assembly in x)
+            {
+                try
+                {
+                    var list = new List<Type>(
+                        assembly
+                        .GetTypes()
+                        .Where(t => t != typeof(ABDataSource))
+                        .Where(t => typeof(ABDataSource).IsAssignableFrom(t)));
+
+
+                    for (int count = 0; count < list.Count; count++)
+                    {
+                        if (list[count].Name == "AssetDatabaseABDataSource")
+                            properList[0] = list[count];
+                        else if (list[count] != null)
+                            properList.Add(list[count]);
+                    }
+                }
+                catch (System.Exception)
+                {
+                    //assembly which raises exception on the GetTypes() call - ignore it
+                }
+            }
+
+
+            return properList;
+        }
+    }
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource/ABDataSourceProvider.cs.meta

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

+ 104 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource/AssetDatabaseABDataSource.cs

@@ -0,0 +1,104 @@
+using System;
+using UnityEngine;
+using UnityEditor;
+using UnityEngine.Assertions;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor.IMGUI.Controls;
+
+namespace AssetBundleBrowser.AssetBundleDataSource
+{
+    internal class AssetDatabaseABDataSource : ABDataSource
+    {
+        public static List<ABDataSource> CreateDataSources()
+        {
+            var op = new AssetDatabaseABDataSource();
+            var retList = new List<ABDataSource>();
+            retList.Add(op);
+            return retList;
+        }
+
+        public string Name {
+            get {
+                return "Default";
+            }
+        }
+
+        public string ProviderName {
+            get {
+                return "Built-in";
+            }
+        }
+
+        public string[] GetAssetPathsFromAssetBundle (string assetBundleName) {
+            return AssetDatabase.GetAssetPathsFromAssetBundle(assetBundleName);
+        }
+
+        public string GetAssetBundleName(string assetPath) {
+            var importer = AssetImporter.GetAtPath(assetPath);
+            if (importer == null) {
+                return string.Empty;
+            }
+            var bundleName = importer.assetBundleName;
+            if (importer.assetBundleVariant.Length > 0) {
+                bundleName = bundleName + "." + importer.assetBundleVariant;
+            }
+            return bundleName;
+        }
+
+        public string GetImplicitAssetBundleName(string assetPath) {
+            return AssetDatabase.GetImplicitAssetBundleName (assetPath);
+        }
+
+        public string[] GetAllAssetBundleNames() {
+            return AssetDatabase.GetAllAssetBundleNames ();
+        }
+
+        public bool IsReadOnly() {
+            return false;
+        }
+
+        public void SetAssetBundleNameAndVariant (string assetPath, string bundleName, string variantName) {
+            AssetImporter.GetAtPath(assetPath).SetAssetBundleNameAndVariant(bundleName, variantName);
+        }
+
+        public void RemoveUnusedAssetBundleNames() {
+            AssetDatabase.RemoveUnusedAssetBundleNames ();
+        }
+
+        public bool CanSpecifyBuildTarget { 
+            get { return true; } 
+        }
+        public bool CanSpecifyBuildOutputDirectory { 
+            get { return true; } 
+        }
+
+        public bool CanSpecifyBuildOptions { 
+            get { return true; } 
+        }
+
+        public bool BuildAssetBundles (ABBuildInfo info) {
+            if(info == null)
+            {
+                Debug.Log("Error in build");
+                return false;
+            }
+
+            var buildManifest = BuildPipeline.BuildAssetBundles(info.outputDirectory, info.options, info.buildTarget);
+            if (buildManifest == null)
+            {
+                Debug.Log("Error in build");
+                return false;
+            }
+
+            foreach(var assetBundleName in buildManifest.GetAllAssetBundles())
+            {
+                if (info.onBuild != null)
+                {
+                    info.onBuild(assetBundleName);
+                }
+            }
+            return true;
+        }
+    }
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleDataSource/AssetDatabaseABDataSource.cs.meta

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

+ 274 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleManageTab.cs

@@ -0,0 +1,274 @@
+using UnityEditor;
+using UnityEditor.IMGUI.Controls;
+using UnityEngine;
+using System.Collections.Generic;
+
+
+namespace AssetBundleBrowser
+{
+    [System.Serializable]
+    internal class AssetBundleManageTab 
+    {
+        [SerializeField]
+        TreeViewState m_BundleTreeState;
+        [SerializeField]
+        TreeViewState m_AssetListState;
+        [SerializeField]
+        MultiColumnHeaderState m_AssetListMCHState;
+        [SerializeField]
+        TreeViewState m_BundleDetailState;
+
+        Rect m_Position;
+
+        AssetBundleTree m_BundleTree;
+        AssetListTree m_AssetList;
+        MessageList m_MessageList;
+        BundleDetailList m_DetailsList;
+        bool m_ResizingHorizontalSplitter = false;
+        bool m_ResizingVerticalSplitterRight = false;
+        bool m_ResizingVerticalSplitterLeft = false;
+        Rect m_HorizontalSplitterRect, m_VerticalSplitterRectRight, m_VerticalSplitterRectLeft;
+        [SerializeField]
+        float m_HorizontalSplitterPercent;
+        [SerializeField]
+        float m_VerticalSplitterPercentRight;
+        [SerializeField]
+        float m_VerticalSplitterPercentLeft;
+        const float k_SplitterWidth = 3f;
+        private static float s_UpdateDelay = 0f;
+
+        SearchField m_searchField;
+
+        EditorWindow m_Parent = null;
+
+        internal AssetBundleManageTab()
+        {
+            m_HorizontalSplitterPercent = 0.4f;
+            m_VerticalSplitterPercentRight = 0.7f;
+            m_VerticalSplitterPercentLeft = 0.85f;
+        }
+
+        internal void OnEnable(Rect pos, EditorWindow parent)
+        {
+            m_Parent = parent;
+            m_Position = pos;
+            m_HorizontalSplitterRect = new Rect(
+                (int)(m_Position.x + m_Position.width * m_HorizontalSplitterPercent),
+                m_Position.y,
+                k_SplitterWidth,
+                m_Position.height);
+            m_VerticalSplitterRectRight = new Rect(
+                m_HorizontalSplitterRect.x,
+                (int)(m_Position.y + m_HorizontalSplitterRect.height * m_VerticalSplitterPercentRight),
+                (m_Position.width - m_HorizontalSplitterRect.width) - k_SplitterWidth,
+                k_SplitterWidth);
+            m_VerticalSplitterRectLeft = new Rect(
+                m_Position.x,
+                (int)(m_Position.y + m_HorizontalSplitterRect.height * m_VerticalSplitterPercentLeft),
+                (m_HorizontalSplitterRect.width) - k_SplitterWidth,
+                k_SplitterWidth);
+
+            m_searchField = new SearchField();
+        }
+
+
+
+        internal void Update()
+        {
+            var t = Time.realtimeSinceStartup;
+            if (t - s_UpdateDelay > 0.1f ||
+                s_UpdateDelay > t) //something went strangely wrong if this second check is true.
+            {
+                s_UpdateDelay = t - 0.001f;
+
+                if(AssetBundleModel.Model.Update())
+                {
+                    m_Parent.Repaint();
+                }
+
+                if (m_DetailsList != null)
+                    m_DetailsList.Update();
+
+                if (m_AssetList != null)
+                    m_AssetList.Update();
+
+            }
+        }
+
+        internal void ForceReloadData()
+        {
+            UpdateSelectedBundles(new List<AssetBundleModel.BundleInfo>());
+            SetSelectedItems(new List<AssetBundleModel.AssetInfo>());
+            m_BundleTree.SetSelection(new int[0]);
+            AssetBundleModel.Model.ForceReloadData(m_BundleTree);
+            m_Parent.Repaint();
+        }
+
+        internal void OnGUI(Rect pos)
+        {
+            m_Position = pos;
+
+            if(m_BundleTree == null)
+            {
+                if (m_AssetListState == null)
+                    m_AssetListState = new TreeViewState();
+
+                var headerState = AssetListTree.CreateDefaultMultiColumnHeaderState();// multiColumnTreeViewRect.width);
+                if (MultiColumnHeaderState.CanOverwriteSerializedFields(m_AssetListMCHState, headerState))
+                    MultiColumnHeaderState.OverwriteSerializedFields(m_AssetListMCHState, headerState);
+                m_AssetListMCHState = headerState;
+
+
+                m_AssetList = new AssetListTree(m_AssetListState, m_AssetListMCHState, this);
+                m_AssetList.Reload();
+                m_MessageList = new MessageList();
+
+                if (m_BundleDetailState == null)
+                    m_BundleDetailState = new TreeViewState();
+                m_DetailsList = new BundleDetailList(m_BundleDetailState);
+                m_DetailsList.Reload();
+
+                if (m_BundleTreeState == null)
+                    m_BundleTreeState = new TreeViewState();
+                m_BundleTree = new AssetBundleTree(m_BundleTreeState, this);
+                m_BundleTree.Refresh();
+                m_Parent.Repaint();
+            }
+            
+            HandleHorizontalResize();
+            HandleVerticalResize();
+
+
+            if (AssetBundleModel.Model.BundleListIsEmpty())
+            {
+                m_BundleTree.OnGUI(m_Position);
+                var style = new GUIStyle(GUI.skin.label);
+                style.alignment = TextAnchor.MiddleCenter;
+                style.wordWrap = true;
+                GUI.Label(
+                    new Rect(m_Position.x + 1f, m_Position.y + 1f, m_Position.width - 2f, m_Position.height - 2f), 
+                    new GUIContent(AssetBundleModel.Model.GetEmptyMessage()),
+                    style);
+            }
+            else
+            {
+
+                //Left half
+                var bundleTreeRect = new Rect(
+                    m_Position.x,
+                    m_Position.y,
+                    m_HorizontalSplitterRect.x,
+                    m_VerticalSplitterRectLeft.y - m_Position.y);
+                
+                m_BundleTree.OnGUI(bundleTreeRect);
+                m_DetailsList.OnGUI(new Rect(
+                    bundleTreeRect.x,
+                    bundleTreeRect.y + bundleTreeRect.height + k_SplitterWidth,
+                    bundleTreeRect.width,
+                    m_Position.height - bundleTreeRect.height - k_SplitterWidth*2));
+
+
+                //Right half.
+                float panelLeft = m_HorizontalSplitterRect.x + k_SplitterWidth;
+                float panelWidth = m_VerticalSplitterRectRight.width - k_SplitterWidth * 2;
+                float searchHeight = 20f;
+                float panelTop = m_Position.y + searchHeight;
+                float panelHeight = m_VerticalSplitterRectRight.y - panelTop;
+                OnGUISearchBar(new Rect(panelLeft, m_Position.y, panelWidth, searchHeight));
+                m_AssetList.OnGUI(new Rect(
+                    panelLeft,
+                    panelTop,
+                    panelWidth,
+                    panelHeight));
+                m_MessageList.OnGUI(new Rect(
+                    panelLeft,
+                    panelTop + panelHeight + k_SplitterWidth,
+                    panelWidth,
+                    (m_Position.height - panelHeight) - k_SplitterWidth * 2));
+
+                if (m_ResizingHorizontalSplitter || m_ResizingVerticalSplitterRight || m_ResizingVerticalSplitterLeft)
+                    m_Parent.Repaint();
+            }
+        }
+
+        void OnGUISearchBar(Rect rect)
+        {
+            m_BundleTree.searchString = m_searchField.OnGUI(rect, m_BundleTree.searchString);
+            m_AssetList.searchString = m_BundleTree.searchString;
+        }
+
+        public bool hasSearch
+        {
+            get { return m_BundleTree.hasSearch;  }
+        }
+
+        private void HandleHorizontalResize()
+        {
+            m_HorizontalSplitterRect.x = (int)(m_Position.width * m_HorizontalSplitterPercent);
+            m_HorizontalSplitterRect.height = m_Position.height;
+
+            EditorGUIUtility.AddCursorRect(m_HorizontalSplitterRect, MouseCursor.ResizeHorizontal);
+            if (Event.current.type == EventType.MouseDown && m_HorizontalSplitterRect.Contains(Event.current.mousePosition))
+                m_ResizingHorizontalSplitter = true;
+
+            if (m_ResizingHorizontalSplitter)
+            {
+                m_HorizontalSplitterPercent = Mathf.Clamp(Event.current.mousePosition.x / m_Position.width, 0.1f, 0.9f);
+                m_HorizontalSplitterRect.x = (int)(m_Position.width * m_HorizontalSplitterPercent);
+            }
+
+            if (Event.current.type == EventType.MouseUp)
+                m_ResizingHorizontalSplitter = false;
+        }
+
+        private void HandleVerticalResize()
+        {
+            m_VerticalSplitterRectRight.x = m_HorizontalSplitterRect.x;
+            m_VerticalSplitterRectRight.y = (int)(m_HorizontalSplitterRect.height * m_VerticalSplitterPercentRight);
+            m_VerticalSplitterRectRight.width = m_Position.width - m_HorizontalSplitterRect.x;
+            m_VerticalSplitterRectLeft.y = (int)(m_HorizontalSplitterRect.height * m_VerticalSplitterPercentLeft);
+            m_VerticalSplitterRectLeft.width = m_VerticalSplitterRectRight.width;
+
+
+            EditorGUIUtility.AddCursorRect(m_VerticalSplitterRectRight, MouseCursor.ResizeVertical);
+            if (Event.current.type == EventType.MouseDown && m_VerticalSplitterRectRight.Contains(Event.current.mousePosition))
+                m_ResizingVerticalSplitterRight = true;
+
+            EditorGUIUtility.AddCursorRect(m_VerticalSplitterRectLeft, MouseCursor.ResizeVertical);
+            if (Event.current.type == EventType.MouseDown && m_VerticalSplitterRectLeft.Contains(Event.current.mousePosition))
+                m_ResizingVerticalSplitterLeft = true;
+
+
+            if (m_ResizingVerticalSplitterRight)
+            {
+                m_VerticalSplitterPercentRight = Mathf.Clamp(Event.current.mousePosition.y / m_HorizontalSplitterRect.height, 0.2f, 0.98f);
+                m_VerticalSplitterRectRight.y = (int)(m_HorizontalSplitterRect.height * m_VerticalSplitterPercentRight);
+            }
+            else if (m_ResizingVerticalSplitterLeft)
+            {
+                m_VerticalSplitterPercentLeft = Mathf.Clamp(Event.current.mousePosition.y / m_HorizontalSplitterRect.height, 0.25f, 0.98f);
+                m_VerticalSplitterRectLeft.y = (int)(m_HorizontalSplitterRect.height * m_VerticalSplitterPercentLeft);
+            }
+
+
+            if (Event.current.type == EventType.MouseUp)
+            {
+                m_ResizingVerticalSplitterRight = false;
+                m_ResizingVerticalSplitterLeft = false;
+            }
+        }
+
+        internal void UpdateSelectedBundles(IEnumerable<AssetBundleModel.BundleInfo> bundles)
+        {
+            AssetBundleModel.Model.AddBundlesToUpdate(bundles);
+            m_AssetList.SetSelectedBundles(bundles);
+            m_DetailsList.SetItems(bundles);
+            m_MessageList.SetItems(null);
+        }
+
+        internal void SetSelectedItems(IEnumerable<AssetBundleModel.AssetInfo> items)
+        {
+            m_MessageList.SetItems(items);
+        }
+    }
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleManageTab.cs.meta

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

+ 9 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: b59abcdb3531bd64ab43572babec263e
+folderAsset: yes
+timeCreated: 1488835755
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 795 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel/ABModel.cs

@@ -0,0 +1,795 @@
+using System;
+using UnityEngine;
+using UnityEditor;
+using UnityEngine.Assertions;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor.IMGUI.Controls;
+
+using AssetBundleBrowser.AssetBundleDataSource;
+
+namespace AssetBundleBrowser.AssetBundleModel
+{
+    /// <summary>
+    /// Static class holding model data for Asset Bundle Browser tool. Data in Model is read from DataSource, but is not pushed.  
+    /// 
+    /// If not using a custom DataSource, then the data comes from the AssetDatabase.  If you wish to alter the data from code, 
+    ///  you should just push changes to the AssetDatabase then tell the Model to Rebuild(). If needed, you can also loop over
+    ///  Update() until it returns true to force all sub-items to refresh.
+    ///  
+    /// </summary>
+    public static class Model
+    {
+        const string k_NewBundleBaseName = "newbundle";
+        const string k_NewVariantBaseName = "newvariant";
+        internal static /*const*/ Color k_LightGrey = Color.grey * 1.5f;
+
+        private static ABDataSource s_DataSource;
+        private static BundleFolderConcreteInfo s_RootLevelBundles = new BundleFolderConcreteInfo("", null);
+        private static List<ABMoveData> s_MoveData = new List<ABMoveData>();
+        private static List<BundleInfo> s_BundlesToUpdate = new List<BundleInfo>();
+        private static Dictionary<string, AssetInfo> s_GlobalAssetList = new Dictionary<string, AssetInfo>();
+        private static Dictionary<string, HashSet<string>> s_DependencyTracker = new Dictionary<string, HashSet<string>>();
+
+        private static bool s_InErrorState = false;
+        const string k_DefaultEmptyMessage = "Drag assets here or right-click to begin creating bundles.";
+        const string k_ProblemEmptyMessage = "There was a problem parsing the list of bundles. See console.";
+        private static string s_EmptyMessageString;
+
+        static private Texture2D s_folderIcon = null;
+        static private Texture2D s_bundleIcon = null;
+        static private Texture2D s_sceneIcon = null;
+
+        /// <summary>
+        /// If using a custom source of asset bundles, you can implement your own ABDataSource and set it here as the active
+        ///  DataSource.  This will allow you to use the Browser with data that you provide.
+        ///  
+        /// If no custom DataSource is provided, then the Browser will create one that feeds off of and into the 
+        ///  AssetDatabase.
+        ///  
+        /// </summary>
+        public static ABDataSource DataSource
+        {
+            get
+            {
+                if (s_DataSource == null)
+                {
+                    s_DataSource = new AssetDatabaseABDataSource ();
+                }
+                return s_DataSource;
+            }
+            set { s_DataSource = value; }
+        }
+
+        /// <summary>
+        /// Update will loop over bundles that need updating and update them. It will only update one bundle
+        ///  per frame and will continue on the same bundle next frame until that bundle is marked as doneUpdating.
+        ///  By default, this will cause a very slow collection of dependency data as it will only update one bundle per
+        /// </summary>
+        public static bool Update()
+        {
+            bool shouldRepaint = false;
+            ExecuteAssetMove(false);     //this should never do anything. just a safety check.
+
+            //TODO - look into EditorApplication callback functions.
+            
+            int size = s_BundlesToUpdate.Count;
+            if (size > 0)
+            {
+                s_BundlesToUpdate[size - 1].Update();
+                s_BundlesToUpdate.RemoveAll(item => item.doneUpdating == true);
+                if (s_BundlesToUpdate.Count == 0)
+                {
+                    shouldRepaint = true;
+                    foreach(var bundle in s_RootLevelBundles.GetChildList())
+                    {
+                        bundle.RefreshDupeAssetWarning();
+                    }
+                }
+            }
+            return shouldRepaint;
+        }
+
+        internal static void ForceReloadData(TreeView tree)
+        {
+            s_InErrorState = false;
+            Rebuild();
+            tree.Reload();
+            bool doneUpdating = s_BundlesToUpdate.Count == 0;
+
+            EditorUtility.DisplayProgressBar("Updating Bundles", "", 0);
+            int fullBundleCount = s_BundlesToUpdate.Count;
+            while (!doneUpdating && !s_InErrorState)
+            {
+                int currCount = s_BundlesToUpdate.Count;
+                EditorUtility.DisplayProgressBar("Updating Bundles", s_BundlesToUpdate[currCount-1].displayName, (float)(fullBundleCount- currCount) / (float)fullBundleCount);
+                doneUpdating = Update();
+            }
+            EditorUtility.ClearProgressBar();
+        }
+        
+        /// <summary>
+        /// Clears and rebuilds model data.  
+        /// </summary>
+        public static void Rebuild()
+        {
+            s_RootLevelBundles = new BundleFolderConcreteInfo("", null);
+            s_MoveData = new List<ABMoveData>();
+            s_BundlesToUpdate = new List<BundleInfo>();
+            s_GlobalAssetList = new Dictionary<string, AssetInfo>();
+            Refresh();
+        }
+
+        internal static void AddBundlesToUpdate(IEnumerable<BundleInfo> bundles)
+        {
+            foreach(var bundle in bundles)
+            {
+                bundle.ForceNeedUpdate();
+                s_BundlesToUpdate.Add(bundle);
+            }
+        }
+
+        internal static void Refresh()
+        {
+            s_EmptyMessageString = k_ProblemEmptyMessage;
+            if (s_InErrorState)
+                return;
+
+            var bundleList = ValidateBundleList();
+            if(bundleList != null)
+            {
+                s_EmptyMessageString = k_DefaultEmptyMessage;
+                foreach (var bundleName in bundleList)
+                {
+                    AddBundleToModel(bundleName);
+                }
+                AddBundlesToUpdate(s_RootLevelBundles.GetChildList());
+            }
+
+            if(s_InErrorState)
+            {
+                s_RootLevelBundles = new BundleFolderConcreteInfo("", null);
+                s_EmptyMessageString = k_ProblemEmptyMessage;
+            }
+        }
+
+        internal static string[] ValidateBundleList()
+        {
+            var bundleList = DataSource.GetAllAssetBundleNames();
+            bool valid = true;
+            HashSet<string> bundleSet = new HashSet<string>();
+            int index = 0;
+            bool attemptedBundleReset = false;
+            while(index < bundleList.Length)
+            {
+                var name = bundleList[index];
+                if (!bundleSet.Add(name))
+                {
+                    LogError("Two bundles share the same name: " + name);
+                    valid = false;
+                }
+
+                int lastDot = name.LastIndexOf('.');
+                if (lastDot > -1)
+                {
+                    var bunName = name.Substring(0, lastDot);
+                    var extraDot = bunName.LastIndexOf('.');
+                    if(extraDot > -1)
+                    {
+                        if(attemptedBundleReset)
+                        {
+                            var message = "Bundle name '" + bunName + "' contains a period.";
+                            message += "  Internally Unity keeps 'bundleName' and 'variantName' separate, but externally treat them as 'bundleName.variantName'.";
+                            message += "  If a bundleName contains a period, the build will (probably) succeed, but this tool cannot tell which portion is bundle and which portion is variant.";
+                            LogError(message);
+                            valid = false;
+                        }
+                        else
+                        {
+                            if (!DataSource.IsReadOnly ())
+                            {
+                                DataSource.RemoveUnusedAssetBundleNames();
+                            }
+                            index = 0;
+                            bundleSet.Clear();
+                            bundleList = DataSource.GetAllAssetBundleNames();
+                            attemptedBundleReset = true;
+                            continue;
+                        }
+                    }
+
+
+                    if (bundleList.Contains(bunName))
+                    {
+                        //there is a bundle.none and a bundle.variant coexisting.  Need to fix that or return an error.
+                        if (attemptedBundleReset)
+                        {
+                            valid = false;
+                            var message = "Bundle name '" + bunName + "' exists without a variant as well as with variant '" + name.Substring(lastDot+1) + "'.";
+                            message += " That is an illegal state that will not build and must be cleaned up.";
+                            LogError(message);
+                        }
+                        else
+                        {
+                            if (!DataSource.IsReadOnly ())
+                            {
+                                DataSource.RemoveUnusedAssetBundleNames();
+                            }
+                            index = 0;
+                            bundleSet.Clear();
+                            bundleList = DataSource.GetAllAssetBundleNames();
+                            attemptedBundleReset = true;
+                            continue;
+                        }
+                    }
+                }
+
+                index++;
+            }
+
+            if (valid)
+                return bundleList;
+            else
+                return null;
+        }
+
+        internal static bool BundleListIsEmpty()
+        {
+            return (s_RootLevelBundles.GetChildList().Count() == 0);
+        }
+
+        internal static string GetEmptyMessage()
+        {
+            return s_EmptyMessageString;
+        }
+
+        internal static BundleInfo CreateEmptyBundle(BundleFolderInfo folder = null, string newName = null)
+        {
+            if ((folder as BundleVariantFolderInfo) != null)
+                return CreateEmptyVariant(folder as BundleVariantFolderInfo);
+
+            folder = (folder == null) ? s_RootLevelBundles : folder;
+            string name = GetUniqueName(folder, newName);
+            BundleNameData nameData;
+            nameData = new BundleNameData(folder.m_Name.bundleName, name);
+            return AddBundleToFolder(folder, nameData);
+        }
+
+        internal static BundleInfo CreateEmptyVariant(BundleVariantFolderInfo folder)
+        {
+            string name = GetUniqueName(folder, k_NewVariantBaseName);
+            string variantName = folder.m_Name.bundleName + "." + name;
+            BundleNameData nameData = new BundleNameData(variantName);
+            return AddBundleToFolder(folder.parent, nameData);
+        }
+
+        internal static BundleFolderInfo CreateEmptyBundleFolder(BundleFolderConcreteInfo folder = null)
+        {
+            folder = (folder == null) ? s_RootLevelBundles : folder;
+            string name = GetUniqueName(folder) + "/dummy";
+            BundleNameData nameData = new BundleNameData(folder.m_Name.bundleName, name);
+            return AddFoldersToBundle(s_RootLevelBundles, nameData);
+        }
+
+        private static BundleInfo AddBundleToModel(string name)
+        {
+            if (name == null)
+                return null;
+            
+            BundleNameData nameData = new BundleNameData(name);
+
+            BundleFolderInfo folder = AddFoldersToBundle(s_RootLevelBundles, nameData);
+            BundleInfo currInfo = AddBundleToFolder(folder, nameData);
+
+            return currInfo;
+        }
+
+        private static BundleFolderConcreteInfo AddFoldersToBundle(BundleFolderInfo root, BundleNameData nameData)
+        {
+            BundleInfo currInfo = root;
+            var folder = currInfo as BundleFolderConcreteInfo;
+            var size = nameData.pathTokens.Count;
+            for (var index = 0; index < size; index++)
+            {
+                if (folder != null)
+                {
+                    currInfo = folder.GetChild(nameData.pathTokens[index]);
+                    if (currInfo == null)
+                    {
+                        currInfo = new BundleFolderConcreteInfo(nameData.pathTokens, index + 1, folder);
+                        folder.AddChild(currInfo);
+                    }
+
+                    folder = currInfo as BundleFolderConcreteInfo;
+                    if (folder == null)
+                    {
+                        s_InErrorState = true;
+                        LogFolderAndBundleNameConflict(currInfo.m_Name.fullNativeName);
+                        break;
+                    }
+                }
+            }
+            return currInfo as BundleFolderConcreteInfo;
+        }
+
+        private static void LogFolderAndBundleNameConflict(string name)
+        {
+            var message = "Bundle '";
+            message += name;
+            message += "' has a name conflict with a bundle-folder.";
+            message += "Display of bundle data and building of bundles will not work.";
+            message += "\nDetails: If you name a bundle 'x/y', then the result of your build will be a bundle named 'y' in a folder named 'x'.  You thus cannot also have a bundle named 'x' at the same level as the folder named 'x'.";
+            LogError(message);
+        }
+
+        private static BundleInfo AddBundleToFolder(BundleFolderInfo root, BundleNameData nameData)
+        {
+            BundleInfo currInfo = root.GetChild(nameData.shortName);
+            if (!System.String.IsNullOrEmpty(nameData.variant))
+            {
+                if(currInfo == null)
+                {
+                    currInfo = new BundleVariantFolderInfo(nameData.bundleName, root);
+                    root.AddChild(currInfo);
+                }
+                var folder = currInfo as BundleVariantFolderInfo;
+                if (folder == null)
+                {
+                    var message = "Bundle named " + nameData.shortName;
+                    message += " exists both as a standard bundle, and a bundle with variants.  ";
+                    message += "This message is not supported for display or actual bundle building.  ";
+                    message += "You must manually fix bundle naming in the inspector.";
+                    
+                    LogError(message);
+                    return null;
+                }
+                
+                
+                currInfo = folder.GetChild(nameData.variant);
+                if (currInfo == null)
+                {
+                    currInfo = new BundleVariantDataInfo(nameData.fullNativeName, folder);
+                    folder.AddChild(currInfo);
+                }
+                
+            }
+            else
+            {
+                if (currInfo == null)
+                {
+                    currInfo = new BundleDataInfo(nameData.fullNativeName, root);
+                    root.AddChild(currInfo);
+                }
+                else
+                {
+                    var dataInfo = currInfo as BundleDataInfo;
+                    if (dataInfo == null)
+                    {
+                        s_InErrorState = true;
+                        LogFolderAndBundleNameConflict(nameData.fullNativeName);
+                    }
+                }
+            }
+            return currInfo;
+        }
+
+        private static string GetUniqueName(BundleFolderInfo folder, string suggestedName = null)
+        {
+            suggestedName = (suggestedName == null) ? k_NewBundleBaseName : suggestedName;
+            string name = suggestedName;
+            int index = 1;
+            bool foundExisting = (folder.GetChild(name) != null);
+            while (foundExisting)
+            {
+                name = suggestedName + index;
+                index++;
+                foundExisting = (folder.GetChild(name) != null);
+            }
+            return name;
+        }
+
+        internal static BundleTreeItem CreateBundleTreeView()
+        {
+            return s_RootLevelBundles.CreateTreeView(-1);
+        }
+
+        internal static AssetTreeItem CreateAssetListTreeView(IEnumerable<AssetBundleModel.BundleInfo> selectedBundles)
+        {
+            var root = new AssetTreeItem();
+            if (selectedBundles != null)
+            {
+                foreach (var bundle in selectedBundles)
+                {
+                    bundle.AddAssetsToNode(root);
+                }
+            }
+            return root;
+        }
+
+        internal static bool HandleBundleRename(BundleTreeItem item, string newName)
+        {
+            var originalName = new BundleNameData(item.bundle.m_Name.fullNativeName);
+
+            var findDot = newName.LastIndexOf('.');
+            var findSlash = newName.LastIndexOf('/');
+            var findBSlash = newName.LastIndexOf('\\');
+            if (findDot == 0 || findSlash == 0 || findBSlash == 0)
+                return false; //can't start a bundle with a / or .
+
+            bool result = item.bundle.HandleRename(newName, 0);
+
+            if (findDot > 0 || findSlash > 0 || findBSlash > 0)
+            {
+                item.bundle.parent.HandleChildRename(newName, string.Empty);
+            }
+
+            ExecuteAssetMove();
+
+            var node = FindBundle(originalName);
+            if (node != null)
+            {
+                var message = "Failed to rename bundle named: ";
+                message += originalName.fullNativeName;
+                message += ".  Most likely this is due to the bundle being assigned to a folder in your Assets directory, AND that folder is either empty or only contains assets that are explicitly assigned elsewhere.";
+                Debug.LogError(message);
+            }
+
+            return result;  
+        }
+
+        internal static void HandleBundleReparent(IEnumerable<BundleInfo> bundles, BundleFolderInfo parent)
+        {
+            parent = (parent == null) ? s_RootLevelBundles : parent;
+            foreach (var bundle in bundles)
+            {
+                bundle.HandleReparent(parent.m_Name.bundleName, parent);
+            }
+            ExecuteAssetMove();
+        }
+
+        internal static void HandleBundleMerge(IEnumerable<BundleInfo> bundles, BundleDataInfo target)
+        {
+            foreach (var bundle in bundles)
+            {
+                bundle.HandleDelete(true, target.m_Name.bundleName, target.m_Name.variant);
+            }
+            ExecuteAssetMove();
+        }
+
+        internal static void HandleBundleDelete(IEnumerable<BundleInfo> bundles)
+        {
+            var nameList = new List<BundleNameData>();
+            foreach (var bundle in bundles)
+            {
+                nameList.Add(bundle.m_Name);
+                bundle.HandleDelete(true);
+            }
+            ExecuteAssetMove();
+
+            //check to see if any bundles are still there...
+            foreach(var name in nameList)
+            {
+                var node = FindBundle(name);
+                if(node != null)
+                {
+                    var message = "Failed to delete bundle named: ";
+                    message += name.fullNativeName;
+                    message += ".  Most likely this is due to the bundle being assigned to a folder in your Assets directory, AND that folder is either empty or only contains assets that are explicitly assigned elsewhere.";
+                    Debug.LogError(message);
+                }
+            }
+        }
+
+        internal static BundleInfo FindBundle(BundleNameData name)
+        {
+            BundleInfo currNode = s_RootLevelBundles;
+            foreach (var token in name.pathTokens)
+            {
+                if(currNode is BundleFolderInfo)
+                {
+                    currNode = (currNode as BundleFolderInfo).GetChild(token);
+                    if (currNode == null)
+                        return null;
+                }
+                else
+                {
+                    return null;
+                }
+            }
+
+            if(currNode is BundleFolderInfo)
+            {
+                currNode = (currNode as BundleFolderInfo).GetChild(name.shortName);
+                if(currNode is BundleVariantFolderInfo)
+                {
+                    currNode = (currNode as BundleVariantFolderInfo).GetChild(name.variant);
+                }
+                return currNode;
+            }
+            else
+            {
+                return null;
+            }
+        }
+
+        internal static BundleInfo HandleDedupeBundles(IEnumerable<BundleInfo> bundles, bool onlyOverlappedAssets)
+        {
+            var newBundle = CreateEmptyBundle();
+            HashSet<string> dupeAssets = new HashSet<string>();
+            HashSet<string> fullAssetList = new HashSet<string>();
+
+            //if they were just selected, then they may still be updating.
+            bool doneUpdating = s_BundlesToUpdate.Count == 0;
+            while (!doneUpdating)
+                doneUpdating = Update();
+
+            foreach (var bundle in bundles)
+            {
+                foreach (var asset in bundle.GetDependencies())
+                {
+                    if (onlyOverlappedAssets)
+                    {
+                        if (!fullAssetList.Add(asset.fullAssetName))
+                            dupeAssets.Add(asset.fullAssetName);
+                    }
+                    else
+                    {
+                        if (asset.IsMessageSet(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles))
+                            dupeAssets.Add(asset.fullAssetName);
+                    }
+                }
+            }
+
+            if (dupeAssets.Count == 0)
+                return null;
+            
+            MoveAssetToBundle(dupeAssets, newBundle.m_Name.bundleName, string.Empty);
+            ExecuteAssetMove();
+            return newBundle;
+        }
+
+        internal static BundleInfo HandleConvertToVariant(BundleDataInfo bundle)
+        {
+            bundle.HandleDelete(true, bundle.m_Name.bundleName, k_NewVariantBaseName);
+            ExecuteAssetMove();
+            var root = bundle.parent.GetChild(bundle.m_Name.shortName) as BundleVariantFolderInfo;
+
+            if (root != null)
+                return root.GetChild(k_NewVariantBaseName);
+            else
+            {
+                //we got here because the converted bundle was empty.
+                var vfolder = new BundleVariantFolderInfo(bundle.m_Name.bundleName, bundle.parent);
+                var vdata = new BundleVariantDataInfo(bundle.m_Name.bundleName + "." + k_NewVariantBaseName, vfolder);
+                bundle.parent.AddChild(vfolder);
+                vfolder.AddChild(vdata);
+                return vdata;
+            }
+        }
+
+        internal class ABMoveData
+        {
+            internal string assetName;
+            internal string bundleName;
+            internal string variantName;
+            internal ABMoveData(string asset, string bundle, string variant)
+            {
+                assetName = asset;
+                bundleName = bundle;
+                variantName = variant;
+            }
+            internal void Apply()
+            {
+                if (!DataSource.IsReadOnly ())
+                {
+                    DataSource.SetAssetBundleNameAndVariant(assetName, bundleName, variantName);
+                }
+            }
+        }
+        internal static void MoveAssetToBundle(AssetInfo asset, string bundleName, string variant)
+        {
+            s_MoveData.Add(new ABMoveData(asset.fullAssetName, bundleName, variant));
+        }
+        internal static void MoveAssetToBundle(string assetName, string bundleName, string variant)
+        {
+            s_MoveData.Add(new ABMoveData(assetName, bundleName, variant));
+        }
+        internal static void MoveAssetToBundle(IEnumerable<AssetInfo> assets, string bundleName, string variant)
+        {
+            foreach (var asset in assets)
+                MoveAssetToBundle(asset, bundleName, variant);
+        }
+        internal static void MoveAssetToBundle(IEnumerable<string> assetNames, string bundleName, string variant)
+        {
+            foreach (var assetName in assetNames)
+                MoveAssetToBundle(assetName, bundleName, variant);
+        }
+
+        internal static void ExecuteAssetMove(bool forceAct=true)
+        {
+            var size = s_MoveData.Count;
+            if(forceAct)
+            {
+                if (size > 0)
+                {
+                    bool autoRefresh = EditorPrefs.GetBool("kAutoRefresh");
+                    EditorPrefs.SetBool("kAutoRefresh", false);
+                    EditorUtility.DisplayProgressBar("Moving assets to bundles", "", 0);
+                    for (int i = 0; i < size; i++)
+                    {
+                        EditorUtility.DisplayProgressBar("Moving assets to bundle " + s_MoveData[i].bundleName, System.IO.Path.GetFileNameWithoutExtension(s_MoveData[i].assetName), (float)i / (float)size);
+                        s_MoveData[i].Apply();
+                    }
+                    EditorUtility.ClearProgressBar();
+                    EditorPrefs.SetBool("kAutoRefresh", autoRefresh);
+                    s_MoveData.Clear();
+                }
+                if (!DataSource.IsReadOnly ())
+                {
+                    DataSource.RemoveUnusedAssetBundleNames();
+                }
+                Refresh();
+            }
+        }
+        
+        //this version of CreateAsset is only used for dependent assets. 
+        internal static AssetInfo CreateAsset(string name, AssetInfo parent)
+        {
+            if (ValidateAsset(name))
+            {
+                var bundleName = GetBundleName(name); 
+                return CreateAsset(name, bundleName, parent);
+            }
+            return null;
+        }
+
+        internal static AssetInfo CreateAsset(string name, string bundleName)
+        {
+            if(ValidateAsset(name))
+            {
+                return CreateAsset(name, bundleName, null);
+            }
+            return null;
+        }
+
+        private static AssetInfo CreateAsset(string name, string bundleName, AssetInfo parent)
+        {
+            if(!System.String.IsNullOrEmpty(bundleName))
+            {
+                return new AssetInfo(name, bundleName);
+            }
+            else
+            {
+                AssetInfo info = null;
+                if(!s_GlobalAssetList.TryGetValue(name, out info))
+                {
+                    info = new AssetInfo(name, string.Empty);
+                    s_GlobalAssetList.Add(name, info);
+                }
+                info.AddParent(parent.displayName);
+                return info;
+            }
+
+        }
+
+        internal static bool ValidateAsset(string name)
+        {
+            if (!name.StartsWith("Assets/"))
+                return false;
+            string ext = System.IO.Path.GetExtension(name);
+            if (ext == ".dll" || ext == ".cs" || ext == ".meta" || ext == ".js" || ext == ".boo")
+                return false;
+
+            return true;
+        }
+
+        internal static string GetBundleName(string asset)
+        {
+            return DataSource.GetAssetBundleName (asset);
+        }
+
+        internal static int RegisterAsset(AssetInfo asset, string bundle)
+        {
+            if(s_DependencyTracker.ContainsKey(asset.fullAssetName))
+            {
+                s_DependencyTracker[asset.fullAssetName].Add(bundle);
+                int count = s_DependencyTracker[asset.fullAssetName].Count;
+                if (count > 1)
+                    asset.SetMessageFlag(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles, true);
+                return count;
+            }
+
+            var bundles = new HashSet<string>();
+            bundles.Add(bundle);
+            s_DependencyTracker.Add(asset.fullAssetName, bundles);
+            return 1;            
+        }
+
+        internal static void UnRegisterAsset(AssetInfo asset, string bundle)
+        {
+            if (s_DependencyTracker == null || asset == null)
+                return;
+
+            if (s_DependencyTracker.ContainsKey(asset.fullAssetName))
+            {
+                s_DependencyTracker[asset.fullAssetName].Remove(bundle);
+                int count = s_DependencyTracker[asset.fullAssetName].Count;
+                switch (count)
+                {
+                    case 0:
+                        s_DependencyTracker.Remove(asset.fullAssetName);
+                        break;
+                    case 1:
+                        asset.SetMessageFlag(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles, false);
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
+        internal static IEnumerable<string> CheckDependencyTracker(AssetInfo asset)
+        {
+            if (s_DependencyTracker.ContainsKey(asset.fullAssetName))
+            {
+                return s_DependencyTracker[asset.fullAssetName];
+            }
+            return new HashSet<string>();
+        }
+        
+        //TODO - switch local cache server on and utilize this method to stay up to date.
+        //static List<string> m_importedAssets = new List<string>();
+        //static List<string> m_deletedAssets = new List<string>();
+        //static List<KeyValuePair<string, string>> m_movedAssets = new List<KeyValuePair<string, string>>();
+        //class AssetBundleChangeListener : AssetPostprocessor
+        //{
+        //    static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
+        //    {
+        //        m_importedAssets.AddRange(importedAssets);
+        //        m_deletedAssets.AddRange(deletedAssets);
+        //        for (int i = 0; i < movedAssets.Length; i++)
+        //            m_movedAssets.Add(new KeyValuePair<string, string>(movedFromAssetPaths[i], movedAssets[i]));
+        //        //m_dirty = true;
+        //    }
+        //}
+
+        static internal void LogError(string message)
+        {
+            Debug.LogError("AssetBundleBrowser: " + message);
+        }
+        static internal void LogWarning(string message)
+        {
+            Debug.LogWarning("AssetBundleBrowser: " + message);
+        }
+
+        static internal Texture2D GetFolderIcon()
+        {
+            if (s_folderIcon == null)
+                FindBundleIcons();
+            return s_folderIcon;
+        }
+        static internal Texture2D GetBundleIcon()
+        {
+            if (s_bundleIcon == null)
+                FindBundleIcons();
+            return s_bundleIcon;
+        }
+        static internal Texture2D GetSceneIcon()
+        {
+            if (s_sceneIcon == null)
+                FindBundleIcons();
+            return s_sceneIcon;
+        }
+        static private void FindBundleIcons()
+        {
+            s_folderIcon = EditorGUIUtility.FindTexture("Folder Icon");
+
+            var packagePath = System.IO.Path.GetFullPath("Packages/com.unity.assetbundlebrowser");
+            if (System.IO.Directory.Exists(packagePath))
+            {
+                s_bundleIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/com.unity.assetbundlebrowser/Editor/Icons/ABundleBrowserIconY1756Basic.png", typeof(Texture2D));
+                s_sceneIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/com.unity.assetbundlebrowser/Editor/Icons/ABundleBrowserIconY1756Scene.png", typeof(Texture2D));
+            }
+        }
+    }
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel/ABModel.cs.meta

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

+ 246 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel/ABModelAssetInfo.cs

@@ -0,0 +1,246 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor.IMGUI.Controls;
+
+namespace AssetBundleBrowser.AssetBundleModel
+{
+    internal sealed class AssetTreeItem : TreeViewItem
+    {
+        private AssetInfo m_asset;
+        internal AssetInfo asset
+        {
+            get { return m_asset; }
+        }
+        internal AssetTreeItem() : base(-1, -1) { }
+        internal AssetTreeItem(AssetInfo a) : base(a != null ? a.fullAssetName.GetHashCode() : Random.Range(int.MinValue, int.MaxValue), 0, a != null ? a.displayName : "failed")
+        {
+            m_asset = a;
+            if (a != null)
+                icon = AssetDatabase.GetCachedIcon(a.fullAssetName) as Texture2D;
+        }
+
+        private Color m_color = new Color(0, 0, 0, 0);
+        internal Color itemColor
+        {
+            get
+            {
+                if (m_color.a == 0.0f && m_asset != null)
+                {
+                    m_color = m_asset.GetColor();
+                }
+                return m_color;
+            }
+            set { m_color = value; }
+        }
+        internal Texture2D MessageIcon()
+        {
+            return MessageSystem.GetIcon(HighestMessageLevel());
+        }
+        internal MessageType HighestMessageLevel()
+        {
+            return m_asset != null ?
+                m_asset.HighestMessageLevel() : MessageType.Error;
+        }
+
+        internal bool ContainsChild(AssetInfo asset)
+        {
+            bool contains = false;
+            if (children == null)
+                return contains;
+
+            if (asset == null)
+                return false;
+            foreach (var child in children)
+            {
+                var c = child as AssetTreeItem;
+                if (c != null && c.asset != null && c.asset.fullAssetName == asset.fullAssetName)
+                {
+                    contains = true;
+                    break;
+                }
+            }
+
+            return contains;
+        }
+
+
+    }
+
+    internal class AssetInfo
+    {
+        internal bool isScene { get; set; }
+        internal bool isFolder { get; set; }
+        internal long fileSize;
+
+        private HashSet<string> m_Parents;
+        private string m_AssetName;
+        private string m_DisplayName;
+        private string m_BundleName;
+        private MessageSystem.MessageState m_AssetMessages = new MessageSystem.MessageState();
+
+        internal AssetInfo(string inName, string bundleName="")
+        {
+            fullAssetName = inName;
+            m_BundleName = bundleName;
+            m_Parents = new HashSet<string>();
+            isScene = false;
+            isFolder = false;
+        }
+
+        internal string fullAssetName
+        {
+            get { return m_AssetName; }
+            set
+            {
+                m_AssetName = value;
+                m_DisplayName = System.IO.Path.GetFileNameWithoutExtension(m_AssetName);
+
+                //TODO - maybe there's a way to ask the AssetDatabase for this size info.
+                System.IO.FileInfo fileInfo = new System.IO.FileInfo(m_AssetName);
+                if (fileInfo.Exists)
+                    fileSize = fileInfo.Length;
+                else
+                    fileSize = 0;
+            }
+        }
+        internal string displayName
+        {
+            get { return m_DisplayName; }
+        }
+        internal string bundleName
+        { get { return System.String.IsNullOrEmpty(m_BundleName) ? "auto" : m_BundleName; } }
+        
+        internal Color GetColor()
+        {
+            if (System.String.IsNullOrEmpty(m_BundleName))
+                return Model.k_LightGrey;
+            else
+                return Color.white;
+        }
+
+        internal bool IsMessageSet(MessageSystem.MessageFlag flag)
+        {
+            return m_AssetMessages.IsSet(flag);
+        }
+        internal void SetMessageFlag(MessageSystem.MessageFlag flag, bool on)
+        {
+            m_AssetMessages.SetFlag(flag, on);
+        }
+        internal MessageType HighestMessageLevel()
+        {
+            return m_AssetMessages.HighestMessageLevel();
+        }
+        internal IEnumerable<MessageSystem.Message> GetMessages()
+        {
+            List<MessageSystem.Message> messages = new List<MessageSystem.Message>();
+            if(IsMessageSet(MessageSystem.MessageFlag.SceneBundleConflict))
+            {
+                var message = displayName + "\n";
+                if (isScene)
+                    message += "Is a scene that is in a bundle with non-scene assets. Scene bundles must have only one or more scene assets.";
+                else
+                    message += "Is included in a bundle with a scene. Scene bundles must have only one or more scene assets.";
+                messages.Add(new MessageSystem.Message(message, MessageType.Error));
+            }
+            if(IsMessageSet(MessageSystem.MessageFlag.DependencySceneConflict))
+            {
+                var message = displayName + "\n";
+                message += MessageSystem.GetMessage(MessageSystem.MessageFlag.DependencySceneConflict).message;
+                messages.Add(new MessageSystem.Message(message, MessageType.Error));
+            }
+            if (IsMessageSet(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles))
+            {
+                var bundleNames = AssetBundleModel.Model.CheckDependencyTracker(this);
+                string message = displayName + "\n" + "Is auto-included in multiple bundles:\n";
+                foreach(var bundleName in bundleNames)
+                {
+                    message += bundleName + ", ";
+                }
+                message = message.Substring(0, message.Length - 2);//remove trailing comma.
+                messages.Add(new MessageSystem.Message(message, MessageType.Warning));
+            }
+
+            if (System.String.IsNullOrEmpty(m_BundleName) && m_Parents.Count > 0)
+            {
+                //TODO - refine the parent list to only include those in the current asset list
+                var message = displayName + "\n" + "Is auto included in bundle(s) due to parent(s): \n";
+                foreach (var parent in m_Parents)
+                {
+                    message += parent + ", ";
+                }
+                message = message.Substring(0, message.Length - 2);//remove trailing comma.
+                messages.Add(new MessageSystem.Message(message, MessageType.Info));
+            }            
+
+            if (m_dependencies != null && m_dependencies.Count > 0)
+            {
+                var message = string.Empty;
+                var sortedDependencies = m_dependencies.OrderBy(d => d.bundleName);
+                foreach (var dependent in sortedDependencies)
+                {
+                    if (dependent.bundleName != bundleName)
+                    {
+                        message += dependent.bundleName + " : " + dependent.displayName + "\n";
+                    }
+                }
+                if (string.IsNullOrEmpty(message) == false)
+                {
+                    message = message.Insert(0, displayName + "\n" + "Is dependent on other bundle's asset(s) or auto included asset(s): \n");
+                    message = message.Substring(0, message.Length - 1);//remove trailing line break.
+                    messages.Add(new MessageSystem.Message(message, MessageType.Info));
+                }
+            }            
+
+            messages.Add(new MessageSystem.Message(displayName + "\n" + "Path: " + fullAssetName, MessageType.Info));
+
+            return messages;
+        }
+        internal void AddParent(string name)
+        {
+            m_Parents.Add(name);
+        }
+        internal void RemoveParent(string name)
+        {
+            m_Parents.Remove(name);
+        }
+
+        internal string GetSizeString()
+        {
+            if (fileSize == 0)
+                return "--";
+            return EditorUtility.FormatBytes(fileSize);
+        }
+
+        List<AssetInfo> m_dependencies = null;
+        internal List<AssetInfo> GetDependencies()
+        {
+            //TODO - not sure this refreshes enough. need to build tests around that.
+            if (m_dependencies == null)
+            {
+                m_dependencies = new List<AssetInfo>();
+                if (AssetDatabase.IsValidFolder(m_AssetName))
+                {
+                    //if we have a folder, its dependencies were already pulled in through alternate means.  no need to GatherFoldersAndFiles
+                    //GatherFoldersAndFiles();
+                }
+                else
+                {
+                    foreach (var dep in AssetDatabase.GetDependencies(m_AssetName, true))
+                    {
+                        if (dep != m_AssetName)
+                        {
+                            var asset = Model.CreateAsset(dep, this);
+                            if (asset != null)
+                                m_dependencies.Add(asset);
+                        }
+                    }
+                }
+            }
+            return m_dependencies;
+        }
+
+    }
+
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel/ABModelAssetInfo.cs.meta

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

+ 1011 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel/ABModelBundleInfo.cs

@@ -0,0 +1,1011 @@
+using System;
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor.IMGUI.Controls;
+
+namespace AssetBundleBrowser.AssetBundleModel
+{
+    internal sealed class BundleTreeItem : TreeViewItem
+    {   
+        private BundleInfo m_Bundle;
+        internal BundleInfo bundle
+        {
+            get { return m_Bundle; }
+        }
+        internal BundleTreeItem(BundleInfo b, int depth, Texture2D iconTexture) : base(b.nameHashCode, depth, b.displayName)
+        {
+            m_Bundle = b;
+            icon = iconTexture;
+            children = new List<TreeViewItem>();
+        }
+
+        internal MessageSystem.Message BundleMessage()
+        {
+            return m_Bundle.HighestMessage();
+        }
+
+        public override string displayName
+        {
+            get
+            {
+                return AssetBundleBrowserMain.instance.m_ManageTab.hasSearch ? m_Bundle.m_Name.fullNativeName : m_Bundle.displayName;
+            }
+        }
+    }
+
+    internal class BundleNameData
+    {
+        private List<string> m_PathTokens;
+        private string m_FullBundleName;
+        private string m_ShortName;
+        private string m_VariantName;
+        private string m_FullNativeName;
+
+        //input (received from native) is a string of format:
+        //  /folder0/.../folderN/name.variant
+        //it's broken into:
+        //  /m_pathTokens[0]/.../m_pathTokens[n]/m_shortName.m_variantName
+        // and...
+        //  m_fullBundleName = /m_pathTokens[0]/.../m_pathTokens[n]/m_shortName
+        // and...
+        //  m_fullNativeName = m_fullBundleName.m_variantName which is the same as the initial input.
+        internal BundleNameData(string name) { SetName(name); }
+        internal BundleNameData(string path, string name)
+        {
+            string finalName = System.String.IsNullOrEmpty(path) ? "" : path + '/';
+            finalName += name;
+            SetName(finalName);
+        }
+        public override int GetHashCode()
+        {
+            return fullNativeName.GetHashCode();
+        }
+        internal string fullNativeName
+        { get { return m_FullNativeName; } }
+
+        internal void SetBundleName(string bundleName, string variantName)
+        {
+            string name = bundleName;
+            name += System.String.IsNullOrEmpty(variantName) ? "" : "." + variantName;
+            SetName(name);
+        }
+        internal string bundleName
+        {
+            get { return m_FullBundleName; }
+            //set { SetName(value); }
+        }
+        internal string shortName
+        {
+            get { return m_ShortName; }
+        }
+        internal string variant
+        {
+            get { return m_VariantName; }
+            set
+            {
+                m_VariantName = value;
+                m_FullNativeName = m_FullBundleName;
+                m_FullNativeName += System.String.IsNullOrEmpty(m_VariantName) ? "" : "." + m_VariantName;
+            }
+        }
+        internal List<string> pathTokens
+        {
+            get { return m_PathTokens; }
+            set
+            {
+                m_PathTokens = value.GetRange(0, value.Count-1);
+                SetShortName(value.Last());
+                GenerateFullName();
+            }
+        }
+
+        private void SetName(string name)
+        {
+            if(m_PathTokens == null)
+                m_PathTokens = new List<string>();
+            else
+                m_PathTokens.Clear();
+
+            int indexOfSlash = name.IndexOf('/');
+            int previousIndex = 0;
+            while(indexOfSlash != -1)
+            {
+                m_PathTokens.Add(name.Substring(previousIndex, (indexOfSlash - previousIndex)));
+                previousIndex = indexOfSlash + 1;
+                indexOfSlash = name.IndexOf('/', previousIndex);
+            }
+            SetShortName(name.Substring(previousIndex));
+            GenerateFullName();
+        }
+        private void SetShortName(string inputName)
+        {
+            m_ShortName = inputName;
+            int indexOfDot = m_ShortName.LastIndexOf('.');
+            if (indexOfDot > -1)
+            {
+                m_VariantName = m_ShortName.Substring(indexOfDot + 1);
+                m_ShortName = m_ShortName.Substring(0, indexOfDot);
+            }
+            else
+                m_VariantName = string.Empty;
+        }
+
+        internal void PartialNameChange(string newToken, int indexFromBack)
+        {
+            if(indexFromBack == 0)
+            {
+                 SetShortName(newToken);
+            }
+            else if(indexFromBack-1 < m_PathTokens.Count)
+            {
+                m_PathTokens[m_PathTokens.Count - indexFromBack] = newToken;
+            }
+            GenerateFullName();
+        }
+
+        private void GenerateFullName()
+        {
+            m_FullBundleName = string.Empty;
+            for(int i = 0; i < m_PathTokens.Count; i++)
+            {
+                m_FullBundleName += m_PathTokens[i];
+                m_FullBundleName += '/';
+            }
+            m_FullBundleName += m_ShortName;
+            m_FullNativeName = m_FullBundleName;
+            m_FullNativeName += System.String.IsNullOrEmpty(m_VariantName) ? "" : "." + m_VariantName;
+        }
+    }
+
+    internal abstract class BundleInfo
+    {
+        protected BundleFolderInfo m_Parent;
+        protected bool m_DoneUpdating;
+        protected bool m_Dirty;
+        internal BundleNameData m_Name;
+        protected MessageSystem.MessageState m_BundleMessages = new MessageSystem.MessageState();
+        protected MessageSystem.Message m_CachedHighMessage = null;
+
+        internal BundleInfo(string name, BundleFolderInfo parent)
+        {
+            m_Name = new BundleNameData(name);
+            m_Parent = parent;
+        }
+
+        internal BundleFolderInfo parent
+        { get { return m_Parent; } }
+        internal virtual string displayName
+        {
+            get { return m_Name.shortName; }
+        }
+        internal virtual int nameHashCode
+        {
+            get { return m_Name.GetHashCode(); }
+        }
+        internal abstract BundleTreeItem CreateTreeView(int depth);
+
+        protected virtual void RefreshMessages()
+        {
+            RefreshEmptyStatus();
+            RefreshDupeAssetWarning();
+            var flag = m_BundleMessages.HighestMessageFlag();
+            m_CachedHighMessage = MessageSystem.GetMessage(flag);
+        }
+        internal abstract bool RefreshEmptyStatus();
+        internal abstract bool RefreshDupeAssetWarning();
+        internal virtual MessageSystem.Message HighestMessage()
+        {
+            if (m_CachedHighMessage == null)
+                RefreshMessages();
+            return m_CachedHighMessage;
+        }
+        internal bool IsMessageSet(MessageSystem.MessageFlag flag)
+        {
+            return m_BundleMessages.IsSet(flag);
+        }
+        internal void SetMessageFlag(MessageSystem.MessageFlag flag, bool on)
+        {
+            m_BundleMessages.SetFlag(flag, on);
+        }
+        internal List<MessageSystem.Message> GetMessages()
+        {
+            return m_BundleMessages.GetMessages();
+        }
+        internal bool HasMessages()
+        {
+            return m_BundleMessages.HasMessages();
+        }
+
+        internal virtual bool HandleRename(string newName, int reverseDepth)
+        {
+            if (reverseDepth == 0)
+            {
+                if (!m_Parent.HandleChildRename(m_Name.shortName, newName))
+                    return false;
+            }
+            m_Name.PartialNameChange(newName, reverseDepth);
+            return true;
+        }
+        internal virtual void HandleDelete(bool isRootOfDelete, string forcedNewName="", string forcedNewVariant = "")
+        {
+            if(isRootOfDelete)
+            {
+                m_Parent.HandleChildRename(m_Name.shortName, string.Empty);
+            }
+        }
+        abstract internal void RefreshAssetList();
+        abstract internal void AddAssetsToNode(AssetTreeItem node);
+        abstract internal void Update();
+        internal virtual bool doneUpdating
+        { get { return m_DoneUpdating; } }
+        internal virtual bool dirty
+        { get { return m_Dirty; } }
+        internal void ForceNeedUpdate()
+        {
+            m_DoneUpdating = false;
+            m_Dirty = true;
+        }
+
+        abstract internal void HandleReparent(string parentName, BundleFolderInfo newParent = null);
+        abstract internal List<AssetInfo> GetDependencies();
+
+        abstract internal bool DoesItemMatchSearch(string search);
+    }
+
+    internal class BundleDataInfo : BundleInfo
+    {
+        protected List<AssetInfo> m_ConcreteAssets;
+        protected List<AssetInfo> m_DependentAssets;
+        protected HashSet<string> m_BundleDependencies;
+        protected int m_ConcreteCounter;
+        protected int m_DependentCounter;
+        protected bool m_IsSceneBundle;
+        protected long m_TotalSize;
+
+        internal BundleDataInfo(string name, BundleFolderInfo parent) : base(name, parent)
+        {
+            m_ConcreteAssets = new List<AssetInfo>();
+            m_DependentAssets = new List<AssetInfo>();
+            m_BundleDependencies = new HashSet<string>();
+            m_ConcreteCounter = 0;
+            m_DependentCounter = 0;
+        }
+        ~BundleDataInfo()
+        {
+            foreach (var asset in m_DependentAssets)
+            {
+                AssetBundleModel.Model.UnRegisterAsset(asset, m_Name.fullNativeName);
+            }
+        }
+        internal override bool HandleRename(string newName, int reverseDepth)
+        { 
+            RefreshAssetList();
+            if (!base.HandleRename(newName, reverseDepth))
+                return false;
+            Model.MoveAssetToBundle(m_ConcreteAssets, m_Name.bundleName, m_Name.variant);
+            return true;
+        }
+        internal override void HandleDelete(bool isRootOfDelete, string forcedNewName="", string forcedNewVariant="")
+        {
+            RefreshAssetList();
+            base.HandleDelete(isRootOfDelete);
+            Model.MoveAssetToBundle(m_ConcreteAssets, forcedNewName, forcedNewVariant);
+        }
+
+        internal string TotalSize()
+        {
+            if (m_TotalSize == 0)
+                return "--";
+            return EditorUtility.FormatBytes(m_TotalSize);
+        }
+
+        internal override void RefreshAssetList()
+        {
+            m_BundleMessages.SetFlag(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles, false);
+            m_BundleMessages.SetFlag(MessageSystem.MessageFlag.SceneBundleConflict, false);
+            m_BundleMessages.SetFlag(MessageSystem.MessageFlag.DependencySceneConflict, false);
+
+            m_ConcreteAssets.Clear();
+            m_TotalSize = 0;
+            m_IsSceneBundle = false;
+
+            foreach (var asset in m_DependentAssets)
+            {
+                AssetBundleModel.Model.UnRegisterAsset(asset, m_Name.fullNativeName);
+            }
+            m_DependentAssets.Clear();
+            m_BundleDependencies.Clear();
+            
+            bool assetInBundle = false;
+            bool sceneError = false;
+            var assets = AssetBundleModel.Model.DataSource.GetAssetPathsFromAssetBundle(m_Name.fullNativeName);
+            foreach(var assetName in assets)
+            {
+                if (AssetDatabase.GetMainAssetTypeAtPath(assetName) == typeof(SceneAsset))
+                {
+                    m_IsSceneBundle = true;
+                    if(assetInBundle)
+                        sceneError = true;
+                }
+                else
+                {
+                    assetInBundle = true;
+                    if (m_IsSceneBundle)
+                        sceneError = true;
+                }
+
+                var bundleName = Model.GetBundleName(assetName);
+                if (System.String.IsNullOrEmpty(bundleName))  
+                {
+                    ///we get here if the current asset is only added due to being in an explicitly added folder
+                    
+
+                    var partialPath = assetName;
+                    while(
+                        !System.String.IsNullOrEmpty(partialPath) && 
+                        partialPath != "Assets" &&
+                        System.String.IsNullOrEmpty(bundleName))
+                    {
+                        partialPath = partialPath.Substring(0, partialPath.LastIndexOf('/'));
+                        bundleName = Model.GetBundleName(partialPath);
+                    }
+                    if(!System.String.IsNullOrEmpty(bundleName))
+                    {
+                        var folderAsset = Model.CreateAsset(partialPath, bundleName);
+                        folderAsset.isFolder = true;
+                        if (m_ConcreteAssets.FindIndex(a => a.displayName == folderAsset.displayName) == -1)
+                        {
+                            m_ConcreteAssets.Add(folderAsset);
+                        }
+                        
+                        m_DependentAssets.Add(Model.CreateAsset(assetName, folderAsset));
+                        if (m_DependentAssets != null && m_DependentAssets.Count > 0)
+                        {
+                            var last = m_DependentAssets.Last();
+                            if (last != null)
+                                m_TotalSize += last.fileSize;
+                        }
+                    }
+                }
+                else
+                {
+                    var newAsset = Model.CreateAsset (assetName, m_Name.fullNativeName);
+                    if (newAsset != null)
+                    {
+                        m_ConcreteAssets.Add(newAsset);
+                        m_TotalSize += m_ConcreteAssets.Last().fileSize;
+                        if (AssetDatabase.GetMainAssetTypeAtPath(assetName) == typeof(SceneAsset))
+                        {
+                            m_IsSceneBundle = true;
+                            m_ConcreteAssets.Last().isScene = true;
+                        }
+                    }
+                }
+            }
+            
+            if(sceneError)
+            {
+                foreach (var asset in m_ConcreteAssets)
+                {
+                    if (asset.isFolder)
+                    {
+                        asset.SetMessageFlag(MessageSystem.MessageFlag.DependencySceneConflict, true);
+                        m_BundleMessages.SetFlag(MessageSystem.MessageFlag.DependencySceneConflict, true);
+                    }
+                    else
+                    {
+                        asset.SetMessageFlag(MessageSystem.MessageFlag.SceneBundleConflict, true);
+                        m_BundleMessages.SetFlag(MessageSystem.MessageFlag.SceneBundleConflict, true);
+                    }
+                }
+            }
+
+
+            m_ConcreteCounter = 0;
+            m_DependentCounter = 0;
+            m_Dirty = true;
+        }
+
+        internal override void AddAssetsToNode(AssetTreeItem node)
+        {
+            foreach (var asset in m_ConcreteAssets)
+                node.AddChild(new AssetTreeItem(asset));
+
+            foreach (var asset in m_DependentAssets)
+            {
+                if(!node.ContainsChild(asset))
+                    node.AddChild(new AssetTreeItem(asset));
+            }
+
+            m_Dirty = false;
+        }
+        internal HashSet<string> GetBundleDependencies()
+        {
+            return m_BundleDependencies;
+        }
+
+        internal override void Update()
+        {
+            int dependents = m_DependentAssets.Count;
+            int bundleDep = m_BundleDependencies.Count;
+            if(m_ConcreteCounter < m_ConcreteAssets.Count)
+            {
+                GatherDependencies(m_ConcreteAssets[m_ConcreteCounter]);
+                m_ConcreteCounter++;
+                m_DoneUpdating = false;
+            }
+            else if (m_DependentCounter < m_DependentAssets.Count)
+            {
+                GatherDependencies(m_DependentAssets[m_DependentCounter], m_Name.fullNativeName);
+                m_DependentCounter++;
+                m_DoneUpdating = false;
+            }
+            else
+            {
+                m_DoneUpdating = true;
+            }
+            m_Dirty = (dependents != m_DependentAssets.Count) || (bundleDep != m_BundleDependencies.Count);
+            if (m_Dirty || m_DoneUpdating)
+                RefreshMessages();
+        }
+
+        private void GatherDependencies(AssetInfo asset, string parentBundle = "")
+        {
+            if (System.String.IsNullOrEmpty(parentBundle))
+                parentBundle = asset.bundleName;
+
+            if (asset == null)
+                return;
+
+            var deps = asset.GetDependencies();
+            if (deps == null)
+                return;
+
+            foreach (var ai in deps)
+            {
+                if (ai == asset || m_ConcreteAssets.Contains(ai) || m_DependentAssets.Contains(ai))
+                    continue;
+
+                var bundleName = AssetBundleModel.Model.DataSource.GetImplicitAssetBundleName(ai.fullAssetName);
+                if (string.IsNullOrEmpty(bundleName))
+                {
+                    m_DependentAssets.Add(ai);
+                    m_TotalSize += ai.fileSize;
+                    if (Model.RegisterAsset(ai, parentBundle) > 1)
+                    {
+                        SetDuplicateWarning();
+                    }
+                }
+                else if(bundleName != m_Name.fullNativeName)
+                {
+                    m_BundleDependencies.Add(bundleName);
+                }
+            }
+        }
+
+        internal override bool RefreshDupeAssetWarning()
+        {
+            foreach(var asset in m_DependentAssets)
+            {
+                if (asset != null && asset.IsMessageSet(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles)) 
+                {
+                    SetDuplicateWarning();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        internal bool IsEmpty()
+        {
+            return (m_ConcreteAssets.Count == 0);
+        }
+
+        internal override bool RefreshEmptyStatus()
+        {
+            bool empty = IsEmpty();
+            m_BundleMessages.SetFlag(MessageSystem.MessageFlag.EmptyBundle, empty);
+            return empty;
+        }
+
+        protected void SetDuplicateWarning()
+        {
+            m_BundleMessages.SetFlag(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles, true);
+            m_Dirty = true;
+        }
+
+        internal bool isSceneBundle
+        { get { return m_IsSceneBundle; } }
+
+        internal override BundleTreeItem CreateTreeView(int depth)
+        {
+            RefreshAssetList();
+            RefreshMessages();
+            if (isSceneBundle)
+                return new BundleTreeItem(this, depth, Model.GetSceneIcon());
+            else
+                return new BundleTreeItem(this, depth, Model.GetBundleIcon());
+        }
+
+        internal override void HandleReparent(string parentName, BundleFolderInfo newParent = null)
+        {
+            RefreshAssetList();
+            string newName = System.String.IsNullOrEmpty(parentName) ? "" : parentName + '/';
+            newName += m_Name.shortName;
+            if (newName == m_Name.bundleName)
+                return;
+
+            if (newParent != null && newParent.GetChild(newName) != null)
+            {
+                Model.LogWarning("An item named '" + newName + "' already exists at this level in hierarchy.  If your desire is to merge bundles, drag one on top of the other.");
+                return;
+            }
+            
+            foreach (var asset in m_ConcreteAssets)
+            {
+                Model.MoveAssetToBundle(asset, newName, m_Name.variant);
+            }
+
+            if (newParent != null)
+            {
+                m_Parent.HandleChildRename(m_Name.shortName, string.Empty);
+                m_Parent = newParent;
+                m_Parent.AddChild(this);
+            }
+            m_Name.SetBundleName(newName, m_Name.variant);
+        }
+
+        internal override List<AssetInfo> GetDependencies()
+        {
+            return m_DependentAssets;
+        }
+
+        internal override bool DoesItemMatchSearch(string search)
+        {
+            foreach(var asset in m_ConcreteAssets)
+            {
+                if (asset.displayName.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0)
+                    return true;
+            }
+            foreach (var asset in m_DependentAssets)
+            {
+                if (asset.displayName.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0)
+                    return true;
+            }
+            return false;
+        }
+    }
+
+    internal class BundleVariantDataInfo : BundleDataInfo
+    {
+        protected List<AssetInfo> m_FolderIncludeAssets = new List<AssetInfo>();
+        internal BundleVariantDataInfo(string name, BundleFolderInfo parent) : base(name, parent)
+        {
+        }
+
+        internal override string displayName
+        {
+            get { return m_Name.variant; }
+        }
+        internal override void Update()
+        {
+            base.Update();
+            (m_Parent as BundleVariantFolderInfo).ValidateVariants();
+        }
+        internal override void RefreshAssetList()
+        {
+            m_FolderIncludeAssets.Clear();
+            base.RefreshAssetList();
+            if(m_DependentAssets.Count > 0)
+                m_FolderIncludeAssets = new List<AssetInfo>(m_DependentAssets);
+        }
+        internal bool IsSceneVariant()
+        {
+            RefreshAssetList();
+            return isSceneBundle;
+        }
+        internal override bool HandleRename(string newName, int reverseDepth)
+        {
+            if (reverseDepth == 0)
+            {
+                RefreshAssetList();
+                if (!m_Parent.HandleChildRename(m_Name.variant, newName))
+                    return false;
+                m_Name.variant = newName;
+                Model.MoveAssetToBundle(m_ConcreteAssets, m_Name.bundleName, m_Name.variant);
+            }
+            else if (reverseDepth == 1)
+            {
+                RefreshAssetList();
+                m_Name.PartialNameChange(newName + "." + m_Name.variant, 0);
+                Model.MoveAssetToBundle(m_ConcreteAssets, m_Name.bundleName, m_Name.variant);
+            }
+            else
+            {
+                return base.HandleRename(newName, reverseDepth-1);
+            }
+            return true;
+        }
+        internal override void HandleDelete(bool isRootOfDelete, string forcedNewName = "", string forcedNewVariant = "")
+        {
+            RefreshAssetList();
+            if (isRootOfDelete)
+            {
+                m_Parent.HandleChildRename(m_Name.variant, string.Empty);
+            }
+            Model.MoveAssetToBundle(m_ConcreteAssets, forcedNewName, forcedNewVariant);
+        }
+
+        internal bool FindContentMismatch(BundleVariantDataInfo other)
+        {
+            bool result = false;
+
+            if (m_FolderIncludeAssets.Count != 0 || other.m_FolderIncludeAssets.Count != 0)
+            {
+                var myUniqueAssets = new HashSet<string>();
+                var otherUniqueAssets = new HashSet<string>(other.m_FolderIncludeAssets.Select(x => x.displayName));
+
+                foreach (var asset in m_FolderIncludeAssets)
+                {
+                    if (!otherUniqueAssets.Remove(asset.displayName))
+                    {
+                        myUniqueAssets.Add(asset.displayName);
+                    }
+                }
+
+                if (myUniqueAssets.Count > 0)
+                {
+                    m_BundleMessages.SetFlag(MessageSystem.MessageFlag.VariantBundleMismatch, true);
+                    result = true;
+                }
+                if (otherUniqueAssets.Count > 0)
+                {
+                    other.m_BundleMessages.SetFlag(MessageSystem.MessageFlag.VariantBundleMismatch, true);
+                    result = true;
+                }
+            }
+            else //this doesn't cover the super weird case of including a folder and some explicit assets. TODO - fix that.
+            {
+                var myUniqueAssets = new HashSet<string>();
+                var otherUniqueAssets = new HashSet<string>(other.m_ConcreteAssets.Select(x => x.displayName));
+
+                foreach (var asset in m_ConcreteAssets)
+                {
+                    if (!otherUniqueAssets.Remove(asset.displayName))
+                    {
+                        myUniqueAssets.Add(asset.displayName);
+                    }
+                }
+
+                if (myUniqueAssets.Count > 0)
+                {
+                    m_BundleMessages.SetFlag(MessageSystem.MessageFlag.VariantBundleMismatch, true);
+                    result = true;
+                }
+                if (otherUniqueAssets.Count > 0)
+                {
+                    other.m_BundleMessages.SetFlag(MessageSystem.MessageFlag.VariantBundleMismatch, true);
+                    result = true;
+                }
+            }
+            return result;
+        }
+    }
+
+
+    internal abstract class BundleFolderInfo : BundleInfo
+    {
+        protected Dictionary<string, BundleInfo> m_Children;
+
+        internal BundleFolderInfo(string name, BundleFolderInfo parent) : base(name, parent)
+        {
+            m_Children = new Dictionary<string, BundleInfo>();
+        }
+        
+        internal BundleFolderInfo(List<string> path, int depth, BundleFolderInfo parent) : base("", parent)
+        {
+            m_Children = new Dictionary<string, BundleInfo>();
+            m_Name = new BundleNameData("");
+            m_Name.pathTokens = path.GetRange(0, depth);
+        }
+
+        internal BundleInfo GetChild(string name)
+        {
+            if (name == null)
+                return null;
+
+            BundleInfo info = null;
+            if (m_Children.TryGetValue(name, out info))
+                return info;
+            return null;
+        }
+        internal Dictionary<string, BundleInfo>.ValueCollection GetChildList()
+        {
+            return m_Children.Values;
+        }
+        internal abstract void AddChild(BundleInfo info);
+
+        internal override bool HandleRename(string newName, int reverseDepth)
+        {
+            if (!base.HandleRename(newName, reverseDepth))
+                return false;
+
+            foreach (var child in m_Children)
+            {
+                child.Value.HandleRename(newName, reverseDepth + 1);
+            }
+            return true;
+        }
+
+        internal override void HandleDelete(bool isRootOfDelete, string forcedNewName="", string forcedNewVariant = "")
+        {
+            base.HandleDelete(isRootOfDelete);
+            foreach (var child in m_Children)
+            {
+                child.Value.HandleDelete(false, forcedNewName, forcedNewVariant);
+            }
+            m_Children.Clear();
+        }
+
+        internal override bool DoesItemMatchSearch(string search)
+        {
+            return false; //folders don't ever match.
+        }
+
+        protected override void RefreshMessages()
+        {
+            m_BundleMessages.SetFlag(MessageSystem.MessageFlag.ErrorInChildren, false);
+            foreach(var child in m_Children)
+            {
+                if (child.Value.IsMessageSet(MessageSystem.MessageFlag.Error))
+                {
+                    m_BundleMessages.SetFlag(MessageSystem.MessageFlag.ErrorInChildren, true);
+                    break;
+                }
+            }
+            base.RefreshMessages();
+        }
+        internal override bool RefreshEmptyStatus()
+        {
+            bool empty = m_Children.Count == 0;
+            foreach (var child in m_Children)
+            {
+                empty |= child.Value.RefreshEmptyStatus();
+            }
+            m_BundleMessages.SetFlag(MessageSystem.MessageFlag.EmptyFolder, empty);
+            return empty;
+        }
+
+        internal override void RefreshAssetList()
+        {
+            foreach (var child in m_Children)
+            {
+                child.Value.RefreshAssetList();
+            }
+        }
+        internal override bool RefreshDupeAssetWarning()
+        {
+            bool dupeWarning = false;
+            foreach (var child in m_Children)
+            {
+                dupeWarning |= child.Value.RefreshDupeAssetWarning();
+            }
+            m_BundleMessages.SetFlag(MessageSystem.MessageFlag.WarningInChildren, dupeWarning);
+            return dupeWarning;
+        }
+        internal override void AddAssetsToNode(AssetTreeItem node)
+        {
+            foreach (var child in m_Children)
+            {
+                child.Value.AddAssetsToNode(node);
+            }
+            m_Dirty = false;
+        }
+        internal virtual bool HandleChildRename(string oldName, string newName)
+        {
+
+            if (!System.String.IsNullOrEmpty(newName) && m_Children.ContainsKey(newName))
+            {
+                Model.LogWarning("Attempting to name an item '" + newName + "' which matches existing name at this level in hierarchy.  If your desire is to merge bundles, drag one on top of the other.");
+                return false;
+            }
+
+            BundleInfo info = null;
+            if (m_Children.TryGetValue(oldName, out info))
+            {
+                m_Children.Remove(oldName);
+                if (!System.String.IsNullOrEmpty(newName))
+                    m_Children.Add(newName, info);
+            }
+            return true;
+        }
+
+        internal override void Update()
+        {
+            m_Dirty = false;
+            m_DoneUpdating = true;
+            foreach (var child in m_Children)
+            {
+                child.Value.Update();
+                m_Dirty |= child.Value.dirty;
+                m_DoneUpdating &= child.Value.doneUpdating;
+            }
+
+            if (m_Dirty || m_DoneUpdating)
+                RefreshMessages();
+        }
+        internal override bool doneUpdating
+        {
+            get
+            {
+                foreach (var child in m_Children)
+                {
+                    m_DoneUpdating &= child.Value.doneUpdating;
+                }
+                return base.doneUpdating;
+            }
+        }
+
+
+        internal override List<AssetInfo> GetDependencies()
+        {
+            List<AssetInfo> assets = new List<AssetInfo>();
+            foreach (var child in m_Children)
+            {
+                assets.AddRange(child.Value.GetDependencies());
+            }
+            return assets;
+        }
+    }
+
+    internal class BundleFolderConcreteInfo : BundleFolderInfo
+    {
+        internal BundleFolderConcreteInfo(string name, BundleFolderInfo parent) : base(name, parent)
+        {
+        }
+
+        internal BundleFolderConcreteInfo(List<string> path, int depth, BundleFolderInfo parent) : base(path, depth, parent)
+        {
+        }
+
+        internal override void AddChild(BundleInfo info)
+        {
+            m_Children.Add(info.displayName, info);
+        }
+        internal override BundleTreeItem CreateTreeView(int depth)
+        {
+            RefreshMessages();
+            var result = new BundleTreeItem(this, depth, Model.GetFolderIcon());
+            foreach (var child in m_Children)
+            {
+                result.AddChild(child.Value.CreateTreeView(depth + 1));
+            }
+            return result;
+        }
+        internal override void HandleReparent(string parentName, BundleFolderInfo newParent = null)
+        {
+            string newName = System.String.IsNullOrEmpty(parentName) ? "" : parentName + '/';
+            newName += displayName;
+            if (newName == m_Name.bundleName)
+                return;
+
+            if (newParent != null && newParent.GetChild(newName) != null)
+            {
+                Model.LogWarning("An item named '" + newName + "' already exists at this level in hierarchy.  If your desire is to merge bundles, drag one on top of the other.");
+                return;
+            }
+
+            foreach (var child in m_Children)
+            {
+                child.Value.HandleReparent(newName);
+            }
+
+            if (newParent != null)
+            {
+                m_Parent.HandleChildRename(m_Name.shortName, string.Empty);
+                m_Parent = newParent;
+                m_Parent.AddChild(this);
+            }
+            m_Name.SetBundleName(newName, m_Name.variant);
+        }
+    }
+
+
+    internal class BundleVariantFolderInfo : BundleFolderInfo
+    {
+        internal BundleVariantFolderInfo(string name, BundleFolderInfo parent) : base(name, parent)
+        {
+        }
+        internal override void AddChild(BundleInfo info)
+        {
+            m_Children.Add(info.m_Name.variant, info);
+        }
+        private bool m_validated;
+        internal override void Update()
+        {
+            m_validated = false;
+            base.Update();
+            if(!m_validated)
+               ValidateVariants();
+        }
+        internal void ValidateVariants()
+        {
+            m_validated = true;
+            bool childMismatch = false;
+            if(m_Children.Count > 1)
+            {
+                BundleVariantDataInfo goldChild = null;
+                foreach(var c in m_Children)
+                {
+                    var child = c.Value as BundleVariantDataInfo;
+                    child.SetMessageFlag(MessageSystem.MessageFlag.VariantBundleMismatch, false);
+                    if (goldChild == null)
+                    {
+                        goldChild = child;
+                        continue;
+                    }
+                    childMismatch |= goldChild.FindContentMismatch(child);
+                }
+            }
+            m_BundleMessages.SetFlag(MessageSystem.MessageFlag.VariantBundleMismatch, childMismatch);
+
+        }
+
+        internal override BundleTreeItem CreateTreeView(int depth)
+        {
+            RefreshMessages();
+            Texture2D icon = null;
+            if ((m_Children.Count > 0) &&
+                ((m_Children.First().Value as BundleVariantDataInfo).IsSceneVariant()))
+            {
+                icon = Model.GetSceneIcon();
+            }
+            else
+                icon = Model.GetBundleIcon();
+
+            var result = new BundleTreeItem(this, depth, icon);
+            foreach (var child in m_Children)
+            {
+                result.AddChild(child.Value.CreateTreeView(depth + 1));
+            }
+            return result;
+        }
+
+        internal override void HandleReparent(string parentName, BundleFolderInfo newParent = null)
+        {
+            string newName = System.String.IsNullOrEmpty(parentName) ? "" : parentName + '/';
+            newName += displayName;
+            if (newName == m_Name.bundleName)
+                return;
+
+            if (newParent != null && newParent.GetChild(newName) != null)
+            {
+                Model.LogWarning("An item named '" + newName + "' already exists at this level in hierarchy.  If your desire is to merge bundles, drag one on top of the other.");
+                return;
+            }
+
+            foreach (var child in m_Children)
+            {
+                child.Value.HandleReparent(parentName);
+            }
+
+            if (newParent != null)
+            {
+                m_Parent.HandleChildRename(m_Name.shortName, string.Empty);
+                m_Parent = newParent;
+                m_Parent.AddChild(this);
+            }
+            m_Name.SetBundleName(newName, string.Empty) ;
+        }
+        internal override bool HandleChildRename(string oldName, string newName)
+        {
+            var result = base.HandleChildRename(oldName, newName);
+            if (m_Children.Count == 0)
+                HandleDelete(true);
+            return result;
+        }
+    }
+
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleModel/ABModelBundleInfo.cs.meta

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

+ 647 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleTree.cs

@@ -0,0 +1,647 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections.Generic;
+using UnityEditor.IMGUI.Controls;
+using System.Linq;
+using System;
+
+
+namespace AssetBundleBrowser
+{
+    internal class AssetBundleTree : TreeView
+    { 
+        AssetBundleManageTab m_Controller;
+        private bool m_ContextOnItem = false;
+        List<UnityEngine.Object> m_EmptyObjectList = new List<UnityEngine.Object>();
+
+        internal AssetBundleTree(TreeViewState state, AssetBundleManageTab ctrl) : base(state)
+        {
+            AssetBundleModel.Model.Rebuild();
+            m_Controller = ctrl;
+            showBorder = true;
+        }
+
+        protected override bool CanMultiSelect(TreeViewItem item)
+        {
+            return true;
+        }
+
+        protected override bool CanRename(TreeViewItem item)
+        {
+            return item != null && item.displayName.Length > 0;
+        }
+
+        protected override bool DoesItemMatchSearch(TreeViewItem item, string search)
+        {
+            var bundleItem = item as AssetBundleModel.BundleTreeItem;
+            return bundleItem.bundle.DoesItemMatchSearch(search);
+        }
+
+        protected override void RowGUI(RowGUIArgs args)
+        {
+            var bundleItem = (args.item as AssetBundleModel.BundleTreeItem);
+            if (args.item.icon == null)
+                extraSpaceBeforeIconAndLabel = 16f;
+            else
+                extraSpaceBeforeIconAndLabel = 0f;
+
+            Color old = GUI.color;
+            if ((bundleItem.bundle as AssetBundleModel.BundleVariantFolderInfo) != null)
+                GUI.color = AssetBundleModel.Model.k_LightGrey; //new Color(0.3f, 0.5f, 0.85f);
+            base.RowGUI(args);
+            GUI.color = old;
+
+            var message = bundleItem.BundleMessage();
+            if(message.severity != MessageType.None)
+            {
+                var size = args.rowRect.height;
+                var right = args.rowRect.xMax;
+                Rect messageRect = new Rect(right - size, args.rowRect.yMin, size, size);
+                GUI.Label(messageRect, new GUIContent(message.icon, message.message ));
+            }
+        }
+
+        protected override void RenameEnded(RenameEndedArgs args)
+        { 
+            base.RenameEnded(args);
+            if (args.newName.Length > 0 && args.newName != args.originalName)
+            {
+                args.newName = args.newName.ToLower();
+                args.acceptedRename = true;
+
+                AssetBundleModel.BundleTreeItem renamedItem = FindItem(args.itemID, rootItem) as AssetBundleModel.BundleTreeItem;
+                args.acceptedRename = AssetBundleModel.Model.HandleBundleRename(renamedItem, args.newName);
+                ReloadAndSelect(renamedItem.bundle.nameHashCode, false);
+            }
+            else
+            {
+                args.acceptedRename = false;
+            }
+        }
+
+        protected override TreeViewItem BuildRoot()
+        {
+            AssetBundleModel.Model.Refresh();
+            var root = AssetBundleModel.Model.CreateBundleTreeView();
+            return root;
+        }
+
+        protected override void SelectionChanged(IList<int> selectedIds)
+        {
+
+            var selectedBundles = new List<AssetBundleModel.BundleInfo>();
+            if (selectedIds != null)
+            {
+                foreach (var id in selectedIds)
+                {
+                    var item = FindItem(id, rootItem) as AssetBundleModel.BundleTreeItem;
+                    if(item != null && item.bundle != null)
+                    {
+                        item.bundle.RefreshAssetList();
+                        selectedBundles.Add(item.bundle);
+                    }
+                }
+            }
+
+            m_Controller.UpdateSelectedBundles(selectedBundles);
+        }
+
+        public override void OnGUI(Rect rect)
+        {
+            base.OnGUI(rect);
+            if(Event.current.type == EventType.MouseDown && Event.current.button == 0 && rect.Contains(Event.current.mousePosition))
+            {
+                SetSelection(new int[0], TreeViewSelectionOptions.FireSelectionChanged);
+            }
+        }
+
+
+        protected override void ContextClicked()
+        {
+            if (m_ContextOnItem)
+            {
+                m_ContextOnItem = false;
+                return;
+            }
+
+            List<AssetBundleModel.BundleTreeItem> selectedNodes = new List<AssetBundleModel.BundleTreeItem>();
+            GenericMenu menu = new GenericMenu();
+
+            if (!AssetBundleModel.Model.DataSource.IsReadOnly ()) {
+                menu.AddItem(new GUIContent("Add new bundle"), false, CreateNewBundle, selectedNodes); 
+                menu.AddItem(new GUIContent("Add new folder"), false, CreateFolder, selectedNodes);
+            }
+
+            menu.AddItem(new GUIContent("Reload all data"), false, ForceReloadData, selectedNodes);
+            menu.ShowAsContext();
+        }
+
+        protected override void ContextClickedItem(int id)
+        {
+            if (AssetBundleModel.Model.DataSource.IsReadOnly ()) {
+                return;
+            }
+
+            m_ContextOnItem = true;
+            List<AssetBundleModel.BundleTreeItem> selectedNodes = new List<AssetBundleModel.BundleTreeItem>();
+            foreach (var nodeID in GetSelection())
+            {
+                selectedNodes.Add(FindItem(nodeID, rootItem) as AssetBundleModel.BundleTreeItem);
+            }
+            
+            GenericMenu menu = new GenericMenu();
+            
+            if(selectedNodes.Count == 1)
+            {
+                if ((selectedNodes[0].bundle as AssetBundleModel.BundleFolderConcreteInfo) != null)
+                {
+                    menu.AddItem(new GUIContent("Add Child/New Bundle"), false, CreateNewBundle, selectedNodes);
+                    menu.AddItem(new GUIContent("Add Child/New Folder"), false, CreateFolder, selectedNodes);
+                    menu.AddItem(new GUIContent("Add Sibling/New Bundle"), false, CreateNewSiblingBundle, selectedNodes);
+                    menu.AddItem(new GUIContent("Add Sibling/New Folder"), false, CreateNewSiblingFolder, selectedNodes);
+                }
+                else if( (selectedNodes[0].bundle as AssetBundleModel.BundleVariantFolderInfo) != null)
+                {
+                    menu.AddItem(new GUIContent("Add Child/New Variant"), false, CreateNewVariant, selectedNodes);
+                    menu.AddItem(new GUIContent("Add Sibling/New Bundle"), false, CreateNewSiblingBundle, selectedNodes);
+                    menu.AddItem(new GUIContent("Add Sibling/New Folder"), false, CreateNewSiblingFolder, selectedNodes);
+                }
+                else
+                {
+                    var variant = selectedNodes[0].bundle as AssetBundleModel.BundleVariantDataInfo;
+                    if (variant == null)
+                    {
+                        menu.AddItem(new GUIContent("Add Sibling/New Bundle"), false, CreateNewSiblingBundle, selectedNodes);
+                        menu.AddItem(new GUIContent("Add Sibling/New Folder"), false, CreateNewSiblingFolder, selectedNodes);
+                        menu.AddItem(new GUIContent("Convert to variant"), false, ConvertToVariant, selectedNodes);
+                    }
+                    else
+                    {
+                        menu.AddItem(new GUIContent("Add Sibling/New Variant"), false, CreateNewSiblingVariant, selectedNodes);
+                    }
+                }
+                if(selectedNodes[0].bundle.IsMessageSet(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles))
+                    menu.AddItem(new GUIContent("Move duplicates to new bundle"), false, DedupeAllBundles, selectedNodes);
+                menu.AddItem(new GUIContent("Rename"), false, RenameBundle, selectedNodes);
+                menu.AddItem(new GUIContent("Delete " + selectedNodes[0].displayName), false, DeleteBundles, selectedNodes);
+                
+            }
+            else if (selectedNodes.Count > 1)
+            { 
+                menu.AddItem(new GUIContent("Move duplicates shared by selected"), false, DedupeOverlappedBundles, selectedNodes);
+                menu.AddItem(new GUIContent("Move duplicates existing in any selected"), false, DedupeAllBundles, selectedNodes);
+                menu.AddItem(new GUIContent("Delete " + selectedNodes.Count + " selected bundles"), false, DeleteBundles, selectedNodes);
+            }
+            menu.ShowAsContext();
+        }
+        void ForceReloadData(object context)
+        {
+            AssetBundleModel.Model.ForceReloadData(this);
+        }
+
+        void CreateNewSiblingFolder(object context)
+        {
+            var selectedNodes = context as List<AssetBundleModel.BundleTreeItem>;
+            if (selectedNodes != null && selectedNodes.Count > 0)
+            {
+                AssetBundleModel.BundleFolderConcreteInfo folder = null;
+                folder = selectedNodes[0].bundle.parent as AssetBundleModel.BundleFolderConcreteInfo;
+                CreateFolderUnderParent(folder);
+            }
+            else
+                Debug.LogError("could not add 'sibling' with no bundles selected");
+        }
+        void CreateFolder(object context)
+        {
+            AssetBundleModel.BundleFolderConcreteInfo folder = null;
+            var selectedNodes = context as List<AssetBundleModel.BundleTreeItem>;
+            if (selectedNodes != null && selectedNodes.Count > 0)
+            {
+                folder = selectedNodes[0].bundle as AssetBundleModel.BundleFolderConcreteInfo;
+            }
+            CreateFolderUnderParent(folder);
+        }
+        void CreateFolderUnderParent(AssetBundleModel.BundleFolderConcreteInfo folder)
+        {
+            var newBundle = AssetBundleModel.Model.CreateEmptyBundleFolder(folder);
+            ReloadAndSelect(newBundle.nameHashCode, true);
+        }
+        void RenameBundle(object context)
+        {
+            var selectedNodes = context as List<AssetBundleModel.BundleTreeItem>;
+            if (selectedNodes != null && selectedNodes.Count > 0)
+            {
+                BeginRename(FindItem(selectedNodes[0].bundle.nameHashCode, rootItem));
+            }
+        }
+
+        void CreateNewSiblingBundle(object context)
+        {
+            var selectedNodes = context as List<AssetBundleModel.BundleTreeItem>;
+            if (selectedNodes != null && selectedNodes.Count > 0)
+            {
+                AssetBundleModel.BundleFolderConcreteInfo folder = null;
+                folder = selectedNodes[0].bundle.parent as AssetBundleModel.BundleFolderConcreteInfo;
+                CreateBundleUnderParent(folder);
+            }
+            else
+                Debug.LogError("could not add 'sibling' with no bundles selected");
+        }
+        void CreateNewBundle(object context)
+        {
+            AssetBundleModel.BundleFolderConcreteInfo folder = null;
+            var selectedNodes = context as List<AssetBundleModel.BundleTreeItem>;
+            if (selectedNodes != null && selectedNodes.Count > 0)
+            {
+                folder = selectedNodes[0].bundle as AssetBundleModel.BundleFolderConcreteInfo;
+            }
+            CreateBundleUnderParent(folder);
+        }
+
+        void CreateBundleUnderParent(AssetBundleModel.BundleFolderInfo folder)
+        {
+            var newBundle = AssetBundleModel.Model.CreateEmptyBundle(folder);
+            ReloadAndSelect(newBundle.nameHashCode, true);
+        }
+
+
+        void CreateNewSiblingVariant(object context)
+        {
+            var selectedNodes = context as List<AssetBundleModel.BundleTreeItem>;
+            if (selectedNodes != null && selectedNodes.Count > 0)
+            {
+                AssetBundleModel.BundleVariantFolderInfo folder = null;
+                folder = selectedNodes[0].bundle.parent as AssetBundleModel.BundleVariantFolderInfo;
+                CreateVariantUnderParent(folder);
+            }
+            else
+                Debug.LogError("could not add 'sibling' with no bundles selected");
+        }
+        void CreateNewVariant(object context)
+        {
+            AssetBundleModel.BundleVariantFolderInfo folder = null;
+            var selectedNodes = context as List<AssetBundleModel.BundleTreeItem>;
+            if (selectedNodes != null && selectedNodes.Count == 1)
+            {
+                folder = selectedNodes[0].bundle as AssetBundleModel.BundleVariantFolderInfo;
+                CreateVariantUnderParent(folder);
+            }
+        }
+        void CreateVariantUnderParent(AssetBundleModel.BundleVariantFolderInfo folder)
+        {
+            if (folder != null)
+            {
+                var newBundle = AssetBundleModel.Model.CreateEmptyVariant(folder);
+                ReloadAndSelect(newBundle.nameHashCode, true);
+            }
+        }
+
+        void ConvertToVariant(object context)
+        {
+            var selectedNodes = context as List<AssetBundleModel.BundleTreeItem>;
+            if (selectedNodes.Count == 1)
+            {
+                var bundle = selectedNodes[0].bundle as AssetBundleModel.BundleDataInfo;
+                var newBundle = AssetBundleModel.Model.HandleConvertToVariant(bundle);
+                int hash = 0;
+                if (newBundle != null)
+                    hash = newBundle.nameHashCode;
+                ReloadAndSelect(hash, true);
+            }
+        }
+
+        void DedupeOverlappedBundles(object context)
+        {
+            DedupeBundles(context, true);
+        }
+        void DedupeAllBundles(object context)
+        {
+            DedupeBundles(context, false);
+        }
+        void DedupeBundles(object context, bool onlyOverlappedAssets)
+        {
+            var selectedNodes = context as List<AssetBundleModel.BundleTreeItem>;
+            var newBundle = AssetBundleModel.Model.HandleDedupeBundles(selectedNodes.Select(item => item.bundle), onlyOverlappedAssets);
+            if(newBundle != null)
+            {
+                var selection = new List<int>();
+                selection.Add(newBundle.nameHashCode);
+                ReloadAndSelect(selection);
+            }
+            else
+            {
+                if (onlyOverlappedAssets)
+                    Debug.LogWarning("There were no duplicated assets that existed across all selected bundles.");
+                else
+                    Debug.LogWarning("No duplicate assets found after refreshing bundle contents.");
+            }
+        }
+
+        void DeleteBundles(object b)
+        {
+            var selectedNodes = b as List<AssetBundleModel.BundleTreeItem>;
+            AssetBundleModel.Model.HandleBundleDelete(selectedNodes.Select(item => item.bundle));
+            ReloadAndSelect(new List<int>());
+
+
+        }
+        protected override void KeyEvent()
+        {
+            if (Event.current.keyCode == KeyCode.Delete && GetSelection().Count > 0)
+            {
+                List<AssetBundleModel.BundleTreeItem> selectedNodes = new List<AssetBundleModel.BundleTreeItem>();
+                foreach (var nodeID in GetSelection())
+                {
+                    selectedNodes.Add(FindItem(nodeID, rootItem) as AssetBundleModel.BundleTreeItem);
+                }
+                DeleteBundles(selectedNodes);
+            }
+        }
+
+        class DragAndDropData
+        {
+            internal bool hasBundleFolder = false;
+            internal bool hasScene = false;
+            internal bool hasNonScene = false;
+            internal bool hasVariantChild = false;
+            internal List<AssetBundleModel.BundleInfo> draggedNodes;
+            internal AssetBundleModel.BundleTreeItem targetNode;
+            internal DragAndDropArgs args;
+            internal string[] paths;
+
+            internal DragAndDropData(DragAndDropArgs a)
+            {
+                args = a;
+                draggedNodes = DragAndDrop.GetGenericData("AssetBundleModel.BundleInfo") as List<AssetBundleModel.BundleInfo>;
+                targetNode = args.parentItem as AssetBundleModel.BundleTreeItem;
+                paths = DragAndDrop.paths;
+
+                if (draggedNodes != null)
+                {
+                    foreach (var bundle in draggedNodes)
+                    {
+                        if ((bundle as AssetBundleModel.BundleFolderInfo) != null)
+                        {
+                            hasBundleFolder = true;
+                        }
+                        else
+                        {
+                            var dataBundle = bundle as AssetBundleModel.BundleDataInfo;
+                            if (dataBundle != null)
+                            {
+                                if (dataBundle.isSceneBundle)
+                                    hasScene = true;
+                                else
+                                    hasNonScene = true;
+
+                                if ( (dataBundle as AssetBundleModel.BundleVariantDataInfo) != null)
+                                    hasVariantChild = true;
+                            }
+                        }
+                    }
+                }
+                else if (DragAndDrop.paths != null)
+                {
+                    foreach (var assetPath in DragAndDrop.paths)
+                    {
+                        if (AssetDatabase.GetMainAssetTypeAtPath(assetPath) == typeof(SceneAsset))
+                            hasScene = true;
+                        else
+                            hasNonScene = true;
+                    }
+                }
+            }
+
+        }
+        protected override DragAndDropVisualMode HandleDragAndDrop(DragAndDropArgs args)
+        {
+            DragAndDropVisualMode visualMode = DragAndDropVisualMode.None;
+            DragAndDropData data = new DragAndDropData(args);
+            
+            if (AssetBundleModel.Model.DataSource.IsReadOnly ()) {
+                return DragAndDropVisualMode.Rejected;
+            }
+
+            if ( (data.hasScene && data.hasNonScene) ||
+                (data.hasVariantChild) )
+                return DragAndDropVisualMode.Rejected;
+            
+            switch (args.dragAndDropPosition)
+            {
+                case DragAndDropPosition.UponItem:
+                    visualMode = HandleDragDropUpon(data);
+                    break;
+                case DragAndDropPosition.BetweenItems:
+                    visualMode = HandleDragDropBetween(data);
+                    break;
+                case DragAndDropPosition.OutsideItems:
+                    if (data.draggedNodes != null)
+                    {
+                        visualMode = DragAndDropVisualMode.Copy;
+                        if (data.args.performDrop)
+                        {
+                            AssetBundleModel.Model.HandleBundleReparent(data.draggedNodes, null);
+                            Reload();
+                        }
+                    }
+                    else if(data.paths != null)
+                    {
+                        visualMode = DragAndDropVisualMode.Copy;
+                        if (data.args.performDrop)
+                        {
+                            DragPathsToNewSpace(data.paths, null);
+                        }
+                    }
+                    break;
+            }
+            return visualMode;
+        }
+
+        private DragAndDropVisualMode HandleDragDropUpon(DragAndDropData data)
+        {
+            DragAndDropVisualMode visualMode = DragAndDropVisualMode.Copy;//Move;
+            var targetDataBundle = data.targetNode.bundle as AssetBundleModel.BundleDataInfo;
+            if (targetDataBundle != null)
+            {
+                if (targetDataBundle.isSceneBundle)
+                {
+                    if(data.hasNonScene)
+                        return DragAndDropVisualMode.Rejected;
+                }
+                else
+                {
+                    if (data.hasBundleFolder)
+                    {
+                        return DragAndDropVisualMode.Rejected;
+                    }
+                    else if (data.hasScene && !targetDataBundle.IsEmpty())
+                    {
+                        return DragAndDropVisualMode.Rejected;
+                    }
+
+                }
+
+               
+                if (data.args.performDrop)
+                {
+                    if (data.draggedNodes != null)
+                    {
+                        AssetBundleModel.Model.HandleBundleMerge(data.draggedNodes, targetDataBundle);
+                        ReloadAndSelect(targetDataBundle.nameHashCode, false);
+                    }
+                    else if (data.paths != null)
+                    {
+                        AssetBundleModel.Model.MoveAssetToBundle(data.paths, targetDataBundle.m_Name.bundleName, targetDataBundle.m_Name.variant);
+                        AssetBundleModel.Model.ExecuteAssetMove();
+                        ReloadAndSelect(targetDataBundle.nameHashCode, false);
+                    }
+                }
+
+            }
+            else
+            {
+                var folder = data.targetNode.bundle as AssetBundleModel.BundleFolderInfo;
+                if (folder != null)
+                {
+                    if (data.args.performDrop)
+                    {
+                        if (data.draggedNodes != null)
+                        {
+                            AssetBundleModel.Model.HandleBundleReparent(data.draggedNodes, folder);
+                            Reload();
+                        }
+                        else if (data.paths != null)
+                        {
+                            DragPathsToNewSpace(data.paths, folder);
+                        }
+                    }
+                }
+                else
+                    visualMode = DragAndDropVisualMode.Rejected; //must be a variantfolder
+                
+            }
+            return visualMode;
+        }
+        private DragAndDropVisualMode HandleDragDropBetween(DragAndDropData data)
+        {
+            DragAndDropVisualMode visualMode = DragAndDropVisualMode.Copy;//Move;
+
+            var parent = (data.args.parentItem as AssetBundleModel.BundleTreeItem);
+
+            if (parent != null)
+            {
+                var variantFolder = parent.bundle as AssetBundleModel.BundleVariantFolderInfo;
+                if (variantFolder != null)
+                    return DragAndDropVisualMode.Rejected;
+
+                if (data.args.performDrop)
+                {
+                    var folder = parent.bundle as AssetBundleModel.BundleFolderConcreteInfo;
+                    if (folder != null)
+                    {
+                        if (data.draggedNodes != null)
+                        {
+                            AssetBundleModel.Model.HandleBundleReparent(data.draggedNodes, folder);
+                            Reload();
+                        }
+                        else if (data.paths != null)
+                        {
+                            DragPathsToNewSpace(data.paths, folder);
+                        }
+                    }
+                }
+            }
+
+            return visualMode;
+        }
+
+        private string[] dragToNewSpacePaths = null;
+        private AssetBundleModel.BundleFolderInfo dragToNewSpaceRoot = null;
+        private void DragPathsAsOneBundle()
+        {
+            var newBundle = AssetBundleModel.Model.CreateEmptyBundle(dragToNewSpaceRoot);
+            AssetBundleModel.Model.MoveAssetToBundle(dragToNewSpacePaths, newBundle.m_Name.bundleName, newBundle.m_Name.variant);
+            AssetBundleModel.Model.ExecuteAssetMove();
+            ReloadAndSelect(newBundle.nameHashCode, true);
+        }
+        private void DragPathsAsManyBundles()
+        {
+            List<int> hashCodes = new List<int>();
+            foreach (var assetPath in dragToNewSpacePaths)
+            {
+                var newBundle = AssetBundleModel.Model.CreateEmptyBundle(dragToNewSpaceRoot, System.IO.Path.GetFileNameWithoutExtension(assetPath).ToLower());
+                AssetBundleModel.Model.MoveAssetToBundle(assetPath, newBundle.m_Name.bundleName, newBundle.m_Name.variant);
+                hashCodes.Add(newBundle.nameHashCode);
+            }
+            AssetBundleModel.Model.ExecuteAssetMove();
+            ReloadAndSelect(hashCodes);
+        }
+
+        private void DragPathsToNewSpace(string[] paths, AssetBundleModel.BundleFolderInfo root)
+        {
+            dragToNewSpacePaths = paths;
+            dragToNewSpaceRoot = root;
+            if (paths.Length > 1)
+            {
+                GenericMenu menu = new GenericMenu();
+                menu.AddItem(new GUIContent("Create 1 Bundle"), false, DragPathsAsOneBundle);
+                var message = "Create ";
+                message += paths.Length;
+                message += " Bundles";
+                menu.AddItem(new GUIContent(message), false, DragPathsAsManyBundles);
+                menu.ShowAsContext();
+            }
+            else
+                DragPathsAsManyBundles();
+        }
+
+        protected override void SetupDragAndDrop(SetupDragAndDropArgs args)
+        {
+            if (args.draggedItemIDs == null)
+                return;
+
+            DragAndDrop.PrepareStartDrag();
+
+            var selectedBundles = new List<AssetBundleModel.BundleInfo>();
+            foreach (var id in args.draggedItemIDs)
+            {
+                var item = FindItem(id, rootItem) as AssetBundleModel.BundleTreeItem;
+                selectedBundles.Add(item.bundle);
+            }
+            DragAndDrop.paths = null;
+            DragAndDrop.objectReferences = m_EmptyObjectList.ToArray();
+            DragAndDrop.SetGenericData("AssetBundleModel.BundleInfo", selectedBundles);
+            DragAndDrop.visualMode = DragAndDropVisualMode.Copy;//Move;
+            DragAndDrop.StartDrag("AssetBundleTree");
+        }
+
+        protected override bool CanStartDrag(CanStartDragArgs args)
+        {
+            return true;
+        }
+
+        internal void Refresh()
+        {
+            var selection = GetSelection();
+            Reload();
+            SelectionChanged(selection);
+        }
+
+        private void ReloadAndSelect(int hashCode, bool rename)
+        {
+            var selection = new List<int>();
+            selection.Add(hashCode);
+            ReloadAndSelect(selection);
+            if(rename)
+            {
+                BeginRename(FindItem(hashCode, rootItem), 0.25f);
+            }
+        }
+        private void ReloadAndSelect(IList<int> hashCodes)
+        {
+            Reload();
+            SetSelection(hashCodes, TreeViewSelectionOptions.RevealAndFrame);
+            SelectionChanged(hashCodes);
+        }
+    }
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetBundleTree.cs.meta

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

+ 447 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetListTree.cs

@@ -0,0 +1,447 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections.Generic;
+using UnityEditor.IMGUI.Controls;
+using System.Linq;
+//using System;
+
+
+namespace AssetBundleBrowser
+{
+    internal class AssetListTree : TreeView
+    {
+        List<AssetBundleModel.BundleInfo> m_SourceBundles = new List<AssetBundleModel.BundleInfo>();
+        AssetBundleManageTab m_Controller;
+        List<UnityEngine.Object> m_EmptyObjectList = new List<UnityEngine.Object>();
+
+        internal static MultiColumnHeaderState CreateDefaultMultiColumnHeaderState()
+        {
+            return new MultiColumnHeaderState(GetColumns());
+        }
+        private static MultiColumnHeaderState.Column[] GetColumns()
+        {
+            var retVal = new MultiColumnHeaderState.Column[] {
+                new MultiColumnHeaderState.Column(),
+                new MultiColumnHeaderState.Column(),
+                new MultiColumnHeaderState.Column(),
+                new MultiColumnHeaderState.Column()
+            };
+            retVal[0].headerContent = new GUIContent("Asset", "Short name of asset. For full name select asset and see message below");
+            retVal[0].minWidth = 50;
+            retVal[0].width = 100;
+            retVal[0].maxWidth = 300;
+            retVal[0].headerTextAlignment = TextAlignment.Left;
+            retVal[0].canSort = true;
+            retVal[0].autoResize = true;
+
+            retVal[1].headerContent = new GUIContent("Bundle", "Bundle name. 'auto' means asset was pulled in due to dependency");
+            retVal[1].minWidth = 50;
+            retVal[1].width = 100;
+            retVal[1].maxWidth = 300;
+            retVal[1].headerTextAlignment = TextAlignment.Left;
+            retVal[1].canSort = true;
+            retVal[1].autoResize = true;
+
+            retVal[2].headerContent = new GUIContent("Size", "Size on disk");
+            retVal[2].minWidth = 30;
+            retVal[2].width = 75;
+            retVal[2].maxWidth = 100;
+            retVal[2].headerTextAlignment = TextAlignment.Left;
+            retVal[2].canSort = true;
+            retVal[2].autoResize = true;
+
+            retVal[3].headerContent = new GUIContent("!", "Errors, Warnings, or Info");
+            retVal[3].minWidth = 16;
+            retVal[3].width = 16;
+            retVal[3].maxWidth = 16;
+            retVal[3].headerTextAlignment = TextAlignment.Left;
+            retVal[3].canSort = true;
+            retVal[3].autoResize = false;
+
+            return retVal;
+        }
+        enum MyColumns
+        {
+            Asset,
+            Bundle,
+            Size,
+            Message
+        }
+        internal enum SortOption
+        {
+            Asset,
+            Bundle,
+            Size,
+            Message
+        }
+        SortOption[] m_SortOptions =
+        {
+            SortOption.Asset,
+            SortOption.Bundle,
+            SortOption.Size,
+            SortOption.Message
+        };
+
+        internal AssetListTree(TreeViewState state, MultiColumnHeaderState mchs, AssetBundleManageTab ctrl ) : base(state, new MultiColumnHeader(mchs))
+        {
+            m_Controller = ctrl;
+            showBorder = true;
+            showAlternatingRowBackgrounds = true;
+            multiColumnHeader.sortingChanged += OnSortingChanged;
+        }
+
+
+        internal void Update()
+        {
+            bool dirty = false;
+            foreach (var bundle in m_SourceBundles)
+            {
+                dirty |= bundle.dirty;
+            }
+            if (dirty)
+                Reload();
+        }
+        public override void OnGUI(Rect rect)
+        {
+            base.OnGUI(rect);
+            if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && rect.Contains(Event.current.mousePosition))
+            {
+                SetSelection(new int[0], TreeViewSelectionOptions.FireSelectionChanged);
+            }
+        }
+
+
+        protected override IList<TreeViewItem> BuildRows(TreeViewItem root)
+        {
+            var rows = base.BuildRows(root);
+            SortIfNeeded(root, rows);
+            return rows;
+        }
+
+        internal void SetSelectedBundles(IEnumerable<AssetBundleModel.BundleInfo> bundles)
+        {
+            m_Controller.SetSelectedItems(null);
+            m_SourceBundles = bundles.ToList();
+            SetSelection(new List<int>());
+            Reload();
+        }
+        protected override TreeViewItem BuildRoot()
+        {
+            var root = AssetBundleModel.Model.CreateAssetListTreeView(m_SourceBundles);
+            return root;
+        }
+
+        protected override void RowGUI(RowGUIArgs args)
+        {
+            for (int i = 0; i < args.GetNumVisibleColumns(); ++i)
+                CellGUI(args.GetCellRect(i), args.item as AssetBundleModel.AssetTreeItem, args.GetColumn(i), ref args);
+        }
+
+        private void CellGUI(Rect cellRect, AssetBundleModel.AssetTreeItem item, int column, ref RowGUIArgs args)
+        {
+            Color oldColor = GUI.color;
+            CenterRectUsingSingleLineHeight(ref cellRect);
+            if(column != 3)
+               GUI.color = item.itemColor;
+
+            switch (column)
+            {
+                case 0:
+                    {
+                        var iconRect = new Rect(cellRect.x + 1, cellRect.y + 1, cellRect.height - 2, cellRect.height - 2);
+                        if(item.icon != null)
+                            GUI.DrawTexture(iconRect, item.icon, ScaleMode.ScaleToFit);
+                        DefaultGUI.Label(
+                            new Rect(cellRect.x + iconRect.xMax + 1, cellRect.y, cellRect.width - iconRect.width, cellRect.height), 
+                            item.displayName, 
+                            args.selected, 
+                            args.focused);
+                    }
+                    break;
+                case 1:
+                    DefaultGUI.Label(cellRect, item.asset.bundleName, args.selected, args.focused);
+                    break;
+                case 2:
+                    DefaultGUI.Label(cellRect, item.asset.GetSizeString(), args.selected, args.focused);
+                    break;
+                case 3:
+                    var icon = item.MessageIcon();
+                    if (icon != null)
+                    {
+                        var iconRect = new Rect(cellRect.x, cellRect.y, cellRect.height, cellRect.height);
+                        GUI.DrawTexture(iconRect, icon, ScaleMode.ScaleToFit);
+                    }
+                    break;
+            }
+            GUI.color = oldColor;
+        }
+
+        protected override void DoubleClickedItem(int id)
+        {
+            var assetItem = FindItem(id, rootItem) as AssetBundleModel.AssetTreeItem;
+            if (assetItem != null)
+            {
+                Object o = AssetDatabase.LoadAssetAtPath<Object>(assetItem.asset.fullAssetName);
+                EditorGUIUtility.PingObject(o);
+                Selection.activeObject = o;
+            }
+        }
+
+        protected override void SelectionChanged(IList<int> selectedIds)
+        {
+            if (selectedIds == null)
+                return;
+
+            List<Object> selectedObjects = new List<Object>();
+            List<AssetBundleModel.AssetInfo> selectedAssets = new List<AssetBundleModel.AssetInfo>();
+            foreach (var id in selectedIds)
+            {
+                var assetItem = FindItem(id, rootItem) as AssetBundleModel.AssetTreeItem;
+                if (assetItem != null)
+                {
+                    Object o = AssetDatabase.LoadAssetAtPath<Object>(assetItem.asset.fullAssetName);
+                    selectedObjects.Add(o);
+                    Selection.activeObject = o;
+                    selectedAssets.Add(assetItem.asset);
+                }
+            }
+            m_Controller.SetSelectedItems(selectedAssets);
+            Selection.objects = selectedObjects.ToArray();
+        }
+        protected override bool CanBeParent(TreeViewItem item)
+        {
+            return false;
+        }
+
+        protected override bool CanStartDrag(CanStartDragArgs args)
+        {
+            args.draggedItemIDs = GetSelection();
+            return true;
+        }
+
+        protected override void SetupDragAndDrop(SetupDragAndDropArgs args)
+        {
+            DragAndDrop.PrepareStartDrag();
+            DragAndDrop.objectReferences = m_EmptyObjectList.ToArray();
+            List<AssetBundleModel.AssetTreeItem> items = 
+                new List<AssetBundleModel.AssetTreeItem>(args.draggedItemIDs.Select(id => FindItem(id, rootItem) as AssetBundleModel.AssetTreeItem));
+            DragAndDrop.paths = items.Select(a => a.asset.fullAssetName).ToArray();
+            DragAndDrop.SetGenericData("AssetListTreeSource", this);
+            DragAndDrop.StartDrag("AssetListTree");
+        }
+        
+        protected override DragAndDropVisualMode HandleDragAndDrop(DragAndDropArgs args)
+        {
+            if(IsValidDragDrop())
+            {
+                if (args.performDrop)
+                {
+                    AssetBundleModel.Model.MoveAssetToBundle(DragAndDrop.paths, m_SourceBundles[0].m_Name.bundleName, m_SourceBundles[0].m_Name.variant);
+                    AssetBundleModel.Model.ExecuteAssetMove();
+                    foreach (var bundle in m_SourceBundles)
+                    {
+                        bundle.RefreshAssetList();
+                    }
+                    m_Controller.UpdateSelectedBundles(m_SourceBundles);
+                }
+                return DragAndDropVisualMode.Copy;//Move;
+            }
+
+            return DragAndDropVisualMode.Rejected;
+        }
+        protected bool IsValidDragDrop()
+        {
+            //can't do drag & drop if data source is read only
+            if (AssetBundleModel.Model.DataSource.IsReadOnly ())
+                return false;
+
+            //can't drag onto none or >1 bundles
+            if (m_SourceBundles.Count == 0 || m_SourceBundles.Count > 1)
+                return false;
+            
+            //can't drag nothing
+            if (DragAndDrop.paths == null || DragAndDrop.paths.Length == 0)
+                return false;
+
+            //can't drag into a folder
+            var folder = m_SourceBundles[0] as AssetBundleModel.BundleFolderInfo;
+            if (folder != null)
+                return false;
+
+            var data = m_SourceBundles[0] as AssetBundleModel.BundleDataInfo;
+            if(data == null)
+                return false; // this should never happen.
+
+            var thing = DragAndDrop.GetGenericData("AssetListTreeSource") as AssetListTree;
+            if (thing != null)
+                return false;
+            
+            if(data.IsEmpty())
+                return true;
+
+
+            if (data.isSceneBundle)
+            {
+                foreach (var assetPath in DragAndDrop.paths)
+                {
+                    if ((AssetDatabase.GetMainAssetTypeAtPath(assetPath) != typeof(SceneAsset)) &&
+                        (!AssetDatabase.IsValidFolder(assetPath)))
+                        return false;
+                }
+            }
+            else
+            {
+                foreach (var assetPath in DragAndDrop.paths)
+                {
+                    if (AssetDatabase.GetMainAssetTypeAtPath(assetPath) == typeof(SceneAsset))
+                        return false;
+                }
+            }
+
+            return true;
+
+        }
+
+        protected override void ContextClickedItem(int id)
+        {
+            if (AssetBundleModel.Model.DataSource.IsReadOnly ()) {
+                return;
+            }
+
+            List<AssetBundleModel.AssetTreeItem> selectedNodes = new List<AssetBundleModel.AssetTreeItem>();
+            foreach(var nodeID in GetSelection())
+            {
+                selectedNodes.Add(FindItem(nodeID, rootItem) as AssetBundleModel.AssetTreeItem);
+            }
+
+            if(selectedNodes.Count > 0)
+            {
+                GenericMenu menu = new GenericMenu();
+                menu.AddItem(new GUIContent("Remove asset(s) from bundle."), false, RemoveAssets, selectedNodes);
+                menu.ShowAsContext();
+            }
+
+        }
+        void RemoveAssets(object obj)
+        {
+            var selectedNodes = obj as List<AssetBundleModel.AssetTreeItem>;
+            var assets = new List<AssetBundleModel.AssetInfo>();
+            //var bundles = new List<AssetBundleModel.BundleInfo>();
+            foreach (var node in selectedNodes)
+            {
+                if (!System.String.IsNullOrEmpty(node.asset.bundleName))
+                    assets.Add(node.asset);
+            }
+            AssetBundleModel.Model.MoveAssetToBundle(assets, string.Empty, string.Empty);
+            AssetBundleModel.Model.ExecuteAssetMove();
+            foreach (var bundle in m_SourceBundles)
+            {
+                bundle.RefreshAssetList();
+            }
+            m_Controller.UpdateSelectedBundles(m_SourceBundles);
+            //ReloadAndSelect(new List<int>());
+        }
+
+        protected override void KeyEvent()
+        {
+            if (m_SourceBundles.Count > 0 && Event.current.keyCode == KeyCode.Delete && GetSelection().Count > 0)
+            {
+                List<AssetBundleModel.AssetTreeItem> selectedNodes = new List<AssetBundleModel.AssetTreeItem>();
+                foreach (var nodeID in GetSelection())
+                {
+                    selectedNodes.Add(FindItem(nodeID, rootItem) as AssetBundleModel.AssetTreeItem);
+                }
+
+                RemoveAssets(selectedNodes);
+            }
+        }
+        void OnSortingChanged(MultiColumnHeader multiColumnHeader)
+        {
+            SortIfNeeded(rootItem, GetRows());
+        }
+        void SortIfNeeded(TreeViewItem root, IList<TreeViewItem> rows)
+        {
+            if (rows.Count <= 1)
+                return;
+
+            if (multiColumnHeader.sortedColumnIndex == -1)
+                return;
+
+            SortByColumn();
+
+            rows.Clear();
+            for (int i = 0; i < root.children.Count; i++)
+                rows.Add(root.children[i]);
+
+            Repaint();
+        }
+        void SortByColumn()
+        {
+            var sortedColumns = multiColumnHeader.state.sortedColumns;
+
+            if (sortedColumns.Length == 0)
+                return;
+
+            List<AssetBundleModel.AssetTreeItem> assetList = new List<AssetBundleModel.AssetTreeItem>();
+            foreach(var item in rootItem.children)
+            {
+                assetList.Add(item as AssetBundleModel.AssetTreeItem);
+            }
+            var orderedItems = InitialOrder(assetList, sortedColumns);
+
+            rootItem.children = orderedItems.Cast<TreeViewItem>().ToList();
+        }
+
+        IOrderedEnumerable<AssetBundleModel.AssetTreeItem> InitialOrder(IEnumerable<AssetBundleModel.AssetTreeItem> myTypes, int[] columnList)
+        {
+            SortOption sortOption = m_SortOptions[columnList[0]];
+            bool ascending = multiColumnHeader.IsSortedAscending(columnList[0]);
+            switch (sortOption)
+            {
+                case SortOption.Asset:
+                    return myTypes.Order(l => l.displayName, ascending);
+                case SortOption.Size:
+                    return myTypes.Order(l => l.asset.fileSize, ascending);
+                case SortOption.Message:
+                    return myTypes.Order(l => l.HighestMessageLevel(), ascending);
+                case SortOption.Bundle:
+                default:
+                    return myTypes.Order(l => l.asset.bundleName, ascending);
+            }
+            
+        }
+
+        private void ReloadAndSelect(IList<int> hashCodes)
+        {
+            Reload();
+            SetSelection(hashCodes);
+            SelectionChanged(hashCodes);
+        }
+    }
+    static class MyExtensionMethods
+    {
+        internal static IOrderedEnumerable<T> Order<T, TKey>(this IEnumerable<T> source, System.Func<T, TKey> selector, bool ascending)
+        {
+            if (ascending)
+            {
+                return source.OrderBy(selector);
+            }
+            else
+            {
+                return source.OrderByDescending(selector);
+            }
+        }
+
+        internal static IOrderedEnumerable<T> ThenBy<T, TKey>(this IOrderedEnumerable<T> source, System.Func<T, TKey> selector, bool ascending)
+        {
+            if (ascending)
+            {
+                return source.ThenBy(selector);
+            }
+            else
+            {
+                return source.ThenByDescending(selector);
+            }
+        }
+    }
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/AssetListTree.cs.meta

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

+ 170 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/BundleDetailList.cs

@@ -0,0 +1,170 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections.Generic;
+using UnityEditor.IMGUI.Controls;
+
+namespace AssetBundleBrowser
+{
+    internal class BundleDetailItem : TreeViewItem
+    {
+        internal BundleDetailItem(int id, int depth, string displayName, MessageType type) : base(id, depth, displayName)
+        {
+            MessageLevel = type;
+        }
+
+        internal MessageType MessageLevel
+        { get; set; }
+    }
+    internal class BundleDetailList : TreeView
+    {
+        HashSet<AssetBundleModel.BundleDataInfo> m_Selecteditems;
+        Rect m_TotalRect;
+
+        const float k_DoubleIndent = 32f;
+        const string k_SizeHeader = "Size: ";
+        const string k_DependencyHeader = "Dependent On:";
+        const string k_DependencyEmpty = k_DependencyHeader + " - None";
+        const string k_MessageHeader = "Messages:";
+        const string k_MessageEmpty = k_MessageHeader + " - None";
+
+
+        internal BundleDetailList(TreeViewState state) : base(state)
+        {
+            m_Selecteditems = new HashSet<AssetBundleModel.BundleDataInfo>();
+            showBorder = true;
+        }
+        internal void Update()
+        {
+            bool dirty = false;
+            foreach (var bundle in m_Selecteditems)
+            {
+                dirty |= bundle.dirty;
+            }
+            if (dirty)
+            {
+                Reload();
+                ExpandAll();
+            }
+        }
+        protected override TreeViewItem BuildRoot()
+        {
+            var root = new TreeViewItem(-1, -1);
+            root.children = new List<TreeViewItem>();
+            if (m_Selecteditems != null)
+            {
+                foreach(var bundle in m_Selecteditems)
+                {
+                    root.AddChild(AppendBundleToTree(bundle));
+                }
+            }
+            return root;
+        }
+
+        protected override void RowGUI(RowGUIArgs args)
+        {
+            if ((args.item as BundleDetailItem) != null)
+            {
+                EditorGUI.HelpBox(
+                    new Rect(args.rowRect.x + k_DoubleIndent, args.rowRect.y, args.rowRect.width - k_DoubleIndent, args.rowRect.height), 
+                    args.item.displayName,
+                    (args.item as BundleDetailItem).MessageLevel);
+            }
+            else
+            {
+                Color old = GUI.color;
+                if (args.item.depth == 1 &&
+                    (args.item.displayName == k_MessageEmpty || args.item.displayName == k_DependencyEmpty))
+                    GUI.color = AssetBundleModel.Model.k_LightGrey;
+                base.RowGUI(args);
+                GUI.color = old;
+            }
+        }
+        public override void OnGUI(Rect rect)
+        {
+            m_TotalRect = rect;
+            base.OnGUI(rect);
+        }
+        protected override float GetCustomRowHeight(int row, TreeViewItem item)
+        {
+            if( (item as BundleDetailItem) != null)
+            {
+                float height = DefaultStyles.backgroundEven.CalcHeight(new GUIContent(item.displayName), m_TotalRect.width);
+                return height + 3f;
+            }
+            return base.GetCustomRowHeight(row, item);
+        }
+
+
+        internal static TreeViewItem AppendBundleToTree(AssetBundleModel.BundleDataInfo bundle)
+        {
+            var itemName = bundle.m_Name.fullNativeName;
+            var bunRoot = new TreeViewItem(itemName.GetHashCode(), 0, itemName);
+
+            var str = itemName + k_SizeHeader;
+            var sz = new TreeViewItem(str.GetHashCode(), 1, k_SizeHeader + bundle.TotalSize());
+
+            str = itemName + k_DependencyHeader;
+            var dependency = new TreeViewItem(str.GetHashCode(), 1, k_DependencyEmpty);
+            var depList = bundle.GetBundleDependencies();
+            if(depList.Count > 0)
+            {
+                dependency.displayName = k_DependencyHeader;
+                foreach (var dep in bundle.GetBundleDependencies())
+                {
+                    str = itemName + dep;
+                    dependency.AddChild(new TreeViewItem(str.GetHashCode(), 2, dep));
+                }
+            }
+
+            str = itemName + k_MessageHeader;
+            var msg = new TreeViewItem(str.GetHashCode(), 1, k_MessageEmpty);
+            if (bundle.HasMessages())
+            {
+                msg.displayName = k_MessageHeader;
+                var currMessages = bundle.GetMessages();
+
+                foreach(var currMsg in currMessages)
+                {
+                    str = itemName + currMsg.message;
+                    msg.AddChild(new BundleDetailItem(str.GetHashCode(), 2, currMsg.message, currMsg.severity));
+                }
+            }
+
+
+            bunRoot.AddChild(sz);
+            bunRoot.AddChild(dependency);
+            bunRoot.AddChild(msg);
+
+            return bunRoot;
+        }
+
+
+
+        internal void SetItems(IEnumerable<AssetBundleModel.BundleInfo> items)
+        {
+            m_Selecteditems.Clear();
+            foreach(var item in items)
+            {
+                CollectBundles(item);
+            }
+            SetSelection(new List<int>());
+            Reload();
+            ExpandAll();
+        }
+        internal void CollectBundles(AssetBundleModel.BundleInfo bundle)
+        {
+            var bunData = bundle as AssetBundleModel.BundleDataInfo;
+            if (bunData != null)
+                m_Selecteditems.Add(bunData);
+            else
+            {
+                var bunFolder = bundle as AssetBundleModel.BundleFolderInfo;
+                foreach (var bun in bunFolder.GetChildList())
+                {
+                    CollectBundles(bun);
+                }
+            }
+        }
+
+    }
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/BundleDetailList.cs.meta

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

+ 9 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/Icons.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: fabc705ac6bb6b746ac5ade02708d0b9
+folderAsset: yes
+timeCreated: 1491494491
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/AssetBundles-Browser-1.7.0/Editor/Icons/ABundleBrowserIconY1756Basic(1).png


+ 147 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/Icons/ABundleBrowserIconY1756Basic(1).png.meta

@@ -0,0 +1,147 @@
+fileFormatVersion: 2
+guid: 0b611177078956746bb7d63ed66bf566
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 12
+  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
+  vTOnly: 0
+  ignoreMasterTextureLimit: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: 1
+    aniso: 1
+    mipBias: 0
+    wrapU: 0
+    wrapV: 0
+    wrapW: 0
+  nPOTScale: 1
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spritePixelsToUnits: 100
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spriteGenerateFallbackPhysicsShape: 1
+  alphaUsage: 1
+  alphaIsTransparency: 0
+  spriteTessellationDetail: -1
+  textureType: 0
+  textureShape: 1
+  singleChannelComponent: 0
+  flipbookRows: 1
+  flipbookColumns: 1
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  ignorePngGamma: 0
+  applyGammaDecoding: 0
+  cookieLightType: 0
+  platformSettings:
+  - serializedVersion: 3
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 3
+    buildTarget: Standalone
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 3
+    buildTarget: Server
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 3
+    buildTarget: Android
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 3
+    buildTarget: WebGL
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+    nameFileIdTable: {}
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/AssetBundles-Browser-1.7.0/Editor/Icons/ABundleBrowserIconY1756Scene.png


+ 77 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/Icons/ABundleBrowserIconY1756Scene.png.meta

@@ -0,0 +1,77 @@
+fileFormatVersion: 2
+guid: 2c52be92045472a4bb2d2fa348b08d6d
+TextureImporter:
+  fileIDToRecycleName: {}
+  externalObjects: {}
+  serializedVersion: 5
+  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
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    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}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  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: []
+  spritePackingTag: 
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 5d1c1f5fd30f85c4f971269388fad046
+folderAsset: yes
+timeCreated: 1497983785
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 514 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/AssetBundleInspectTab.cs

@@ -0,0 +1,514 @@
+using UnityEditor;
+using UnityEngine;
+using UnityEditor.IMGUI.Controls;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Linq;
+
+namespace AssetBundleBrowser
+{
+    [System.Serializable]
+    internal class AssetBundleInspectTab
+    {
+        Rect m_Position;
+
+        [SerializeField]
+        private InspectTabData m_Data;
+        
+
+        private Dictionary<string, List<string> > m_BundleList;
+        private InspectBundleTree m_BundleTreeView;
+        [SerializeField]
+        private TreeViewState m_BundleTreeState;
+
+        internal Editor m_Editor = null;
+
+        private SingleBundleInspector m_SingleInspector;
+
+        /// <summary>
+        /// Collection of loaded asset bundle records indexed by bundle name
+        /// </summary>
+        private Dictionary<string, AssetBundleRecord> m_loadedAssetBundles;
+
+        /// <summary>
+        /// Returns the record for a loaded asset bundle by name if it exists in our container.
+        /// </summary>
+        /// <returns>Asset bundle record instance if loaded, otherwise null.</returns>
+        /// <param name="bundleName">Name of the loaded asset bundle, excluding the variant extension</param>
+        private AssetBundleRecord GetLoadedBundleRecordByName(string bundleName)
+        {
+            if (string.IsNullOrEmpty(bundleName))
+            {
+                return null;
+            }
+
+            if (!m_loadedAssetBundles.ContainsKey(bundleName))
+            {
+                return null;
+            }
+
+            return m_loadedAssetBundles[bundleName];
+        }
+
+        internal AssetBundleInspectTab()
+        {
+            m_BundleList = new Dictionary<string, List<string>>();
+            m_SingleInspector = new SingleBundleInspector();
+            m_loadedAssetBundles = new Dictionary<string, AssetBundleRecord>();
+        }
+
+        internal void OnEnable(Rect pos)
+        {
+            m_Position = pos;
+            if (m_Data == null)
+                m_Data = new InspectTabData();
+
+            //LoadData...
+            var dataPath = System.IO.Path.GetFullPath(".");
+            dataPath = dataPath.Replace("\\", "/");
+            dataPath += "/Library/AssetBundleBrowserInspect.dat";
+
+            if (File.Exists(dataPath))
+            {
+                BinaryFormatter bf = new BinaryFormatter();
+                FileStream file = File.Open(dataPath, FileMode.Open);
+                var data = bf.Deserialize(file) as InspectTabData;
+                if (data != null)
+                    m_Data = data;
+                file.Close();
+            }
+
+
+            if (m_BundleList == null)
+                m_BundleList = new Dictionary<string, List<string>>();
+
+            if (m_BundleTreeState == null)
+                m_BundleTreeState = new TreeViewState();
+            m_BundleTreeView = new InspectBundleTree(m_BundleTreeState, this);
+
+
+            RefreshBundles();
+        }
+
+        internal void OnDisable()
+        {
+            ClearData();
+
+            var dataPath = System.IO.Path.GetFullPath(".");
+            dataPath = dataPath.Replace("\\", "/");
+            dataPath += "/Library/AssetBundleBrowserInspect.dat";
+
+            BinaryFormatter bf = new BinaryFormatter();
+            FileStream file = File.Create(dataPath);
+
+            bf.Serialize(file, m_Data);
+            file.Close();
+        }
+
+        internal void OnGUI(Rect pos)
+        {
+            m_Position = pos;
+
+            if (Application.isPlaying)
+            {
+                var style = new GUIStyle(GUI.skin.label);
+                style.alignment = TextAnchor.MiddleCenter;
+                style.wordWrap = true;
+                GUI.Label(
+                    new Rect(m_Position.x + 1f, m_Position.y + 1f, m_Position.width - 2f, m_Position.height - 2f),
+                    new GUIContent("Inspector unavailable while in PLAY mode"),
+                    style);
+            }
+            else
+            {
+                OnGUIEditor();
+            }
+        }
+
+        private void OnGUIEditor()
+        {
+            EditorGUILayout.Space();
+            GUILayout.BeginHorizontal();
+
+            if (GUILayout.Button("Add File", GUILayout.MaxWidth(75f)))
+            {
+                BrowseForFile();
+            }
+            if (GUILayout.Button("Add Folder", GUILayout.MaxWidth(75f)))
+            {
+                BrowseForFolder();
+            }
+
+            GUILayout.EndHorizontal();
+            EditorGUILayout.Space();
+
+            if (m_BundleList.Count > 0)
+            {
+                int halfWidth = (int)(m_Position.width / 2.0f);
+                m_BundleTreeView.OnGUI(new Rect(m_Position.x, m_Position.y + 30, halfWidth, m_Position.height - 30));
+                m_SingleInspector.OnGUI(new Rect(m_Position.x + halfWidth, m_Position.y + 30, halfWidth, m_Position.height - 30));
+            }
+        }
+
+        internal void RemoveBundlePath(string pathToRemove)
+        {
+            UnloadBundle(pathToRemove);
+            m_Data.RemovePath(pathToRemove);
+        }
+        internal void RemoveBundleFolder(string pathToRemove)
+        {
+            List<string> paths = null;
+            if(m_BundleList.TryGetValue(pathToRemove, out paths))
+            {
+                foreach(var p in paths)
+                {
+                    UnloadBundle(p);
+                }
+            }
+            m_Data.RemoveFolder(pathToRemove);
+        }
+
+        private void BrowseForFile()
+        {
+            var newPath = EditorUtility.OpenFilePanelWithFilters("Bundle Folder", string.Empty, new string[] { });
+            if (!string.IsNullOrEmpty(newPath))
+            {
+                var gamePath = System.IO.Path.GetFullPath(".");//TODO - FileUtil.GetProjectRelativePath??
+                gamePath = gamePath.Replace("\\", "/");
+                if (newPath.StartsWith(gamePath))
+                    newPath = newPath.Remove(0, gamePath.Length + 1);
+
+                m_Data.AddPath(newPath);
+
+                RefreshBundles();
+            }
+        }
+
+        //TODO - this is largely copied from BuildTab, should maybe be shared code.
+        private void BrowseForFolder(string folderPath = null)
+        {
+           folderPath = EditorUtility.OpenFolderPanel("Bundle Folder", string.Empty, string.Empty);
+            if (!string.IsNullOrEmpty(folderPath))
+            {
+                var gamePath = System.IO.Path.GetFullPath(".");//TODO - FileUtil.GetProjectRelativePath??
+                gamePath = gamePath.Replace("\\", "/");
+                if (folderPath.StartsWith(gamePath))
+                    folderPath = folderPath.Remove(0, gamePath.Length + 1);
+
+                AddBundleFolder(folderPath);
+
+                RefreshBundles();
+            }
+        }
+
+        internal void AddBundleFolder(string folderPath)
+        {
+            m_Data.AddFolder(folderPath);
+        }
+
+        private void ClearData()
+        {
+            m_SingleInspector.SetBundle(null);
+
+            if (null != m_loadedAssetBundles)
+            {
+                List<AssetBundleRecord> records = new List<AssetBundleRecord>(m_loadedAssetBundles.Values);
+                foreach (AssetBundleRecord record in records)
+                {
+                    record.bundle.Unload(true);
+                }
+
+                m_loadedAssetBundles.Clear();
+            }
+        }
+
+        internal void RefreshBundles()
+        {
+            ClearData();
+
+
+            if (m_Data.BundlePaths == null)
+                return;
+
+            //find assets
+            if (m_BundleList == null)
+                m_BundleList = new Dictionary<string, List<string>>();
+
+            m_BundleList.Clear();
+            var pathsToRemove = new List<string>();
+            foreach(var filePath in m_Data.BundlePaths)
+            {
+                if(File.Exists(filePath))
+                {
+                    AddBundleToList(string.Empty, filePath);
+                }
+                else
+                {
+                    Debug.Log("Expected bundle not found: " + filePath);
+                    pathsToRemove.Add(filePath);
+                }
+            }
+            foreach(var path in pathsToRemove)
+            {
+                m_Data.RemovePath(path);
+            }
+            pathsToRemove.Clear();
+
+            foreach(var folder in m_Data.BundleFolders)
+            {
+                if(Directory.Exists(folder.path))
+                {
+                    AddFilePathToList(folder.path, folder.path);
+                }
+                else
+                {
+                    Debug.Log("Expected folder not found: " + folder);
+                    pathsToRemove.Add(folder.path);
+                }
+            }
+            foreach (var path in pathsToRemove)
+            {
+                m_Data.RemoveFolder(path);
+            }
+
+            m_BundleTreeView.Reload();
+        }
+
+        private void AddBundleToList(string parent, string bundlePath)
+        {
+            List<string> bundles = null;
+            m_BundleList.TryGetValue(parent, out bundles);
+
+            if(bundles == null)
+            {
+                bundles = new List<string>();
+                m_BundleList.Add(parent, bundles);
+            }
+            bundles.Add(bundlePath);
+        }
+        private void AddFilePathToList(string rootPath, string path)
+        {
+            var notAllowedExtensions = new string[] { ".meta", ".manifest", ".dll", ".cs", ".exe", ".js" };
+            foreach (var file in Directory.GetFiles(path))
+            {
+                var ext = Path.GetExtension(file);
+                if(!notAllowedExtensions.Contains(ext))
+                {
+                    var f = file.Replace('\\', '/');
+                    if (File.Exists(file) && !m_Data.FolderIgnoresFile(rootPath, f))
+                    {
+                        AddBundleToList(rootPath, f);
+                    }
+                }
+            }
+
+            foreach (var dir in Directory.GetDirectories(path))
+            {
+                AddFilePathToList(rootPath, dir);
+            }
+        }
+
+        internal Dictionary<string, List<string>> BundleList
+        { get { return m_BundleList; } }
+
+
+        internal void SetBundleItem(IList<InspectTreeItem> selected)
+        {
+            //m_SelectedBundleTreeItems = selected;
+            if (selected == null || selected.Count == 0 || selected[0] == null)
+            {
+                m_SingleInspector.SetBundle(null);
+            }
+            else if(selected.Count == 1)
+            {
+                AssetBundle bundle = LoadBundle(selected[0].bundlePath);
+                m_SingleInspector.SetBundle(bundle, selected[0].bundlePath, m_Data, this);
+            }
+            else
+            {
+                m_SingleInspector.SetBundle(null);
+
+                //perhaps there should be a way to set a message in the inspector, to tell it...
+                //var style = GUI.skin.label;
+                //style.alignment = TextAnchor.MiddleCenter;
+                //style.wordWrap = true;
+                //GUI.Label(
+                //    inspectorRect,
+                //    new GUIContent("Multi-select inspection not supported"),
+                //    style);
+            }
+        }
+
+        [System.Serializable]
+        internal class InspectTabData
+        {
+            [SerializeField]
+            private List<string> m_BundlePaths = new List<string>();
+            [SerializeField]
+            private List<BundleFolderData> m_BundleFolders = new List<BundleFolderData>();
+
+            internal IList<string> BundlePaths { get { return m_BundlePaths.AsReadOnly(); } }
+            internal IList<BundleFolderData> BundleFolders { get { return m_BundleFolders.AsReadOnly(); } }
+
+            internal void AddPath(string newPath)
+            {
+                if (!m_BundlePaths.Contains(newPath))
+                {
+                    var possibleFolderData = FolderDataContainingFilePath(newPath);
+                    if(possibleFolderData == null)
+                    {
+                        m_BundlePaths.Add(newPath);
+                    }
+                    else
+                    {
+                        possibleFolderData.ignoredFiles.Remove(newPath);
+                    }
+                }
+            }
+
+            internal void AddFolder(string newPath)
+            {
+                if (!BundleFolderContains(newPath))
+                    m_BundleFolders.Add(new BundleFolderData(newPath));
+            }
+
+            internal void RemovePath(string pathToRemove)
+            {
+                m_BundlePaths.Remove(pathToRemove);
+            }
+
+            internal void RemoveFolder(string pathToRemove)
+            {
+                m_BundleFolders.Remove(BundleFolders.FirstOrDefault(bfd => bfd.path == pathToRemove));
+            }
+
+            internal bool FolderIgnoresFile(string folderPath, string filePath)
+            {
+                if (BundleFolders == null)
+                    return false;
+                var bundleFolderData = BundleFolders.FirstOrDefault(bfd => bfd.path == folderPath);
+                return bundleFolderData != null && bundleFolderData.ignoredFiles.Contains(filePath);
+            }
+
+            internal BundleFolderData FolderDataContainingFilePath(string filePath)
+            {
+                foreach (var bundleFolderData in BundleFolders)
+                {
+                    if (Path.GetFullPath(filePath).StartsWith(Path.GetFullPath(bundleFolderData.path)))
+                    {
+                        return bundleFolderData;
+                    }
+                }
+                return null;
+            }
+
+            private bool BundleFolderContains(string folderPath)
+            {
+                foreach(var bundleFolderData in BundleFolders)
+                {
+                    if(Path.GetFullPath(bundleFolderData.path) == Path.GetFullPath(folderPath))
+                    {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            [System.Serializable]
+            internal class BundleFolderData
+            {
+                [SerializeField]
+                internal string path;
+
+                [SerializeField]
+                private List<string> m_ignoredFiles;
+                internal List<string> ignoredFiles
+                {
+                    get
+                    {
+                        if (m_ignoredFiles == null)
+                            m_ignoredFiles = new List<string>();
+                        return m_ignoredFiles;
+                    }
+                }
+
+                internal BundleFolderData(string p)
+                {
+                    path = p;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Returns the bundle at the specified path, loading it if necessary.
+        /// Unloads previously loaded bundles if necessary when dealing with variants.
+        /// </summary>
+        /// <returns>Returns the loaded bundle, null if it could not be loaded.</returns>
+        /// <param name="path">Path of bundle to get</param>
+        private AssetBundle LoadBundle(string path)
+        {
+            if (string.IsNullOrEmpty(path))
+            {
+                return null;
+            }
+
+            string extension = Path.GetExtension(path);
+
+            string bundleName = path.Substring(0, path.Length - extension.Length);
+
+            // Check if we have a record for this bundle
+            AssetBundleRecord record = GetLoadedBundleRecordByName(bundleName);
+            AssetBundle bundle = null;
+            if (null != record)
+            {
+                // Unload existing bundle if variant names differ, otherwise use existing bundle
+                if (!record.path.Equals(path))
+                {
+                    UnloadBundle(bundleName);
+                }
+                else
+                {
+                    bundle = record.bundle;
+                }
+            }
+                
+            if (null == bundle)
+            {
+                // Load the bundle
+                bundle = AssetBundle.LoadFromFile(path);
+                if (null == bundle)
+                {
+                    return null;
+                }
+
+                m_loadedAssetBundles[bundleName] = new AssetBundleRecord(path, bundle);
+
+                // Load the bundle's assets
+                string[] assetNames = bundle.GetAllAssetNames();
+                foreach (string name in assetNames)
+                {
+                    bundle.LoadAsset(name);
+                }
+            }
+
+            return bundle;
+        }
+
+        /// <summary>
+        /// Unloads the bundle with the given name.
+        /// </summary>
+        /// <param name="bundleName">Name of the bundle to unload without variant extension</param>
+        private void UnloadBundle(string bundleName)
+        {
+            AssetBundleRecord record = this.GetLoadedBundleRecordByName(bundleName);
+            if (null == record)
+            {
+                return;
+            }
+
+            record.bundle.Unload(true);
+            m_loadedAssetBundles.Remove(bundleName);
+        }
+    }
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/AssetBundleInspectTab.cs.meta

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

+ 60 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/AssetBundleRecord.cs

@@ -0,0 +1,60 @@
+using UnityEngine;
+
+namespace AssetBundleBrowser
+{
+    /// <summary>
+    /// This class maintains a record of a loaded asset bundle, allowing us
+    /// to associate the full path of an asset bundle with the actual bundle,
+    /// so that we can:
+    /// 
+    /// 1. distinguish between bundle variants, which, when loaded
+    /// resolve to the same name. 
+    /// 
+    /// 2. Differentiate between the same asset bundles built for different platforms.
+    /// 
+    /// ex:
+    ///
+    /// Two asset bundle variants:
+    /// 
+    /// - variant one: mycylinder.one
+    /// - variant two: mycylinder.two
+    /// 
+    /// Will Resolve to "mycylinder" when loaded.
+    /// 
+    /// Likewise, 
+    /// 
+    /// - iOS: AssetBundles/iOS/myBundle
+    /// - Android: AssetBundle/Android/myBundle
+    /// 
+    /// Will both resolve to "mybundle" when loaded.
+    /// 
+    /// </summary>
+    internal class AssetBundleRecord
+    {
+        /// <summary>
+        /// Full path of the asset bundle.
+        /// </summary>
+        internal string path { get; private set; }
+
+        /// <summary>
+        /// Reference to the loaded asset bundle associated with the path.
+        /// </summary>
+        internal AssetBundle bundle { get; private set; }
+
+        internal AssetBundleRecord(string path, AssetBundle bundle)
+        {
+            if (string.IsNullOrEmpty(path) ||
+                null == bundle)
+            {
+                string msg = string.Format("AssetBundleRecord encountered invalid parameters path={0}, bundle={1}",
+                    path,
+                    bundle);
+                
+                throw new System.ArgumentException(msg);
+            }
+
+            this.path = path;
+            this.bundle = bundle;
+        }
+    }
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/AssetBundleRecord.cs.meta

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

+ 129 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/InspectSingleBundle.cs

@@ -0,0 +1,129 @@
+using UnityEditor;
+using UnityEngine;
+using System.IO;
+
+namespace AssetBundleBrowser
+{
+    class SingleBundleInspector
+    {
+        internal static string currentPath { get; set; }
+
+
+        internal SingleBundleInspector() { }
+
+        private Editor m_Editor = null;
+
+        private Rect m_Position;
+
+        [SerializeField]
+        private Vector2 m_ScrollPosition;
+
+        private AssetBundleInspectTab m_assetBundleInspectTab = null;
+        private AssetBundleInspectTab.InspectTabData m_inspectTabData = null;
+
+        internal void SetBundle(AssetBundle bundle, string path = "", AssetBundleInspectTab.InspectTabData inspectTabData = null, AssetBundleInspectTab assetBundleInspectTab = null)
+        {
+            //static var...
+            currentPath = path;
+            m_inspectTabData = inspectTabData;
+            m_assetBundleInspectTab = assetBundleInspectTab;
+
+            //members
+            m_Editor = null;
+            if(bundle != null)
+            {
+                m_Editor = Editor.CreateEditor(bundle);
+            }
+        }
+
+        internal void OnGUI(Rect pos)
+        {
+            m_Position = pos;
+
+            DrawBundleData();
+        }
+
+        private void DrawBundleData()
+        {
+            if (m_Editor != null)
+            {
+                GUILayout.BeginArea(m_Position);
+                m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition);
+                m_Editor.OnInspectorGUI();
+                EditorGUILayout.EndScrollView();
+                GUILayout.EndArea();
+            }
+            else if(!string.IsNullOrEmpty(currentPath))
+            {
+                var style = new GUIStyle(GUI.skin.label);
+                style.alignment = TextAnchor.MiddleCenter;
+                style.wordWrap = true;
+                GUI.Label(m_Position, new GUIContent("Invalid bundle selected"), style);
+
+                if (m_inspectTabData != null && GUI.Button(new Rect(new Vector2((m_Position.position.x + m_Position.width / 2f) - 37.5f, (m_Position.position.y + m_Position.height / 2f) + 15), new Vector2(75, 30)), "Ignore file"))
+                {
+                    var possibleFolderData = m_inspectTabData.FolderDataContainingFilePath(currentPath);
+                    if (possibleFolderData != null)
+                    {
+                        if (!possibleFolderData.ignoredFiles.Contains(currentPath))
+                            possibleFolderData.ignoredFiles.Add(currentPath);
+
+                        if(m_assetBundleInspectTab != null)
+                            m_assetBundleInspectTab.RefreshBundles();
+                    }
+                } 
+            }
+        }
+    }
+
+    [CustomEditor(typeof(AssetBundle))]
+    internal class AssetBundleEditor : Editor
+    {
+        internal bool pathFoldout = false;
+        internal bool advancedFoldout = false;
+        public override void OnInspectorGUI()
+        {
+            AssetBundle bundle = target as AssetBundle;
+
+            using (new EditorGUI.DisabledScope(true))
+            {
+                var leftStyle = new GUIStyle(GUI.skin.GetStyle("Label"));
+                leftStyle.alignment = TextAnchor.UpperLeft;
+                GUILayout.Label(new GUIContent("Name: " + bundle.name), leftStyle);
+
+                long fileSize = -1;
+                if(!System.String.IsNullOrEmpty(SingleBundleInspector.currentPath) && File.Exists(SingleBundleInspector.currentPath) )
+                {
+                    System.IO.FileInfo fileInfo = new System.IO.FileInfo(SingleBundleInspector.currentPath);
+                    fileSize = fileInfo.Length;
+                }
+
+                if (fileSize < 0)
+                    GUILayout.Label(new GUIContent("Size: unknown"), leftStyle);
+                else
+                    GUILayout.Label(new GUIContent("Size: " + EditorUtility.FormatBytes(fileSize)), leftStyle);
+
+                var assetNames = bundle.GetAllAssetNames();
+                pathFoldout = EditorGUILayout.Foldout(pathFoldout, "Source Asset Paths");
+                if (pathFoldout)
+                {
+                    EditorGUI.indentLevel++;
+                    foreach (var asset in assetNames)
+                        EditorGUILayout.LabelField(asset);
+                    EditorGUI.indentLevel--;
+                }
+
+
+                advancedFoldout = EditorGUILayout.Foldout(advancedFoldout, "Advanced Data");
+
+            }
+
+            if (advancedFoldout)
+            {
+                EditorGUI.indentLevel++;
+                base.OnInspectorGUI();
+                EditorGUI.indentLevel--;
+            }
+        }
+    }
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/InspectSingleBundle.cs.meta

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

+ 133 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/InspectTreeView.cs

@@ -0,0 +1,133 @@
+using UnityEngine;
+using UnityEditor.IMGUI.Controls;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AssetBundleBrowser
+{
+	internal class InspectTreeItem : TreeViewItem
+	{
+        internal string bundlePath { get; private set; }
+            
+		internal InspectTreeItem(string path, int depth) : base(path.GetHashCode(), depth, path)
+		{
+            bundlePath = path;
+        }
+        internal InspectTreeItem(string path, int depth, string prettyName) : base(path.GetHashCode(), depth, prettyName)
+        {
+            bundlePath = path;
+        }
+    }
+
+	class InspectBundleTree : TreeView
+	{
+		AssetBundleInspectTab m_InspectTab;
+		internal InspectBundleTree(TreeViewState s, AssetBundleInspectTab parent) : base(s)
+		{
+			m_InspectTab = parent;
+			showBorder = true;
+		}
+
+		protected override TreeViewItem BuildRoot()
+		{
+			var root = new TreeViewItem(-1, -1);
+			root.children = new List<TreeViewItem>();
+			if (m_InspectTab == null)
+				Debug.Log("Unknown problem in AssetBundle Browser Inspect tab.  Restart Browser and try again, or file ticket on github.");
+			else
+			{
+				foreach (var folder in m_InspectTab.BundleList)
+				{
+                    if (System.String.IsNullOrEmpty(folder.Key))
+                    {
+                        foreach(var path in folder.Value)
+                            root.AddChild(new InspectTreeItem(path, 0));
+                    }
+                    else
+                    {
+                        var folderItem = new TreeViewItem(folder.Key.GetHashCode(), 0, folder.Key);
+                        foreach (var path in folder.Value)
+                        {
+
+                            var prettyName = path;
+                            if (path.StartsWith(folder.Key)) //how could it not?
+                                prettyName = path.Remove(0, folder.Key.Length + 1);
+
+                            folderItem.AddChild(new InspectTreeItem(path, 1, prettyName));
+                        }
+                        root.AddChild(folderItem);
+                    }
+				}
+			}
+			return root;
+		}
+
+		public override void OnGUI(Rect rect)
+		{
+			base.OnGUI(rect);
+			if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && rect.Contains(Event.current.mousePosition))
+			{
+				SetSelection(new int[0], TreeViewSelectionOptions.FireSelectionChanged);
+			}
+		}
+
+        protected override void RowGUI(RowGUIArgs args)
+        {
+            base.RowGUI(args);
+            if (args.item.depth == 0)
+            {
+                var width = 16;
+                var edgeRect = new Rect(args.rowRect.xMax - width, args.rowRect.y, width, args.rowRect.height);
+                if (GUI.Button(edgeRect, "-"))
+                {
+                    if (GetSelection().Contains(args.item.id))
+                    {
+                        var selection = GetSelection();
+                        foreach (var id in selection)
+                        {
+                            var item = FindItem(id, rootItem);
+                            if(item.depth == 0)
+                                RemoveItem(item);
+                        }
+                    }
+                    else
+                    {
+                        RemoveItem(args.item);
+                    }
+                    m_InspectTab.RefreshBundles();
+                }
+            }
+        }
+        private void RemoveItem(TreeViewItem item)
+        {
+            var inspectItem = item as InspectTreeItem;
+            if (inspectItem != null)
+                m_InspectTab.RemoveBundlePath(inspectItem.bundlePath);
+            else
+                m_InspectTab.RemoveBundleFolder(item.displayName);
+        }
+        protected override void SelectionChanged(IList<int> selectedIds)
+		{
+			base.SelectionChanged(selectedIds);
+
+            if (selectedIds == null)
+                return;
+
+			if (selectedIds.Count > 0)
+			{
+                m_InspectTab.SetBundleItem(FindRows(selectedIds).Select(tvi => tvi as InspectTreeItem).ToList());
+				//m_InspectTab.SetBundleItem(FindItem(selectedIds[0], rootItem) as InspectTreeItem);
+			}
+			else
+            {
+				m_InspectTab.SetBundleItem(null);
+            }
+		}
+
+		protected override bool CanMultiSelect(TreeViewItem item)
+		{
+			return true;
+		}
+	}
+
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/InspectTab/InspectTreeView.cs.meta

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

+ 116 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/MessageList.cs

@@ -0,0 +1,116 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections.Generic;
+
+namespace AssetBundleBrowser
+{
+    internal class MessageList
+    {
+        private Vector2 m_ScrollPosition = Vector2.zero;
+
+        private GUIStyle[] m_Style = new GUIStyle[2];
+
+        IEnumerable<AssetBundleModel.AssetInfo> m_Selecteditems;
+        List<MessageSystem.Message> m_Messages;
+
+        Vector2 m_Dimensions = new Vector2(0, 0);
+        const float k_ScrollbarPadding = 16f;
+        const float k_BorderSize = 1f;
+
+
+        internal MessageList()
+        {
+            Init();
+        }
+        private void Init()
+        {
+            m_Style[0] = "OL EntryBackOdd";
+            m_Style[1] = "OL EntryBackEven";
+            m_Style[0].wordWrap = true;
+            m_Style[1].wordWrap = true;
+            m_Style[0].padding = new RectOffset(32, 0, 1, 4);
+            m_Style[1].padding = new RectOffset(32, 0, 1, 4);
+            m_Messages = new List<MessageSystem.Message>();
+
+        }
+        internal void OnGUI(Rect fullPos)
+        {
+            DrawOutline(fullPos, 1f);
+
+            Rect pos = new Rect(fullPos.x + k_BorderSize, fullPos.y + k_BorderSize, fullPos.width - 2 * k_BorderSize, fullPos.height - 2 * k_BorderSize);
+            
+
+            if (m_Dimensions.y == 0 || m_Dimensions.x != pos.width - k_ScrollbarPadding)
+            {
+                //recalculate height.
+                m_Dimensions.x = pos.width - k_ScrollbarPadding;
+                m_Dimensions.y = 0;
+                foreach (var message in m_Messages)
+                {
+                    m_Dimensions.y += m_Style[0].CalcHeight(new GUIContent(message.message), m_Dimensions.x);
+                }
+            }
+
+            m_ScrollPosition = GUI.BeginScrollView(pos, m_ScrollPosition, new Rect(0, 0, m_Dimensions.x, m_Dimensions.y));
+            int counter = 0;
+            float runningHeight = 0.0f;
+            foreach (var message in m_Messages) 
+            {
+                int index = counter % 2;
+                var content = new GUIContent(message.message);
+                float height = m_Style[index].CalcHeight(content, m_Dimensions.x);
+
+                GUI.Box(new Rect(0, runningHeight, m_Dimensions.x, height), content, m_Style[index]);
+                GUI.DrawTexture(new Rect(0, runningHeight, 32f, 32f), message.icon);
+                //TODO - cleanup formatting issues and switch to HelpBox
+                //EditorGUI.HelpBox(new Rect(0, runningHeight, m_dimensions.x, height), message.message, (MessageType)message.severity);
+
+                counter++;
+                runningHeight += height;
+            }
+            GUI.EndScrollView();
+        }
+
+        internal void SetItems(IEnumerable<AssetBundleModel.AssetInfo> items)
+        {
+            m_Selecteditems = items;
+            CollectMessages();
+        }
+
+        internal void CollectMessages()
+        {
+            m_Messages.Clear();
+            m_Dimensions.y = 0f;
+            if(m_Selecteditems != null)
+            {
+                foreach (var asset in m_Selecteditems)
+                {
+                    m_Messages.AddRange(asset.GetMessages());
+                }
+            }
+        }
+
+        internal static void DrawOutline(Rect rect, float size)
+        {
+            Color color = new Color(0.6f, 0.6f, 0.6f, 1.333f);
+            if(EditorGUIUtility.isProSkin)
+            {
+                color.r = 0.12f;
+                color.g = 0.12f;
+                color.b = 0.12f;
+            }
+
+            if (Event.current.type != EventType.Repaint)
+                return;
+
+            Color orgColor = GUI.color;
+            GUI.color = GUI.color * color;
+            GUI.DrawTexture(new Rect(rect.x, rect.y, rect.width, size), EditorGUIUtility.whiteTexture);
+            GUI.DrawTexture(new Rect(rect.x, rect.yMax - size, rect.width, size), EditorGUIUtility.whiteTexture);
+            GUI.DrawTexture(new Rect(rect.x, rect.y + 1, size, rect.height - 2 * size), EditorGUIUtility.whiteTexture);
+            GUI.DrawTexture(new Rect(rect.xMax - size, rect.y + 1, size, rect.height - 2 * size), EditorGUIUtility.whiteTexture);
+
+            GUI.color = orgColor;
+        }
+    }
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/MessageList.cs.meta

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

+ 198 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/MessageSystem.cs

@@ -0,0 +1,198 @@
+using System;
+using UnityEngine;
+using UnityEditor;
+using UnityEngine.Assertions;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor.IMGUI.Controls;
+
+namespace AssetBundleBrowser
+{
+    internal class MessageSystem
+    {
+        private static Texture2D s_ErrorIcon = null;
+        private static Texture2D s_WarningIcon = null;
+        private static Texture2D s_InfoIcon = null;
+        private static Dictionary<MessageFlag, Message> s_MessageLookup = null;
+
+        [Flags]
+        internal enum MessageFlag
+        {
+            None = 0x0,
+
+            Info = 0x80,                  //this flag is only used to check bits, not set.
+            EmptyBundle = 0x81,
+            EmptyFolder = 0x82,
+
+            Warning = 0x8000,                  //this flag is only used to check bits, not set.
+            WarningInChildren = 0x8100,
+            AssetsDuplicatedInMultBundles = 0x8200,
+            VariantBundleMismatch = 0x8400,
+
+            Error = 0x800000,                  //this flag is only used to check bits, not set.
+            ErrorInChildren = 0x810000,
+            SceneBundleConflict = 0x820000,
+            DependencySceneConflict = 0x840000,
+        }
+
+        internal class MessageState
+        {
+            //I have an enum and a set of enums to make some logic cleaner.  
+            // The enum has masks for Error/Warning/Info that won't ever be in the set
+            // this allows for easy checking of IsSet for error rather than specific errors. 
+            private MessageFlag m_MessageFlags;
+            private HashSet<MessageFlag> m_MessageSet;
+
+
+            internal MessageState()
+            {
+                m_MessageFlags = MessageFlag.None;
+                m_MessageSet = new HashSet<MessageFlag>();
+            }
+
+            internal void Clear()
+            {
+                m_MessageFlags = MessageFlag.None;
+                m_MessageSet.Clear();
+            }
+
+            internal void SetFlag(MessageFlag flag, bool on)
+            {
+                if (flag == MessageFlag.Info || flag == MessageFlag.Warning || flag == MessageFlag.Error)
+                    return;
+
+                if (on)
+                {
+                    m_MessageFlags |= flag;
+                    m_MessageSet.Add(flag);
+                }
+                else
+                {
+                    m_MessageFlags &= ~flag;
+                    m_MessageSet.Remove(flag);
+                }
+            }
+            internal bool IsSet(MessageFlag flag)
+            {
+                return (m_MessageFlags & flag) == flag;
+            }
+            internal bool HasMessages()
+            {
+                return (m_MessageFlags != MessageFlag.None);
+            }
+
+            internal MessageType HighestMessageLevel()
+            {
+                if (IsSet(MessageFlag.Error))
+                    return MessageType.Error;
+                if (IsSet(MessageFlag.Warning))
+                    return MessageType.Warning;
+                if (IsSet(MessageFlag.Info))
+                    return MessageType.Info;
+                return MessageType.None;
+            }
+            internal MessageFlag HighestMessageFlag()
+            {
+                MessageFlag high = MessageFlag.None;
+                foreach(var f in m_MessageSet)
+                {
+                    if (f > high)
+                        high = f;
+                }
+                return high;
+            }
+
+            internal List<Message> GetMessages()
+            {
+                var msgs = new List<Message>();
+                foreach(var f in m_MessageSet)
+                {
+                    msgs.Add(GetMessage(f));
+                }
+                return msgs;
+            }
+        }
+        internal static Texture2D GetIcon(MessageType sev)
+        {
+            if (sev == MessageType.Error)
+                return GetErrorIcon();
+            else if (sev == MessageType.Warning)
+                return GetWarningIcon();
+            else if (sev == MessageType.Info)
+                return GetInfoIcon();
+            else
+                return null;
+        }
+        private static Texture2D GetErrorIcon()
+        {
+            if (s_ErrorIcon == null)
+                FindMessageIcons();
+            return s_ErrorIcon;
+        }
+        private static Texture2D GetWarningIcon()
+        {
+            if (s_WarningIcon == null)
+                FindMessageIcons();
+            return s_WarningIcon;
+        }
+        private static Texture2D GetInfoIcon()
+        {
+            if (s_InfoIcon == null)
+                FindMessageIcons();
+            return s_InfoIcon;
+        }
+
+        private static void FindMessageIcons()
+        {
+            s_ErrorIcon = EditorGUIUtility.FindTexture("console.errorIcon");
+            s_WarningIcon = EditorGUIUtility.FindTexture("console.warnicon");
+            s_InfoIcon = EditorGUIUtility.FindTexture("console.infoIcon");
+        }
+        internal class Message
+        {
+            internal Message(string msg, MessageType sev)
+            {
+                message = msg;
+                severity = sev;
+            }
+
+            internal MessageType severity;
+            internal string message;
+            internal Texture2D icon
+            {
+                get
+                {
+                    return GetIcon(severity);
+                }
+            }
+        }
+
+        internal static Message GetMessage(MessageFlag lookup)
+        {
+            if (s_MessageLookup == null)
+                InitMessages();
+
+            Message msg = null;
+            s_MessageLookup.TryGetValue(lookup, out msg);
+            if (msg == null)
+                msg = s_MessageLookup[MessageFlag.None];
+            return msg;
+        }
+
+        private static void InitMessages()
+        {
+            s_MessageLookup = new Dictionary<MessageFlag, Message>();
+
+            s_MessageLookup.Add(MessageFlag.None, new Message(string.Empty, MessageType.None));
+            s_MessageLookup.Add(MessageFlag.EmptyBundle, new Message("This bundle is empty.  Empty bundles cannot get saved with the scene and will disappear from this list if Unity restarts or if various other bundle rename or move events occur.", MessageType.Info));
+            s_MessageLookup.Add(MessageFlag.EmptyFolder, new Message("This folder is either empty or contains only empty children.  Empty bundles cannot get saved with the scene and will disappear from this list if Unity restarts or if various other bundle rename or move events occur.", MessageType.Info));
+            s_MessageLookup.Add(MessageFlag.WarningInChildren, new Message("Warning in child(ren)", MessageType.Warning));
+            s_MessageLookup.Add(MessageFlag.AssetsDuplicatedInMultBundles, new Message("Assets being pulled into this bundle due to dependencies are also being pulled into another bundle.  This will cause duplication in memory", MessageType.Warning));
+            s_MessageLookup.Add(MessageFlag.VariantBundleMismatch, new Message("Variants of a given bundle must have exactly the same assets between them based on a Name.Extension (without Path) comparison. These bundle variants fail that check.", MessageType.Warning));
+            s_MessageLookup.Add(MessageFlag.ErrorInChildren, new Message("Error in child(ren)", MessageType.Error));
+            s_MessageLookup.Add(MessageFlag.SceneBundleConflict, new Message("A bundle with one or more scenes must only contain scenes.  This bundle has scenes and non-scene assets.", MessageType.Error));
+            s_MessageLookup.Add(MessageFlag.DependencySceneConflict, new Message("The folder added to this bundle has pulled in scenes and non-scene assets.  A bundle must only have one type or the other.", MessageType.Error));
+        }
+    }
+
+}

+ 11 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/MessageSystem.cs.meta

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

+ 9 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/Unity.AssetBundleBrowser.Editor.asmdef

@@ -0,0 +1,9 @@
+{
+    "name": "Unity.AssetBundleBrowser.Editor",
+    "references": [
+    ],
+    "includePlatforms": [
+        "Editor"
+    ],
+    "excludePlatforms": []
+}

+ 7 - 0
Assets/AssetBundles-Browser-1.7.0/Editor/Unity.AssetBundleBrowser.Editor.asmdef.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: c4b8fc492eac8184fb9a42684cf8c464
+AssemblyDefinitionImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 18 - 0
Assets/AssetBundles-Browser-1.7.0/QAReport.md

@@ -0,0 +1,18 @@
+# Quality Report
+
+## QA Owner: @davidla
+
+## Test strategy
+* Unit test coverage:
+  * Bundle renaming
+  * Bundle folder movement
+  * Bundle creation
+  * Asset movement
+  * Internal bundle updating
+  * Bundle merge and delete
+  * Basic variant functionality
+  * Internal data (model) stability
+
+## Package Status
+* open bugs: https://github.com/Unity-Technologies/AssetBundles-Browser/issues
+* package has been openly available on github since April, officially released on github and the asset store since June.  Users have been able to report bugs through github (see above link) and give feedback in the asset store.  Current asset store rating is 5 stars after 19 votes.

+ 8 - 0
Assets/AssetBundles-Browser-1.7.0/QAReport.md.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b596f3cdbada8164aa95baafaa47dd5c
+timeCreated: 1511283002
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 10 - 0
Assets/AssetBundles-Browser-1.7.0/README.md

@@ -0,0 +1,10 @@
+# Unity Asset Bundle Browser tool
+
+This tool enables the user to view and edit the configuration of asset bundles for their Unity project.  It will block editing that would create invalid bundles, and inform you of any issues with existing bundles.  It also provides basic build functionality.
+
+This tool is intended to replace the current workflow of selecting assets and setting their asset bundle manually in the inspector.  It can be dropped into any Unity project with a version of 5.6 or greater.  It will create a new menu item in *Window->AssetBundle Browser*.  
+
+## Full Documentation
+#### Official Released Features
+See [the official manual page](https://docs.unity3d.com/Manual/AssetBundles-Browser.html) or view the included [project manual page](Documentation/com.unity.assetbundlebrowser.md)
+

+ 8 - 0
Assets/AssetBundles-Browser-1.7.0/README.md.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8ed8819a06e39ed4499b36b63173497f
+timeCreated: 1507818222
+licenseType: Pro
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 5 - 0
Assets/AssetBundles-Browser-1.7.0/license.md

@@ -0,0 +1,5 @@
+Asset Bundle Browser copyright © 2017 Unity Technologies ApS
+
+Licensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License). 
+
+Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions.

+ 7 - 0
Assets/AssetBundles-Browser-1.7.0/license.md.meta

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

+ 12 - 0
Assets/AssetBundles-Browser-1.7.0/package.json

@@ -0,0 +1,12 @@
+
+{
+	"name": "com.unity.assetbundlebrowser",
+	"displayName": "Asset Bundle Browser",
+	"version": "1.7.0",
+	"unity": "2018.1",
+	"description": "The Asset Bundle Browser tool enables the user to view and edit the configuration of asset bundles for their Unity project. It will block editing that would create invalid bundles, and inform you of any issues with existing bundles. It also provides basic build functionality.\n\nUse this tool as an alternative to selecting assets and setting their asset bundle manually in the inspector. It can be dropped into any Unity project with a version of 5.6 or greater. It will create a new menu item in Window > AssetBundle Browser. The bundle configuration, build functionality, and built-bundle inspection are split into three tabs within the new window.",
+	"keywords": ["asset", "bundle", "bundles", "assetbundles"],
+	"category": "Asset Bundles",
+	"dependencies": {
+	}
+}

+ 7 - 0
Assets/AssetBundles-Browser-1.7.0/package.json.meta

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

+ 8 - 0
Assets/Editor.meta

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

+ 8 - 0
Assets/Editor/HybridCLR.meta

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

+ 146 - 0
Assets/Editor/HybridCLR/BuildAssetsCommand.cs

@@ -0,0 +1,146 @@
+using HybridCLR.Editor.Commands;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEditor;
+using UnityEngine;
+
+namespace HybridCLR.Editor
+{
+    public static class BuildAssetsCommand
+    {
+        public static string HybridCLRBuildCacheDir => Application.dataPath + "/HybridCLRBuildCache";
+
+        public static string AssetBundleOutputDir => $"{HybridCLRBuildCacheDir}/AssetBundleOutput";
+
+        public static string AssetBundleSourceDataTempDir => $"{HybridCLRBuildCacheDir}/AssetBundleSourceData";
+
+
+        public static string GetAssetBundleOutputDirByTarget(BuildTarget target)
+        {
+            return $"{AssetBundleOutputDir}/{target}";
+        }
+
+        public static string GetAssetBundleTempDirByTarget(BuildTarget target)
+        {
+            return $"{AssetBundleSourceDataTempDir}/{target}";
+        }
+
+        public static string ToRelativeAssetPath(string s)
+        {
+            return s.Substring(s.IndexOf("Assets/"));
+        }
+
+        /// <summary>
+        /// 将HotFix.dll和HotUpdatePrefab.prefab打入common包.
+        /// 将HotUpdateScene.unity打入scene包.
+        /// </summary>
+        /// <param name="tempDir"></param>
+        /// <param name="outputDir"></param>
+        /// <param name="target"></param>
+        private static void BuildAssetBundles(string tempDir, string outputDir, BuildTarget target)
+        {
+            Directory.CreateDirectory(tempDir);
+            Directory.CreateDirectory(outputDir);
+            
+            List<AssetBundleBuild> abs = new List<AssetBundleBuild>();
+
+            {
+                var prefabAssets = new List<string>();
+                string testPrefab = $"{Application.dataPath}/Prefabs/Cube.prefab";
+                prefabAssets.Add(testPrefab);
+                AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
+                abs.Add(new AssetBundleBuild
+                {
+                    assetBundleName = "prefabs",
+                    assetNames = prefabAssets.Select(s => ToRelativeAssetPath(s)).ToArray(),
+                });
+            }
+
+            BuildPipeline.BuildAssetBundles(outputDir, abs.ToArray(), BuildAssetBundleOptions.None, target);
+            AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
+        }
+
+        public static void BuildAssetBundleByTarget(BuildTarget target)
+        {
+            BuildAssetBundles(GetAssetBundleTempDirByTarget(target), GetAssetBundleOutputDirByTarget(target), target);
+        }
+
+        [MenuItem("Build/BuildAssetsAndCopyToStreamingAssets")]
+        public static void BuildAndCopyABAOTHotUpdateDlls()
+        {
+            BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
+            BuildAssetBundleByTarget(target);
+            CompileDllCommand.CompileDll(target);
+            CopyABAOTHotUpdateDlls(target);
+            AssetDatabase.Refresh();
+        }
+
+        public static void CopyABAOTHotUpdateDlls(BuildTarget target)
+        {
+            CopyAssetBundlesToStreamingAssets(target);
+            CopyAOTAssembliesToStreamingAssets();
+            CopyHotUpdateAssembliesToStreamingAssets();
+        }
+
+
+        //[MenuItem("HybridCLR/Build/BuildAssetbundle")]
+        public static void BuildSceneAssetBundleActiveBuildTargetExcludeAOT()
+        {
+            BuildAssetBundleByTarget(EditorUserBuildSettings.activeBuildTarget);
+        }
+
+        public static void CopyAOTAssembliesToStreamingAssets()
+        {
+            var target = EditorUserBuildSettings.activeBuildTarget;
+            string aotAssembliesSrcDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
+            string aotAssembliesDstDir = Application.streamingAssetsPath;
+
+            foreach (var dll in SettingsUtil.AOTAssemblyNames)
+            {
+                string srcDllPath = $"{aotAssembliesSrcDir}/{dll}.dll";
+                if (!File.Exists(srcDllPath))
+                {
+                    Debug.LogError($"ab中添加AOT补充元数据dll:{srcDllPath} 时发生错误,文件不存在。裁剪后的AOT dll在BuildPlayer时才能生成,因此需要你先构建一次游戏App后再打包。");
+                    continue;
+                }
+                string dllBytesPath = $"{aotAssembliesDstDir}/{dll}.dll.bytes";
+                File.Copy(srcDllPath, dllBytesPath, true);
+                Debug.Log($"[CopyAOTAssembliesToStreamingAssets] copy AOT dll {srcDllPath} -> {dllBytesPath}");
+            }
+        }
+
+        public static void CopyHotUpdateAssembliesToStreamingAssets()
+        {
+            var target = EditorUserBuildSettings.activeBuildTarget;
+
+            string hotfixDllSrcDir = SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target);
+            string hotfixAssembliesDstDir = Application.streamingAssetsPath;
+            foreach (var dll in SettingsUtil.HotUpdateAssemblyFilesExcludePreserved)
+            {
+                string dllPath = $"{hotfixDllSrcDir}/{dll}";
+                string dllBytesPath = $"{hotfixAssembliesDstDir}/{dll}.bytes";
+                File.Copy(dllPath, dllBytesPath, true);
+                Debug.Log($"[CopyHotUpdateAssembliesToStreamingAssets] copy hotfix dll {dllPath} -> {dllBytesPath}");
+            }
+        }
+
+        public static void CopyAssetBundlesToStreamingAssets(BuildTarget target)
+        {
+            string streamingAssetPathDst = Application.streamingAssetsPath;
+            Directory.CreateDirectory(streamingAssetPathDst);
+            string outputDir = GetAssetBundleOutputDirByTarget(target);
+            var abs = new string[] { "prefabs" };
+            foreach (var ab in abs)
+            {
+                string srcAb = ToRelativeAssetPath($"{outputDir}/{ab}");
+                string dstAb = ToRelativeAssetPath($"{streamingAssetPathDst}/{ab}");
+                Debug.Log($"[CopyAssetBundlesToStreamingAssets] copy assetbundle {srcAb} -> {dstAb}");
+                AssetDatabase.CopyAsset( srcAb, dstAb);
+            }
+        }
+    }
+}

+ 11 - 0
Assets/Editor/HybridCLR/BuildAssetsCommand.cs.meta

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

+ 85 - 0
Assets/Editor/HybridCLR/BuildPlayerCommand.cs

@@ -0,0 +1,85 @@
+using HybridCLR.Editor.Commands;
+using HybridCLR.Editor.Installer;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using UnityEditor;
+using UnityEngine;
+
+namespace HybridCLR.Editor
+{
+    public class BuildPlayerCommand
+    {
+        public static void CopyAssets(string outputDir)
+        {
+            Directory.CreateDirectory(outputDir);
+
+            foreach(var srcFile in Directory.GetFiles(Application.streamingAssetsPath))
+            {
+                string dstFile = $"{outputDir}/{Path.GetFileName(srcFile)}";
+                File.Copy(srcFile, dstFile, true);
+            }
+        }
+
+        public static void InstallFromRepo()
+        {
+            var ic = new InstallerController();
+            ic.InstallDefaultHybridCLR();
+        }
+
+        public static void InstallBuildWin64()
+        {
+            InstallFromRepo();
+            Build_Win64(true);
+        }
+
+        [MenuItem("Build/Win64")]
+        public static void Build_Win64()
+        {
+            Build_Win64(false);
+        }
+
+        public static void Build_Win64(bool existWhenCompleted)
+        {
+            BuildTarget target = BuildTarget.StandaloneWindows64;
+            BuildTarget activeTarget = EditorUserBuildSettings.activeBuildTarget;
+            if (activeTarget != BuildTarget.StandaloneWindows64 && activeTarget != BuildTarget.StandaloneWindows)
+            {
+                Debug.LogError("请先切到Win平台再打包");
+                return;
+            }
+            // Get filename.
+            string outputPath = $"{SettingsUtil.ProjectDir}/Release-Win64";
+
+            var buildOptions = BuildOptions.CompressWithLz4;
+
+            string location = $"{outputPath}/HybridCLRTrial.exe";
+
+            PrebuildCommand.GenerateAll();
+            Debug.Log("====> Build App");
+            BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions()
+            {
+                scenes = new string[] { "Assets/Scenes/main.unity" },
+                locationPathName = location,
+                options = buildOptions,
+                target = target,
+                targetGroup = BuildTargetGroup.Standalone,
+            };
+
+            var report = BuildPipeline.BuildPlayer(buildPlayerOptions);
+            if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
+            {
+                Debug.LogError("打包失败");
+                if (existWhenCompleted)
+                {
+                    EditorApplication.Exit(1);
+                }
+                return;
+            }
+
+            Debug.Log("====> 复制热更新资源和代码");
+            BuildAssetsCommand.BuildAndCopyABAOTHotUpdateDlls();
+            BashUtil.CopyDir(Application.streamingAssetsPath, $"{outputPath}/HybridCLRTrial_Data/StreamingAssets", true);
+        }
+    }
+}

+ 11 - 0
Assets/Editor/HybridCLR/BuildPlayerCommand.cs.meta

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

+ 8 - 0
Assets/HotUpdate.meta

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

+ 40 - 0
Assets/HotUpdate/Entry.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+
+
+public static class Entry
+{
+    public static void Start()
+    {
+        Debug.Log("[Entry::Start] 看到这个日志表示你成功运行了热更新代码");
+        Run_InstantiateByAddComponent();
+        Run_AOTGeneric();
+    }
+
+    private static void Run_InstantiateByAddComponent()
+    {
+        // 代码中动态挂载脚本
+        GameObject cube = new GameObject("");
+        cube.AddComponent<InstantiateByAddComponent>();
+    }
+
+
+    struct MyVec3
+    {
+        public int x;
+        public int y;
+        public int z;
+    }
+
+    private static void Run_AOTGeneric()
+    {
+        // 泛型实例化
+        var arr = new List<MyVec3>();
+        arr.Add(new MyVec3 { x = 1 });
+        Debug.Log("[Demos.Run_AOTGeneric] 成功运行泛型代码");
+    }
+}

+ 11 - 0
Assets/HotUpdate/Entry.cs.meta

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

+ 3 - 0
Assets/HotUpdate/HotUpdate.asmdef

@@ -0,0 +1,3 @@
+{
+	"name": "HotUpdate"
+}

+ 7 - 0
Assets/HotUpdate/HotUpdate.asmdef.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 8fbf9762e4d9906438d9b26ab8a5caad
+AssemblyDefinitionImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 14 - 0
Assets/HotUpdate/InstantiateByAddComponent.cs

@@ -0,0 +1,14 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using UnityEngine;
+
+public class InstantiateByAddComponent : MonoBehaviour
+{
+
+    void Start()
+    {
+     //   Debug.Log($"[InstantiateByAddComponent] 这个脚本通过AddComponent的方式实例化.");
+    }
+}

+ 11 - 0
Assets/HotUpdate/InstantiateByAddComponent.cs.meta

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

+ 15 - 0
Assets/HotUpdate/InstantiateByAsset.cs

@@ -0,0 +1,15 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using UnityEngine;
+
+public class InstantiateByAsset : MonoBehaviour
+{
+    public string text;
+
+    void Start()
+    {
+        Debug.Log($"[InstantiateByAsset] text:{text}, 这个脚本通过挂载到资源的方式实例化");
+    }
+}

+ 11 - 0
Assets/HotUpdate/InstantiateByAsset.cs.meta

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

+ 75 - 0
Assets/HotUpdate/LoadDLL2.cs

@@ -0,0 +1,75 @@
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Networking;
+
+public class LoadDll2 
+{
+    private static string GetWebRequestPath(string asset)
+    {
+        var path = $"{Application.streamingAssetsPath}/{asset}";
+        if (!path.Contains("://"))
+        {
+            path = "file://" + path;
+        }
+        return path;
+    }
+    static Dictionary<string, AssetBundle> ablist = new Dictionary<string, AssetBundle>();
+    public static IEnumerator DownLoadAssets(Action<AssetBundle> callback)
+    {
+        if (ablist.ContainsKey("obe"))
+        {
+            callback.Invoke(ablist["obe"]);
+
+            yield return null;
+        }
+        else
+        {
+            string dllPath = GetWebRequestPath("obe");
+            Debug.Log($"start download asset:{dllPath}");
+            UnityWebRequest www = UnityWebRequest.Get(dllPath);
+            yield return www.SendWebRequest();
+
+#if UNITY_2020_1_OR_NEWER
+            if (www.result != UnityWebRequest.Result.Success)
+            {
+                Debug.Log(www.error);
+            }
+#else
+        if (www.isHttpError || www.isNetworkError)
+        {
+            Debug.Log(www.error);
+        }
+#endif
+            else
+            {
+                if (ablist.ContainsKey("obe"))
+                {
+
+                    callback.Invoke(ablist["obe"]);
+                }
+                else
+                {
+                    Debug.Log("assets===>" + "obe");
+                    // Or retrieve results as binary data
+                    byte[] assetData = www.downloadHandler.data;
+
+                    AssetBundle ab = AssetBundle.LoadFromMemory(assetData);
+                    ablist.Add("obe", ab);
+                    callback.Invoke(ab);
+                    UnityEngine.Object[] assets = ab.LoadAllAssets();
+                    for (int i = 0; i < assets.Length; i++)
+                    {
+                        Debug.Log("assets===>" + assets[i].name);
+                        yield return null;
+                    }
+
+                }
+
+            }
+
+        }
+    }
+}

+ 11 - 0
Assets/HotUpdate/LoadDLL2.cs.meta

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

+ 8 - 0
Assets/HotUpdate/Scripts.meta

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

+ 550 - 0
Assets/HotUpdate/Scripts/AudioManager.cs

@@ -0,0 +1,550 @@
+using UnityEngine;
+using System.Collections;
+using UnityEngine.SceneManagement;
+using System.Runtime.CompilerServices;
+
+/// <summary>
+/// 音频管理类
+/// </summary>
+public class AudioManager : MonoSingletonOBE<AudioManager>
+{
+    // private static AudioManager _instance;
+    //public static AudioManager Instance;
+    //{
+
+    //    get
+    //    {
+
+    //        //if (_instance == null)
+    //        //{
+    //        //    string name = "SoundManager";
+    //        //    GameObject manager = GameObject.Find("SoundManager");
+    //        //    if (manager == null)
+    //        //    {
+    //        //        manager = new GameObject(name);
+    //        //        _instance = manager.AddComponent<AudioManager>();
+    //        //    }
+    //        //    else
+    //        //    {
+    //        //        _instance = manager.GetComponent<AudioManager>();
+    //        //        if (_instance == null)
+    //        //        {
+    //        //            _instance = manager.AddComponent<AudioManager>();
+    //        //        }
+    //        //    }
+    //        //}
+
+    //        return _instance;
+    //    }
+    //}
+
+    private AudioSource audioSound;     //音效播放器
+    private AudioSource audioMusic;     //背景音乐播放
+    private AudioSource audioLanguage;  //配音播放器
+    public AudioClip[] sceses_BJList;    //主背景音效
+    public AudioClip[] sceses_SanGuoList;//三国场景音效
+
+    public AudioClip[] scences_Aquarium;//海洋馆音效
+    public AudioClip[] sceses_GongYeList_OBE;//工业obe场景音效
+    public AudioClip[] sceses_GongYeList_GKJ;//工业光刻机场景音效
+    public AudioClip[] sceses_GongYeList_DT;//工业地铁内抛图场景音效
+    public AudioClip[] sceses_YiLiaoList;//医疗场景音效
+    public AudioClip[] sceses_WeiLaiChengShiList;//未来城市
+    public AudioClip[] sceses_XiaoFangAnQuanList;//消防安全音效
+    public AudioClip[] sceses_JiaoYuList;//化学教育音效
+    public AudioClip[] sceses_BoWuGunList;//博物馆音效
+    public AudioClip[] sceses_PartyBuildingList;//党建音效
+
+
+    public float bjSoundVolume;
+
+
+
+    /// <summary>
+    /// 背景音效
+    /// </summary>
+    /// <param name="str"></param>
+    public void PlayBJSounds(string str)
+    {
+        Debug.Log(str);
+
+        switch (str)
+        {
+
+            case "bjSound_SanGuo":
+                PlayMusic((AudioClip)sceses_BJList[0], true);
+                break;
+            case "bjSound2_GongYe":
+                PlayMusic((AudioClip)sceses_BJList[1], true);
+                break;
+            case "bjSound3_RenTi":
+                PlayMusic((AudioClip)sceses_BJList[2], true);
+                break;
+            case "bjSound4_JiaoYu":
+                PlayMusic((AudioClip)sceses_BJList[3], true);
+                break;
+            case "bjSound5_WeiLaiChengShi":
+                PlayMusic((AudioClip)sceses_BJList[4], true);
+                break;
+            case "bjSound6_FireSafe":
+                PlayMusic((AudioClip)sceses_BJList[5], true);
+                break;
+            case "bjSound5_BoWuGuan":
+                PlayMusic((AudioClip)sceses_BJList[6], true);
+                break;
+            case "bjSound5_PartyBuilding":
+                PlayMusic((AudioClip)sceses_BJList[7], true);
+                break;
+            case "None":
+                PlayMusic((AudioClip)sceses_BJList[8], false);
+                break;
+
+
+
+        }
+    }
+    /// <summary>
+    /// 三国场景音效
+    /// </summary>
+    /// <param name="str"></param>
+    public void AudioSanGuo_LanguageSounds(string str)
+    {
+        switch (str)
+        {
+            case "SG_HLG"://虎牢关 三英战吕布
+                PlayLanguage(sceses_SanGuoList[0]);
+                break;
+            case "SG_TYSJY"://桃园三结义
+                PlayLanguage(sceses_SanGuoList[1]);
+                break;
+            case "SG_HSCB"://火烧赤壁
+                PlayLanguage(sceses_SanGuoList[2]);
+                break;
+            case "SG_YMSJ"://辕门射戟
+                PlayLanguage(sceses_SanGuoList[3]);
+                break;
+
+        }
+    }
+    /// <summary>
+    /// OBE
+    /// </summary>
+    /// <param name="str"></param>
+    public void AudioGongYe_OBE_LanguageSounds(string str)
+    {
+        switch (str)
+        {
+            case "GY_OBE_SoundStart":
+                PlayLanguage(sceses_GongYeList_OBE[0]);
+                break;
+            case "GY_OBE_Sound1":
+                PlayLanguage(sceses_GongYeList_OBE[1]);
+                break;
+            case "GY_OBE_Sound2":
+                PlayLanguage(sceses_GongYeList_OBE[2]);
+                break;
+            case "GY_OBE_Sound3":
+                PlayLanguage(sceses_GongYeList_OBE[3]);
+                break;
+            case "GY_OBE_Sound4":
+                PlayLanguage(sceses_GongYeList_OBE[4]);
+                break;
+            case "GY_OBE_Sound5":
+                PlayLanguage(sceses_GongYeList_OBE[5]);
+                break;
+            case "GY_OBE_SoundEnd":
+                PlayLanguage(sceses_GongYeList_OBE[6]);
+                break;
+        }
+    }
+    /// <summary>
+    /// 光刻机
+    /// </summary>
+    /// <param name="str"></param>
+    public void AudioGongYe_GKJ_LanguageSounds(string str)
+    {
+        switch (str)
+        {
+
+            case "GY_GKJ1":
+                PlayLanguage(sceses_GongYeList_GKJ[0]);
+                break;
+            case "GY_GKJ2":
+                PlayLanguage(sceses_GongYeList_GKJ[1]);
+                break;
+            case "GY_GKJ3":
+                PlayLanguage(sceses_GongYeList_GKJ[2]);
+                break;
+            case "GY_GKJ4":
+                PlayLanguage(sceses_GongYeList_GKJ[3]);
+                break;
+            case "GY_GKJ5":
+                PlayLanguage(sceses_GongYeList_GKJ[4]);
+                break;
+            case "GY_GKJ6":
+                PlayLanguage(sceses_GongYeList_GKJ[5]);
+                break;
+            case "GY_GKJ_Start":
+                PlayLanguage(sceses_GongYeList_GKJ[6]);
+                break;
+
+        }
+    }
+    /// <summary>
+    /// 地铁内视图
+    /// </summary>
+    /// <param name="str"></param>
+    public void AudioGongYe_DT_LanguageSounds(string str)
+    {
+
+        Debug.Log("str");
+        switch (str)
+        {
+            case "GY_dianliqianyin"://电力牵引机
+                PlayLanguage(sceses_GongYeList_DT[0]);
+                break;
+            case "GY_guagqian"://光纤交换机
+                PlayLanguage(sceses_GongYeList_DT[1]);
+                break;
+            case "GY_luyouqi"://路由器
+                PlayLanguage(sceses_GongYeList_DT[2]);
+                break;
+            case "GY_yitaiwang"://以太网交换机
+                PlayLanguage(sceses_GongYeList_DT[3]);
+                break;
+            case "GY_jiankong"://.监控系统
+                PlayLanguage(sceses_GongYeList_DT[4]);
+                break;
+            case "GY_zhuanhuanqi"://转换器
+                PlayLanguage(sceses_GongYeList_DT[5]);
+                break;
+            case "GY_dianji"://电机
+                PlayLanguage(sceses_GongYeList_DT[6]);
+                break;
+            case "GY_kongtiao"://空调通风系统
+                PlayLanguage(sceses_GongYeList_DT[7]);
+                break;
+            case "GY_DT"://空调通风系统
+                PlayLanguage(sceses_GongYeList_DT[8]);
+                break;
+
+        }
+    }
+
+
+
+    /// <summary>
+    ///医疗音效
+    /// </summary>
+    /// <param name="str"></param>
+    public void AudioYiLiao_LanguageSounds(string str)
+    {
+        switch (str)
+        {
+            case "YL_Start":
+                PlayLanguage(sceses_YiLiaoList[0]);
+                break;
+        }
+    }
+
+    /// <summary>
+    ///未来城市
+    /// </summary>
+    /// <param name="str"></param>
+    public void AudioWLCS_LanguageSounds(string str)
+    {
+        switch (str)
+        {
+            case "WLCS_Start":
+                PlayLanguage(sceses_WeiLaiChengShiList[0]);
+                break;
+        }
+    }
+    /// <summary>
+    /// 消防安全
+    /// </summary>
+    /// <param name="str"></param>
+    public void AudioHZ_LanguageSounds(string str)
+    {
+        switch (str)
+        {
+            case "XFAQ_Start":
+                PlayLanguage(sceses_XiaoFangAnQuanList[0]);
+                break;
+        }
+    }
+
+    /// <summary>
+    /// 化学教育音效
+    /// </summary>
+    /// <param name="str"></param>
+    public void AudioJiaoYu_LanguageSounds(string str)
+    {
+        switch (str)
+        {
+            case "HX_SoundStart":
+                PlayLanguage(sceses_JiaoYuList[0]);
+                break;
+            case "HX_1":
+                PlayLanguage(sceses_JiaoYuList[1]);
+                break;
+            case "HX_2":
+                PlayLanguage(sceses_JiaoYuList[2]);
+                break;
+            case "HX_3":
+                PlayLanguage(sceses_JiaoYuList[3]);
+                break;
+            case "HX_4":
+                PlayLanguage(sceses_JiaoYuList[4]);
+                break;
+            case "HX_5":
+                PlayLanguage(sceses_JiaoYuList[5]);
+                break;
+            case "HX_6":
+                PlayLanguage(sceses_JiaoYuList[6]);
+                break;
+        }
+    }
+    /// <summary>
+    /// 博物馆音效
+    /// </summary>
+    /// <param name="str"></param>
+    public void AudioBoWuGun_LanguageSounds(string str)
+    {
+        Debug.Log(str);
+        switch (str)
+        {
+
+            case "matafeiyan":
+                PlayLanguage(sceses_BoWuGunList[0]);
+                break;
+            case "yuwanggoujianjian":
+                PlayLanguage(sceses_BoWuGunList[1]);
+                break;
+            case "tangsancai":
+                PlayLanguage(sceses_BoWuGunList[2]);
+                break;
+            case "qinghuaci":
+                PlayLanguage(sceses_BoWuGunList[3]);
+                break;
+            case "BWG_end":
+                PlayLanguage(sceses_BoWuGunList[4]);
+                break;
+        }
+    }
+
+    /// <summary>
+    /// 党建音乐
+    /// </summary>
+    /// <param name="str"></param>
+    public void AudioPartyBuilding_LanguageSounds(string str)
+    {
+        switch (str)
+        {
+            case "PartyBuilding_zgcl"://中共成立
+                PlayLanguage((AudioClip)sceses_PartyBuildingList[0]);
+                break;
+            case "PartyBuilding_gxscd"://过雪山草地
+                PlayLanguage((AudioClip)sceses_PartyBuildingList[1]);
+                break;
+            case "PartyBuilding_zxzd"://政协制度
+                PlayLanguage((AudioClip)sceses_PartyBuildingList[2]);
+                break;
+            case "PartyBuilding_ggkf"://改革开放
+                PlayLanguage((AudioClip)sceses_PartyBuildingList[3]);
+                break;
+            case "PartyBuilding_kgdd"://开国大典
+                PlayLanguage((AudioClip)sceses_PartyBuildingList[4]);
+                break;
+        }
+    }
+
+
+    /// <summary>
+    /// 是否播放背景音乐
+    /// </summary>
+    public bool IsPlayMusic
+    {
+        get { return !audioMusic.mute; }
+        set
+        {
+            audioMusic.mute = !value;
+            PlayerPrefs.SetInt("isMusicOpen", value ? 1 : 0);
+        }
+    }
+
+    /// <summary>
+    /// 是否播放音效
+    /// </summary>
+    public bool IsPlaySound
+    {
+        get { return !audioSound.mute; }
+        set
+        {
+            audioSound.mute = !value;
+            PlayerPrefs.SetInt("isSoundOpen", value ? 1 : 0);
+        }
+    }
+
+    /// <summary>
+    /// 是否播放配音
+    /// </summary>
+    public bool IsPlayLanguage
+    {
+        get { return !audioLanguage.mute; }
+        set
+        {
+            audioLanguage.mute = !value;
+            PlayerPrefs.SetInt("isLanguageOpen", value ? 1 : 0);
+        }
+    }
+
+    /// <summary>
+    /// 背景音乐大小,调节大小
+    /// </summary>
+    public float MusicVolume
+    {
+        get { return audioMusic.volume; }
+        set
+        {
+            audioMusic.volume = value;
+            PlayerPrefs.SetFloat("MusicVolume", Mathf.Clamp(value, 0f, 1f));
+        }
+    }
+
+    /// <summary>
+    /// 。调节大小
+    /// </summary>
+    public float SoundVolume
+    {
+        get { return audioSound.volume; }
+        set
+        {
+            audioSound.volume = value;
+            PlayerPrefs.SetFloat("SoundVolume", Mathf.Clamp(value, 0f, 1f));
+        }
+    }
+    /// <summary>
+    /// 音效大小
+    /// </summary>
+    public float LanguageVolume
+    {
+        get { return audioLanguage.volume; }
+        set
+        {
+            audioLanguage.volume = value;
+            PlayerPrefs.SetFloat("LanguageVolume", Mathf.Clamp(value, 0f, 1f));
+        }
+    }
+
+
+    void Awake()
+    {
+        //  DontDestroyOnLoad(this.gameObject);
+        //Instance = this;
+        //sceses_BJList = Resources.LoadAll("Sounds/BJSounds");//自动加载文件夹下的声音
+
+
+        audioSound = gameObject.AddComponent<AudioSource>();
+        audioMusic = gameObject.AddComponent<AudioSource>();
+        audioLanguage = gameObject.AddComponent<AudioSource>();
+
+        audioMusic.loop = true;
+        audioMusic.playOnAwake = false;
+
+
+
+        MusicVolume = bjSoundVolume;
+
+        this.IsPlayMusic = (PlayerPrefs.GetInt("isMusicOpen", 1) > 0);
+        this.IsPlaySound = (PlayerPrefs.GetInt("isSoundOpen", 1) > 0);
+        this.IsPlayLanguage = (PlayerPrefs.GetInt("isLanguageOpen", 1) > 0);
+
+        this.MusicVolume = PlayerPrefs.GetFloat("MusicVolume", bjSoundVolume);
+        this.SoundVolume = PlayerPrefs.GetFloat("SoundVolume", 1f);
+        this.LanguageVolume = PlayerPrefs.GetFloat("LanguageVolume", 1f);
+    }
+
+    private void Start()
+    {
+        // StartCoroutine(MusicPlay());
+    }
+
+    IEnumerator MusicPlay()
+    {
+        yield return new WaitForSeconds(0.1f);
+        audioMusic.volume = 0.2f;//背景初始音效为0.2f
+    }
+    /// <summary>
+    /// 播放背景音乐
+    /// </summary>
+    public void PlayMusic(AudioClip clip, bool isLoop)
+    {
+        audioMusic.clip = null;
+        audioLanguage.clip = null;
+        if (clip == null)
+        {
+
+            return;
+        }
+
+        if (isLoop == false)
+        {
+            audioMusic.loop = false;
+            audioMusic.clip = clip;
+            audioMusic.Play();
+        }
+        else
+        {
+            audioMusic.loop = true;
+            audioMusic.clip = clip;
+            audioMusic.Play();
+        }
+
+        //if (audioMusic.isPlaying && clip.name == audioMusic.clip.name)
+        //{
+        //    return;
+        //}
+
+    }
+
+    /// <summary>
+    /// 停止播放音乐
+    /// </summary>
+    public void StopMusic()
+    {
+        audioMusic.clip = null;
+        audioMusic.Stop();
+        audioLanguage.clip = null;
+        audioLanguage.Stop();
+        audioSound.clip = null;
+        audioSound.Stop();
+    }
+
+    /// <summary>
+    /// 播放音效
+    /// </summary>
+    public void PlaySound(AudioClip clip)
+    {
+        if (clip == null)
+        {
+            return;
+        }
+        audioSound.PlayOneShot(clip);
+    }
+
+    /// <summary>
+    /// 播放配音
+    /// </summary>
+    public void PlayLanguage(AudioClip clip)
+    {
+        audioLanguage.clip = null;
+        if (clip == null)
+        {
+            return;
+        }
+        audioLanguage.clip = clip;
+        audioLanguage.Play();
+        // audioLanguage.PlayOneShot(clip);
+    }
+}

+ 11 - 0
Assets/HotUpdate/Scripts/AudioManager.cs.meta

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

+ 8 - 0
Assets/HotUpdate/Scripts/Entity.meta

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

+ 8 - 0
Assets/HotUpdate/Scripts/Entity/ContentInfo.cs

@@ -0,0 +1,8 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+[System.Serializable]
+public class ContentInfo 
+{
+    public string content;
+}

+ 11 - 0
Assets/HotUpdate/Scripts/Entity/ContentInfo.cs.meta

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

+ 19 - 0
Assets/HotUpdate/Scripts/Entity/FunctionInfo.cs

@@ -0,0 +1,19 @@
+using CCS.App;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+[System.Serializable]
+public class FunctionInfo 
+{
+    public uint moduleID;
+    public uint functionID;// 唯一的id
+    public FunctionButtonType functionBtnType;// button 类型 只有开始/开始、关闭/或其他
+    public string functionName;//显示name
+    public int defaultValue;// 默认值
+    public bool isOpen;// 此功能是否在中控中开放
+    //public int functionValue;// 当前值
+    public List<FunctionValue> functionValues;
+    public FunctionType functionType;//功能类型
+    public int rangeValueMin=0;// 起始值
+    public int rangeValueMax=1;// 最大值
+}

+ 11 - 0
Assets/HotUpdate/Scripts/Entity/FunctionInfo.cs.meta

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

+ 10 - 0
Assets/HotUpdate/Scripts/Entity/FunctionValue.cs

@@ -0,0 +1,10 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+[System.Serializable]
+public class FunctionValue 
+{
+    public int index;
+    public int value;
+    public bool isShow;
+}

+ 11 - 0
Assets/HotUpdate/Scripts/Entity/FunctionValue.cs.meta

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

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