少年修仙传客户端基础资源
lwb
2020-11-27 558e098efe457f6a84a21b788167fcb1a6cf542f
9527 接入港台渠道
6个文件已修改
62个文件已添加
6861 ■■■■■ 已修改文件
Assets/Editor/AndroidPostBuildProcessor.cs 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AndroidPostBuildProcessor.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser.meta 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleBrowserMain.cs 222 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleBrowserMain.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleBuildTab.cs 896 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleBuildTab.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource.meta 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource/ABDataSource.cs 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource/ABDataSource.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource/ABDataSourceProvider.cs 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource/ABDataSourceProvider.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource/AssetDatabaseABDataSource.cs 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource/AssetDatabaseABDataSource.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleManageTab.cs 254 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleManageTab.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleModel.meta 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleModel/ABModel.cs 773 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleModel/ABModel.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleModel/ABModelAssetInfo.cs 228 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleModel/ABModelAssetInfo.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleModel/ABModelBundleInfo.cs 964 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleModel/ABModelBundleInfo.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleTree.cs 638 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetBundleTree.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetListTree.cs 444 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/AssetListTree.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/BundleDetailList.cs 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/BundleDetailList.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/Icons.meta 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/Icons/ABundleBrowserIconY1756Basic.png 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/Icons/ABundleBrowserIconY1756Basic.png.meta 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/Icons/ABundleBrowserIconY1756Scene.png 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/Icons/ABundleBrowserIconY1756Scene.png.meta 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/InspectTab.meta 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/InspectTab/AssetBundleInspectTab.cs 237 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/InspectTab/AssetBundleInspectTab.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/InspectTab/InspectSingleBundle.cs 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/InspectTab/InspectSingleBundle.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/InspectTab/InspectTreeView.cs 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/InspectTab/InspectTreeView.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/MessageList.cs 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/MessageList.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/MessageSystem.cs 198 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleBrowser/MessageSystem.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleUtilityEditor.cs 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AssetBundleUtilityEditor.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Logo/gtgame.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Logo/gtgame/Icon.png 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Logo/gtgame/Icon.png.meta 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Logo/gtgame/Launch_1.png 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Logo/gtgame/Launch_1.png.meta 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Logo/gtgame/LoginBackGround.png 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Logo/gtgame/LoginBackGround.png.meta 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Logo/gtgame/SplashImage.png 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Logo/gtgame/SplashImage.png.meta 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Logo/gtgame/TB_DL_Logo.png 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Logo/gtgame/TB_DL_Logo.png.meta 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Tool/AssetBundleBuildTool.cs 58 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Tool/ClientPackage.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Tool/UpdateAssetBundleName.cs 125 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/VersionConfigs/Versions.txt 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/Android/AndroidManifest.xml 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/Android/AndroidManifest.xml.meta 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/Android/mainTemplate.gradle 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/Android/mainTemplate.gradle.meta 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Resources/VersionConfig.asset 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ProjectSettings/ProjectSettings.asset 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/AndroidPostBuildProcessor.cs
New file
@@ -0,0 +1,27 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor.Android;
using UnityEngine;
public class AndroidPostBuildProcessor : IPostGenerateGradleAndroidProject
{
    public int callbackOrder => 999;
    public void OnPostGenerateGradleAndroidProject(string path)
    {
        Debug.Log("AndroidPostBuildProcessor path : " + path);
        //导入当前渠道需要使用的第三方远程依赖库
        var versionConfig = VersionConfig.Get();
        var depsFile = StringUtility.Contact(ClientPackage.SDK_PLUGIN_PROJECT, "/Channel/Android/", versionConfig.appId, "/deps.gradle");
        if (File.Exists(depsFile))
        {
            File.Copy(depsFile, path + "/deps.gradle");
            Debug.Log("渠道第三方远程依赖脚本已拷贝:" + depsFile);
        }
        else
            Debug.Log("渠道第三方远程依赖脚本不存在:" + depsFile);
    }
}
Assets/Editor/AndroidPostBuildProcessor.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 654b18606f4e0b04d993cedb9538e995
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser.meta
New file
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 8c37e9a99bc1d674ca851e33ca984797
folderAsset: yes
timeCreated: 1503232241
licenseType: Free
DefaultImporter:
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/AssetBundleBrowserMain.cs
New file
@@ -0,0 +1,222 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
namespace UnityEngine.AssetBundles
{
    public class AssetBundleBrowserMain : EditorWindow, IHasCustomMenu
    {
        public const float kButtonWidth = 150;
        enum Mode
        {
            Browser,
            Builder,
            Inspect,
        }
        [SerializeField]
        Mode m_Mode;
        [SerializeField]
        public AssetBundleManageTab m_ManageTab;
        [SerializeField]
        public AssetBundleBuildTab m_BuildTab;
        [SerializeField]
        public AssetBundleInspectTab m_InspectTab;
        private Texture2D m_RefreshTexture;
        const float k_ToolbarPadding = 15;
        const float k_MenubarPadding = 32;
        [MenuItem("Tools/AssetBundle Browser", priority = 2050)]
        static void ShowWindow()
        {
            var window = GetWindow<AssetBundleBrowserMain>();
            window.titleContent = new GUIContent("AssetBundles");
            window.Show();
        }
        [SerializeField]
        public bool multiDataSource = false;
        public virtual void AddItemsToMenu(GenericMenu menu)
        {
            //menu.AddSeparator(string.Empty);
            menu.AddItem(new GUIContent("Custom Sources"), multiDataSource, FlipDataSource);
        }
        public 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(subPos, this);
            if (m_InspectTab == null)
                m_InspectTab = new AssetBundleInspectTab();
            m_InspectTab.OnEnable(subPos, this);
            m_RefreshTexture = EditorGUIUtility.FindTexture("Refresh");
            //determine if we are "multi source" or not...
            multiDataSource = false;
            List<System.Type> types = AssetBundleDataSource.ABDataSourceProviderUtility.CustomABDataSourceTypes;
            if (types.Count > 1)
                multiDataSource = true;
        }
        private void OnDisable()
        {
            if (m_BuildTab != null)
                m_BuildTab.OnDisable();
            if (m_InspectTab != null)
                m_InspectTab.OnDisable();
        }
        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(GetSubWindowArea());
                    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();
                        bool firstItem = true;
                        foreach (var info in AssetBundleDataSource.ABDataSourceProviderUtility.CustomABDataSourceTypes)
                        {
                            List<AssetBundleDataSource.ABDataSource> dataSourceList = null;
                            dataSourceList = info.GetMethod("CreateDataSources").Invoke(null, null) as List<AssetBundleDataSource.ABDataSource>;
                            if (dataSourceList == null)
                                continue;
                            if (!firstItem)
                            {
                                menu.AddSeparator("");
                            }
                            foreach (var ds in dataSourceList)
                            {
                                menu.AddItem(new GUIContent(string.Format("{0} ({1})", ds.Name, ds.ProviderName)), false,
                                    () =>
                                    {
                                        var thisDataSource = ds;
                                        AssetBundleModel.Model.DataSource = thisDataSource;
                                        m_ManageTab.ForceReloadData();
                                    }
                                );
                            }
                            firstItem = false;
                        }
                        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();
            }
        }
    }
}
Assets/Editor/AssetBundleBrowser/AssetBundleBrowserMain.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6783bbbd420e56a40b6b1b4f3edbd7d5
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/AssetBundleBuildTab.cs
New file
@@ -0,0 +1,896 @@
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine.AssetBundles.AssetBundleDataSource;
using Assets.Editor.Tool;
namespace UnityEngine.AssetBundles
{
    [System.Serializable]
    public class AssetBundleBuildTab
    {
        const string k_BuildPrefPrefix = "ABBBuild:";
        // gui vars
        //[SerializeField]
        //private ValidBuildTarget m_BuildTarget = ValidBuildTarget.StandaloneWindows;
        //[SerializeField]
        //private CompressOptions m_Compression = CompressOptions.StandardCompression;
        //private string m_OutputPath = string.Empty;
        //[SerializeField]
        //private bool m_UseDefaultPath = true;
        private string m_streamingPath
        {
            get
            {
                switch (m_UserData.m_BuildTarget)
                {
                    case ValidBuildTarget.Android:
                        return StringUtility.Contact("Assets/StreamingAssets", "/android");
                    case ValidBuildTarget.iOS:
                        return StringUtility.Contact("Assets/StreamingAssets", "/ios");
                    case ValidBuildTarget.StandaloneWindows:
                    case ValidBuildTarget.StandaloneWindows64:
                        return StringUtility.Contact("Assets/StreamingAssets", "/standalone");
                    default:
                        return "Assets/StreamingAssets";
                }
            }
        }
        [SerializeField]
        private bool m_AdvancedSettings;
        [SerializeField]
        private Vector2 m_ScrollPosition;
        class ToggleData
        {
            public 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;
            }
            //public string prefsKey
            //{ get { return k_BuildPrefPrefix + content.text; } }
            public bool state;
            public GUIContent content;
            public BuildAssetBundleOptions option;
        }
        [SerializeField]
        private BuildTabData m_UserData;
        [SerializeField] int m_Version;
        public string ApkOutputPath
        {
            get { return LocalSave.GetString("APKOutPutPath"); }
            set { LocalSave.SetString("APKOutPutPath", value); }
        }
        public string publishers
        {
            get { return LocalSave.GetString("APKPublishers"); }
            set { LocalSave.SetString("APKPublishers", value); }
        }
        List<ToggleData> m_ToggleData;
        ToggleData m_ForceRebuild;
        ToggleData m_CopyToStreaming;
        GUIContent m_TargetContent;
        GUIContent m_CompressionContent;
        public 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 };
        int rechargeSkin = 1;
        string createRoleLevel = "001";
        public AssetBundleBuildTab()
        {
            m_AdvancedSettings = false;
            m_UserData = new BuildTabData();
            m_UserData.m_OnToggles = new List<string>();
            m_UserData.m_UseDefaultPath = true;
        }
        public 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();
        }
        public void OnEnable(Rect pos, EditorWindow parent)
        {
            //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",
                "不包含类型信息。发布web平台时,不能使用该选项。",
                m_UserData.m_OnToggles,
                BuildAssetBundleOptions.DisableWriteTypeTree));
            m_ToggleData.Add(new ToggleData(
                false,
                "Force Rebuild",
                "强制重新build所有ab包。",
                m_UserData.m_OnToggles,
                BuildAssetBundleOptions.ForceRebuildAssetBundle));
            m_ToggleData.Add(new ToggleData(
                false,
                "Ignore Type Tree Changes",
                "忽略typetree的变化,不能与DisableWriteTypeTree同时使用。",
                m_UserData.m_OnToggles,
                BuildAssetBundleOptions.IgnoreTypeTreeChanges));
            m_ToggleData.Add(new ToggleData(
                false,
                "Append Hash",
                "附加hash到assetbundle名字中。",
                m_UserData.m_OnToggles,
                BuildAssetBundleOptions.AppendHashToAssetBundleName));
            m_ToggleData.Add(new ToggleData(
                false,
                "Strict Mode",
                "使用严格模式build ab, 有任何非致命的error都不会build成功。",
                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,
                "Rebuild",
                "选中后会清空所有旧的资源,全部重新打包(建议测试时不勾选可加快打包速度)",
                m_UserData.m_OnToggles);
            m_CopyToStreaming = new ToggleData(
                false,
                "Copy to StreamingAssets",
                "资源打包完成后,会将所有资源拷贝至:" + 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();
            }
        }
        public void OnGUI(Rect pos)
        {
            m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition);
            bool newState = false;
            var centeredStyle = 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 ((newPath != m_UserData.m_OutputPath) &&
                     (newPath != string.Empty))
                {
                    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 All Assets"))
            {
                EditorApplication.delayCall += ExecuteBuildAll;
            }
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Config"))
            {
                EditorApplication.delayCall += ExcuteBuildConfig;
            }
            if (GUILayout.Button("Lua"))
            {
                EditorApplication.delayCall += ExcuteBuildLua;
            }
            if (GUILayout.Button("UI"))
            {
                EditorApplication.delayCall += ExcuteBuildUI;
            }
            if (GUILayout.Button("BuiltIn"))
            {
                EditorApplication.delayCall += ExcuteBuildBuiltIn;
            }
            if (GUILayout.Button("Audio"))
            {
                EditorApplication.delayCall += ExcuteBuildAudio;
            }
            if (GUILayout.Button("Levels"))
            {
                EditorApplication.delayCall += ExcuteBuildLevels;
            }
            if (GUILayout.Button("MobEffectShader"))
            {
                EditorApplication.delayCall += ExcuteBuildMobEffectShader;
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Make VersionFile"))
            {
                EditorApplication.delayCall += MakeAssetsVersionFile;
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
            EditorGUILayout.Space();
            EditorGUILayout.Space();
#if UNITY_ANDROID
            GUILayout.BeginHorizontal();
            EditorGUILayout.TextField("Apk Output Path", ApkOutputPath);
            if (GUILayout.Button("Browse", GUILayout.MaxWidth(75f)))
            {
                BrowseForApkOutput();
            }
            GUILayout.EndHorizontal();
            EditorGUILayout.Space();
#endif
#if UNITY_STANDALONE
            GUILayout.BeginHorizontal();
            EditorGUILayout.TextField("EXE Output Path", ApkOutputPath);
            if (GUILayout.Button("Browse", GUILayout.MaxWidth(75f)))
            {
                BrowseForApkOutput();
            }
            GUILayout.EndHorizontal();
            EditorGUILayout.Space();
#endif
            GUILayout.BeginHorizontal();
            EditorGUILayout.TextField("SDK Project Path", ClientPackage.SDK_PLUGIN_PROJECT);
            if (GUILayout.Button("Browse", GUILayout.MaxWidth(75f)))
            {
                BrowseForSDKProject();
            }
            GUILayout.EndHorizontal();
            EditorGUILayout.Space();
#if UNITY_IOS
            ClientPackage.auditOutTime = EditorGUILayout.TextField("AppStore OutTime", ClientPackage.auditOutTime, GUILayout.Height(20));
            EditorGUILayout.Space();
#endif
            GUILayout.BeginHorizontal();
            ClientPackage.AssetPrior = EditorGUILayout.IntField("AssetPrior", ClientPackage.AssetPrior, GUILayout.Height(50), GUILayout.Width(250));
            publishers = EditorGUILayout.TextField("Publishers", publishers, GUILayout.Height(50));
            GUILayout.EndHorizontal();
            EditorGUILayout.Space();
            GUILayout.BeginHorizontal();
            ClientPackage.obfuscatorEnabled = EditorGUILayout.Toggle("Obfuscator Enable ", ClientPackage.obfuscatorEnabled, GUILayout.Width(250));
#if UNITY_STANDALONE
            if (GUILayout.Button("EXE"))
            {
                EditorApplication.delayCall += ExecuteBuildClientPackageStandalone;
            }
#elif UNITY_ANDROID
            if (GUILayout.Button("APK"))
            {
                EditorApplication.delayCall += ExecuteBuildClientPackageApk;
            }
#elif UNITY_IOS
            if (GUILayout.Button("IPA_Append "))
            {
                EditorApplication.delayCall += ExecuteBuildClientPackageIpaAppend;
            }
#endif
#if UNITY_STANDALONE
            if (GUILayout.Button("EXE Development "))
            {
                EditorApplication.delayCall += ExecuteBuildClientPackageStandaloneDevelopment;
            }
#elif UNITY_ANDROID
            if (GUILayout.Button("APK Development"))
            {
                EditorApplication.delayCall += ExecuteBuildClientPackageDevelopApk;
            }
#elif UNITY_IOS
            if (GUILayout.Button("IPA_Replace"))
            {
                EditorApplication.delayCall += ExecuteBuildClientPackageIpaReplace;
            }
#endif
            GUILayout.EndHorizontal();
            GUILayout.Space(20);
            if (GUILayout.Button("SwitchVersionConfig"))
            {
                EditorApplication.delayCall += ExecuteSwitchVersionConfig;
            }
            GUILayout.Space(20);
            GUILayout.BeginHorizontal();
            rechargeSkin = EditorGUILayout.IntField("Recharge Skin", rechargeSkin, GUILayout.Width(250));
            if (GUILayout.Button("Switch"))
            {
                UpdateSpriteSetting.SetRechargeSkin(rechargeSkin);
                AssetDatabase.Refresh();
                UpdateSpritePackingSetting.UpdateAllSpritePackingSetting();
            }
            createRoleLevel = EditorGUILayout.TextField("CreateRole Level", createRoleLevel, GUILayout.Width(250));
            if (GUILayout.Button("Switch"))
            {
                UpdateLevelSetting.SetCreateRoleLevel(createRoleLevel);
                AssetDatabase.Refresh();
            }
            GUILayout.EndHorizontal();
            GUILayout.EndVertical();
            EditorGUILayout.EndScrollView();
        }
        private void ExecuteBuildAll()
        {
            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)
                {
                    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);
                }
            }
            ExcuteBuildAudio();
            ExcuteBuildMobEffectShader();
            ExcuteBuildConfig();
            ExcuteBuildLevels();
            ExcuteBuildUI();
            ExcuteBuildBuiltIn();
            ExcuteBuildLua();
            AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
            MakeAssetsVersionFile();
            if (m_CopyToStreaming.state)
            {
                if (Directory.Exists(m_streamingPath))
                    Directory.Delete(m_streamingPath, true);
                DirectoryCopy(m_UserData.m_OutputPath, m_streamingPath);
            }
        }
        private void ExcuteBuildAsset(string _category)
        {
            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;
                }
                opt |= BuildAssetBundleOptions.DeterministicAssetBundle;
                foreach (var tog in m_ToggleData)
                {
                    if (tog.state)
                    {
                        opt |= tog.option;
                    }
                }
            }
            var outputPath = Application.dataPath.Replace("Assets", m_UserData.m_OutputPath);
            AssetBundleBuildExtersion.Build(outputPath, _category, opt, (BuildTarget)m_UserData.m_BuildTarget, m_ForceRebuild.state);
        }
        private void ExcuteBuildBuiltIn()
        {
            BuiltInResourceSetting.SetLaunchBackGround(publishers.Split('|')[0], (BuildTarget)m_UserData.m_BuildTarget);
            BuiltInResourceSetting.SetLoginBackGround(publishers.Split('|')[0], (BuildTarget)m_UserData.m_BuildTarget);
            BuiltInResourceSetting.SetLoginLogo(publishers.Split('|')[0], (BuildTarget)m_UserData.m_BuildTarget);
            UpdateBuiltInSetting.SetBuiltinAssetBundleName();
            ExcuteBuildAsset("builtin");
        }
        private void ExcuteBuildAudio()
        {
            UpdateAudioSetting.SetAllAudioAssetBundleName();
            ExcuteBuildAsset("audio");
            //   UpdateVideoSetting.SetAllVideoAssetBundleName();
            //   ExcuteBuildAsset("video");
        }
        private void ExcuteBuildMobEffectShader()
        {
            UpdateEffectPrefabSetting.SetAllEffectPrefabAssetBundleName();
            UpdateMobSetting.SetAllMobAssetBundleName();
            UpdateShaderSetting.SetAllShaderAssetBundleName();
            ExcuteBuildAsset("mobeffectshader");
        }
        private void ExcuteBuildConfig()
        {
            UpdateScriptableObjectsSetting.SetAllScriptableObjectAssetBundleName();
            ExcuteBuildAsset("config");
            TableTool.CopyConfigsToOutPutPath(StringUtility.Contact(m_UserData.m_OutputPath, "/config"));
        }
        private void ExcuteBuildLua()
        {
            LuaBuildHelper.OnPreBuild();
            UpdateLuaSetting.SetAllLuaAssetBundleName();
            ExcuteBuildAsset("lua");
            LuaBuildHelper.OnPostBuild();
        }
        private void ExcuteBuildLevels()
        {
            UpdateLevelSetting.SetAllLevelAssetBundleName();
            ExcuteBuildAsset("maps");
        }
        private void ExcuteBuildUI()
        {
            AssetSource.allFromEditor = true;
            //CheckFontSwitch.CheckAndReplaceFontSwitch();
            UpdateUIPrefabSetting.SetAllUIPrefabAssetBundleName();
            UpdateUIWindowSetting.SetAllUIWindowAssetBundleName();
            UpdateSpriteSetting.SetAllSpriteAssetBundleName();
            ExcuteBuildAsset("ui");
        }
        private void SetAssetsVersion()
        {
            var fileInfos = new List<FileInfo>();
            FileExtersion.GetAllDirectoryFileInfos(m_UserData.m_OutputPath, fileInfos);
            for (int i = 0; i < fileInfos.Count; i++)
            {
                var fileInfo = fileInfos[i];
                var fullName = FileExtersion.RemoveVersionFromFileFullName(fileInfo.FullName);
                var newFullName = FileExtersion.AddVersionToFileFullName(fullName, m_Version);
                if (fullName != newFullName)
                {
                    File.Copy(fullName, newFullName, true);
                    File.Delete(fullName);
                }
            }
        }
        private void RemoveAssetsVersion()
        {
            var fileInfos = new List<FileInfo>();
            FileExtersion.GetAllDirectoryFileInfos(m_UserData.m_OutputPath, fileInfos);
            for (int i = 0; i < fileInfos.Count; i++)
            {
                var fileInfo = fileInfos[i];
                var fullName = FileExtersion.RemoveVersionFromFileFullName(fileInfo.FullName);
                if (fullName != fileInfo.FullName)
                {
                    File.Copy(fileInfo.FullName, fullName, true);
                    File.Delete(fileInfo.FullName);
                }
            }
        }
        private void MakeAssetsVersionFile()
        {
            var fileInfos = new List<FileInfo>();
            FileExtersion.GetAllDirectoryFileInfos(m_UserData.m_OutputPath, fileInfos);
            AssetsVersionMaker.WriteAssetsVersionFile(Path.Combine(Directory.GetParent(Application.dataPath).FullName, m_UserData.m_OutputPath), fileInfos);
        }
        static int packageIndex
        {
            get { return LocalSave.GetInt("ClientPackageIndex", 1); }
            set { LocalSave.SetInt("ClientPackageIndex", value); }
        }
        private void ExecuteBuildClientPackageIpaAppend()
        {
            packageIndex++;
            var outputPath = Application.dataPath.Replace("Assets", m_UserData.m_OutputPath);
            ClientPackage.BuildPublishers(ClientPackage.SDK_PLUGIN_PROJECT, outputPath, ApkOutputPath, publishers, packageIndex, false, false);
        }
        private void ExecuteBuildClientPackageIpaReplace()
        {
            packageIndex++;
            var outputPath = Application.dataPath.Replace("Assets", m_UserData.m_OutputPath);
            ClientPackage.BuildPublishers(ClientPackage.SDK_PLUGIN_PROJECT, outputPath, ApkOutputPath, publishers, packageIndex, false, true);
        }
        private void ExecuteBuildClientPackageApk()
        {
            packageIndex++;
            var outputPath = Application.dataPath.Replace("Assets", m_UserData.m_OutputPath);
            ClientPackage.BuildPublishers(ClientPackage.SDK_PLUGIN_PROJECT, outputPath, ApkOutputPath, publishers, packageIndex, false, false);
        }
        private void ExecuteBuildClientPackageDevelopApk()
        {
            packageIndex++;
            var outputPath = Application.dataPath.Replace("Assets", m_UserData.m_OutputPath);
            ClientPackage.BuildPublishers(ClientPackage.SDK_PLUGIN_PROJECT, outputPath, ApkOutputPath, publishers, packageIndex, true, false);
        }
        private void ExecuteBuildClientPackageStandalone()
        {
            packageIndex++;
            var outputPath = Application.dataPath.Replace("Assets", m_UserData.m_OutputPath);
            ClientPackage_Standalone.Build(new ClientPackage_Standalone.BuildParams()
            {
                assetBundle = outputPath,
                output = ApkOutputPath,
                buildIndex = packageIndex,
                development = false,
                publisher = publishers,
            });
        }
        private void ExecuteBuildClientPackageStandaloneDevelopment()
        {
            packageIndex++;
            var outputPath = Application.dataPath.Replace("Assets", m_UserData.m_OutputPath);
            ClientPackage_Standalone.Build(new ClientPackage_Standalone.BuildParams()
            {
                assetBundle = outputPath,
                output = ApkOutputPath,
                buildIndex = packageIndex,
                development = true,
                publisher = publishers,
            });
        }
        private void ExecuteSwitchVersionConfig()
        {
            var newVersionConfigPath = StringUtility.Contact("Assets/Resources/ScriptableObject/Config/VersionConfig", ".asset");
            var versionsFilePath = Application.dataPath + Path.DirectorySeparatorChar + "Editor/VersionConfigs/Versions.txt";
            var lines = File.ReadAllLines(versionsFilePath);
            for (int i = 2; i < lines.Length; i++)
            {
                var line = lines[i];
                var lineStrings = line.Split('\t');
                if (lineStrings[0] == publishers)
                {
                    VersionConfig.Get().Read(line);
                    break;
                }
            }
        }
        private static void DirectoryCopy(string sourceDirName, string destDirName)
        {
            // Get the subdirectories for the specified directory.
            DirectoryInfo dir = new DirectoryInfo(sourceDirName);
            // If the destination directory doesn't exist, create it.
            if (!Directory.Exists(destDirName))
            {
                Directory.CreateDirectory(destDirName);
            }
            // Get the files in the directory and copy them to the new location.
            FileInfo[] files = dir.GetFiles();
            foreach (FileInfo file in files)
            {
                string temppath = Path.Combine(destDirName, file.Name);
                file.CopyTo(temppath, false);
            }
            DirectoryInfo[] dirs = dir.GetDirectories();
            foreach (DirectoryInfo subdir in dirs)
            {
                string temppath = Path.Combine(destDirName, subdir.Name);
                DirectoryCopy(subdir.FullName, temppath);
            }
        }
        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 BrowseForApkOutput()
        {
            var newPath = EditorUtility.OpenFolderPanel("Apk Folder", ApkOutputPath, 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);
                ApkOutputPath = newPath;
            }
        }
        private void BrowseForSDKProject()
        {
            var newPath = EditorUtility.OpenFolderPanel("Apk Folder", ClientPackage.SDK_PLUGIN_PROJECT, 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);
                ClientPackage.SDK_PLUGIN_PROJECT = newPath;
            }
        }
        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
        public 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]
        public class BuildTabData
        {
            public List<string> m_OnToggles;
            public ValidBuildTarget m_BuildTarget = ValidBuildTarget.StandaloneWindows;
            public CompressOptions m_Compression = CompressOptions.StandardCompression;
            public string m_OutputPath = string.Empty;
            public bool m_UseDefaultPath = true;
        }
    }
}
Assets/Editor/AssetBundleBrowser/AssetBundleBuildTab.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b1e018d921bf6e941ba3518ba24c14ac
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource.meta
New file
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: af0d51c3f04e6084e8088753c93d3fff
folderAsset: yes
timeCreated: 1499908885
licenseType: Pro
DefaultImporter:
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource/ABDataSource.cs
New file
@@ -0,0 +1,33 @@
using UnityEditor;
namespace UnityEngine.AssetBundles.AssetBundleDataSource
{
    public partial struct ABBuildInfo
    {
        public string outputDirectory;
        public BuildAssetBundleOptions options;
        public BuildTarget buildTarget;
    }
    public partial interface ABDataSource
    {
        //public static List<ABDataSource> CreateDataSources();
        string Name { get; }
        string ProviderName { get; }
        string[] GetAssetPathsFromAssetBundle (string assetBundleName);
        string GetAssetBundleName(string assetPath);
        string GetImplicitAssetBundleName(string assetPath);
        string[] GetAllAssetBundleNames();
        bool IsReadOnly();
        void SetAssetBundleNameAndVariant (string assetPath, string bundleName, string variantName);
        void RemoveUnusedAssetBundleNames();
        bool CanSpecifyBuildTarget { get; }
        bool CanSpecifyBuildOutputDirectory { get; }
        bool CanSpecifyBuildOptions { get; }
        bool BuildAssetBundles (ABBuildInfo info);
    }
}
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource/ABDataSource.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 27cff74fd1bba9146bcfc85f4c159b2b
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource/ABDataSourceProvider.cs
New file
@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace UnityEngine.AssetBundles.AssetBundleDataSource
{
    public class ABDataSourceProviderUtility {
        private static List<Type> s_customNodes;
        public static List<Type> CustomABDataSourceTypes {
            get {
                if(s_customNodes == null) {
                    s_customNodes = BuildCustomABDataSourceList();
                }
                return s_customNodes;
            }
        }
        private static List<Type> BuildCustomABDataSourceList() {
            var list = new List<Type>(Assembly
                .GetExecutingAssembly()
                .GetTypes()
                .Where(t => t != typeof(ABDataSource))
                .Where(t => typeof(ABDataSource).IsAssignableFrom(t)) );
            var properList = new List<Type>();
            properList.Add(null); //empty spot for "default"
            for(int count = 0; count < list.Count; count++)
            {
                if(list[count].Name == "AssetDatabaseABDataSource")
                    properList[0] = list[count];
                else
                    properList.Add(list[count]);
            }
            return properList;
        }
    }
}
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource/ABDataSourceProvider.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e6e4b74c22791a74598a5887a4dde4f1
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource/AssetDatabaseABDataSource.cs
New file
@@ -0,0 +1,85 @@
using System;
using UnityEngine;
using UnityEditor;
using UnityEngine.Assertions;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.IMGUI.Controls;
namespace UnityEngine.AssetBundles.AssetBundleDataSource
{
    public 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) {
            BuildPipeline.BuildAssetBundles(info.outputDirectory, info.options, info.buildTarget);
            return true;
        }
    }
}
Assets/Editor/AssetBundleBrowser/AssetBundleDataSource/AssetDatabaseABDataSource.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 92f8c138ab1fcfc4397b6fe1f8ac2337
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/AssetBundleManageTab.cs
New file
@@ -0,0 +1,254 @@
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using System.Collections.Generic;
namespace UnityEngine.AssetBundles
{
    [System.Serializable]
    public 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 m_UpdateDelay = 0f;
        EditorWindow m_Parent = null;
        public AssetBundleManageTab()
        {
            m_HorizontalSplitterPercent = 0.4f;
            m_VerticalSplitterPercentRight = 0.7f;
            m_VerticalSplitterPercentLeft = 0.85f;
        }
        public 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);
        }
        public void Update()
        {
            if(Time.realtimeSinceStartup - m_UpdateDelay > 0.1f)
            {
                m_UpdateDelay = Time.realtimeSinceStartup;
                if(AssetBundleModel.Model.Update())
                {
                    m_Parent.Repaint();
                }
                if (m_DetailsList != null)
                    m_DetailsList.Update();
                if (m_AssetList != null)
                    m_AssetList.Update();
            }
        }
        public void ForceReloadData()
        {
            UpdateSelectedBundles(new List<AssetBundleModel.BundleInfo>());
            SetSelectedItems(new List<AssetBundleModel.AssetInfo>());
            AssetBundleModel.Model.ForceReloadData(m_BundleTree);
            m_Parent.Repaint();
        }
        public 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 = 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 panelHeight = m_VerticalSplitterRectRight.y - m_Position.y;
                m_AssetList.OnGUI(new Rect(
                    panelLeft,
                    m_Position.y,
                    panelWidth,
                    panelHeight));
                m_MessageList.OnGUI(new Rect(
                    panelLeft,
                    m_Position.y + panelHeight + k_SplitterWidth,
                    panelWidth,
                    (m_Position.height - panelHeight) - k_SplitterWidth * 2));
                if (m_ResizingHorizontalSplitter || m_ResizingVerticalSplitterRight || m_ResizingVerticalSplitterLeft)
                    m_Parent.Repaint();
            }
        }
        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;
            }
        }
        public void UpdateSelectedBundles(IEnumerable<AssetBundleModel.BundleInfo> bundles)
        {
            AssetBundleModel.Model.AddBundlesToUpdate(bundles);
            m_AssetList.SetSelectedBundles(bundles);
            m_DetailsList.SetItems(bundles);
            m_MessageList.SetItems(null);
        }
        public void SetSelectedItems(IEnumerable<AssetBundleModel.AssetInfo> items)
        {
            m_MessageList.SetItems(items);
        }
    }
}
Assets/Editor/AssetBundleBrowser/AssetBundleManageTab.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 09f21df0ffab0e841b69215a8a139ff6
timeCreated: 1499908885
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/AssetBundleModel.meta
New file
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: f303c377c98172b43800b835b4b1f4f2
folderAsset: yes
timeCreated: 1499908885
licenseType: Pro
DefaultImporter:
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/AssetBundleModel/ABModel.cs
New file
@@ -0,0 +1,773 @@
using System;
using UnityEngine;
using UnityEditor;
using UnityEngine.Assertions;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.IMGUI.Controls;
using UnityEngine.AssetBundles.AssetBundleDataSource;
namespace UnityEngine.AssetBundles.AssetBundleModel
{
    public class Model
    {
        const string k_NewBundleBaseName = "newbundle";
        const string k_NewVariantBaseName = "newvariant";
        public static /*const*/ Color k_LightGrey = Color.grey * 1.5f;
        private static ABDataSource m_DataSource;
        private static BundleFolderConcreteInfo m_RootLevelBundles = new BundleFolderConcreteInfo("", null);
        private static List<ABMoveData> m_MoveData = new List<ABMoveData>();
        private static List<BundleInfo> m_BundlesToUpdate = new List<BundleInfo>();
        private static Dictionary<string, AssetInfo> m_GlobalAssetList = new Dictionary<string, AssetInfo>();
        private static Dictionary<string, HashSet<string>> m_DependencyTracker = new Dictionary<string, HashSet<string>>();
        private static bool m_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 m_EmptyMessageString;
        static private Texture2D m_folderIcon = null;
        static private Texture2D m_bundleIcon = null;
        static private Texture2D m_sceneIcon = null;
        public static ABDataSource DataSource
        {
            get
            {
                if (m_DataSource == null)
                {
                    m_DataSource = new AssetDatabaseABDataSource ();
                }
                return m_DataSource;
            }
            set { m_DataSource = value; }
        }
        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 = m_BundlesToUpdate.Count;
            if (size > 0)
            {
                m_BundlesToUpdate[size - 1].Update();
                m_BundlesToUpdate.RemoveAll(item => item.doneUpdating == true);
                if (m_BundlesToUpdate.Count == 0)
                {
                    shouldRepaint = true;
                    foreach(var bundle in m_RootLevelBundles.GetChildList())
                    {
                        bundle.RefreshDupeAssetWarning();
                    }
                }
            }
            return shouldRepaint;
        }
        public static void ForceReloadData(TreeView tree)
        {
            m_InErrorState = false;
            Rebuild();
            tree.Reload();
            bool doneUpdating = m_BundlesToUpdate.Count == 0;
            EditorUtility.DisplayProgressBar("Updating Bundles", "", 0);
            int fullBundleCount = m_BundlesToUpdate.Count;
            while (!doneUpdating && !m_InErrorState)
            {
                int currCount = m_BundlesToUpdate.Count;
                EditorUtility.DisplayProgressBar("Updating Bundles", m_BundlesToUpdate[currCount-1].displayName, (float)(fullBundleCount- currCount) / (float)fullBundleCount);
                doneUpdating = Update();
            }
            EditorUtility.ClearProgressBar();
        }
        public static void Rebuild()
        {
            m_RootLevelBundles = new BundleFolderConcreteInfo("", null);
            m_MoveData = new List<ABMoveData>();
            m_BundlesToUpdate = new List<BundleInfo>();
            m_GlobalAssetList = new Dictionary<string, AssetInfo>();
            Refresh();
        }
        public static void AddBundlesToUpdate(IEnumerable<BundleInfo> bundles)
        {
            foreach(var bundle in bundles)
            {
                bundle.ForceNeedUpdate();
                m_BundlesToUpdate.Add(bundle);
            }
        }
        public static void Refresh()
        {
            m_EmptyMessageString = k_ProblemEmptyMessage;
            if (m_InErrorState)
                return;
            var bundleList = ValidateBundleList();
            if(bundleList != null)
            {
                m_EmptyMessageString = k_DefaultEmptyMessage;
                foreach (var bundleName in bundleList)
                {
                    AddBundleToModel(bundleName);
                }
                AddBundlesToUpdate(m_RootLevelBundles.GetChildList());
            }
            if(m_InErrorState)
            {
                m_RootLevelBundles = new BundleFolderConcreteInfo("", null);
                m_EmptyMessageString = k_ProblemEmptyMessage;
            }
        }
        public 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;
        }
        public static bool BundleListIsEmpty()
        {
            return (m_RootLevelBundles.GetChildList().Count() == 0);
        }
        public static string GetEmptyMessage()
        {
            return m_EmptyMessageString;
        }
        public static BundleInfo CreateEmptyBundle(BundleFolderInfo folder = null, string newName = null)
        {
            if ((folder as BundleVariantFolderInfo) != null)
                return CreateEmptyVariant(folder as BundleVariantFolderInfo);
            folder = (folder == null) ? m_RootLevelBundles : folder;
            string name = GetUniqueName(folder, newName);
            BundleNameData nameData;
            nameData = new BundleNameData(folder.m_Name.bundleName, name);
            return AddBundleToFolder(folder, nameData);
        }
        public 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);
        }
        public static BundleFolderInfo CreateEmptyBundleFolder(BundleFolderConcreteInfo folder = null)
        {
            folder = (folder == null) ? m_RootLevelBundles : folder;
            string name = GetUniqueName(folder) + "/dummy";
            BundleNameData nameData = new BundleNameData(folder.m_Name.bundleName, name);
            return AddFoldersToBundle(m_RootLevelBundles, nameData);
        }
        private static BundleInfo AddBundleToModel(string name)
        {
            if (name == null)
                return null;
            BundleNameData nameData = new BundleNameData(name);
            BundleFolderInfo folder = AddFoldersToBundle(m_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)
                    {
                        m_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 (nameData.variant != string.Empty)
            {
                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)
                    {
                        m_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;
        }
        public static BundleTreeItem CreateBundleTreeView()
        {
            return m_RootLevelBundles.CreateTreeView(-1);
        }
        public static AssetTreeItem CreateAssetListTreeView(IEnumerable<AssetBundleModel.BundleInfo> selectedBundles)
        {
            var root = new AssetTreeItem();
            if (selectedBundles != null)
            {
                foreach (var bundle in selectedBundles)
                {
                    bundle.AddAssetsToNode(root);
                }
            }
            return root;
        }
        public 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;
        }
        public static void HandleBundleReparent(IEnumerable<BundleInfo> bundles, BundleFolderInfo parent)
        {
            parent = (parent == null) ? m_RootLevelBundles : parent;
            foreach (var bundle in bundles)
            {
                bundle.HandleReparent(parent.m_Name.bundleName, parent);
            }
            ExecuteAssetMove();
        }
        public 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();
        }
        public 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);
                }
            }
        }
        public static BundleInfo FindBundle(BundleNameData name)
        {
            BundleInfo currNode = m_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;
            }
        }
        public 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 = m_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;
        }
        public 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;
            }
        }
        class ABMoveData
        {
            public string assetName;
            public string bundleName;
            public string variantName;
            public ABMoveData(string asset, string bundle, string variant)
            {
                assetName = asset;
                bundleName = bundle;
                variantName = variant;
            }
            public void Apply()
            {
                if (!DataSource.IsReadOnly ())
                {
                    DataSource.SetAssetBundleNameAndVariant(assetName, bundleName, variantName);
                }
            }
        }
        public static void MoveAssetToBundle(AssetInfo asset, string bundleName, string variant)
        {
            m_MoveData.Add(new ABMoveData(asset.fullAssetName, bundleName, variant));
        }
        public static void MoveAssetToBundle(string assetName, string bundleName, string variant)
        {
            m_MoveData.Add(new ABMoveData(assetName, bundleName, variant));
        }
        public static void MoveAssetToBundle(IEnumerable<AssetInfo> assets, string bundleName, string variant)
        {
            foreach (var asset in assets)
                MoveAssetToBundle(asset, bundleName, variant);
        }
        public static void MoveAssetToBundle(IEnumerable<string> assetNames, string bundleName, string variant)
        {
            foreach (var assetName in assetNames)
                MoveAssetToBundle(assetName, bundleName, variant);
        }
        public static void ExecuteAssetMove(bool forceAct=true)
        {
            var size = m_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 " + m_MoveData[i].bundleName, System.IO.Path.GetFileNameWithoutExtension(m_MoveData[i].assetName), (float)i / (float)size);
                        m_MoveData[i].Apply();
                    }
                    EditorUtility.ClearProgressBar();
                    EditorPrefs.SetBool("kAutoRefresh", autoRefresh);
                    m_MoveData.Clear();
                }
                if (!DataSource.IsReadOnly ())
                {
                    DataSource.RemoveUnusedAssetBundleNames();
                }
                Refresh();
            }
        }
        //this version of CreateAsset is only used for dependent assets.
        public static AssetInfo CreateAsset(string name, AssetInfo parent)
        {
            if (ValidateAsset(name))
            {
                var bundleName = GetBundleName(name);
                return CreateAsset(name, bundleName, parent);
            }
            return null;
        }
        public 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(bundleName != string.Empty)
            {
                return new AssetInfo(name, bundleName);
            }
            else
            {
                AssetInfo info = null;
                if(!m_GlobalAssetList.TryGetValue(name, out info))
                {
                    info = new AssetInfo(name, string.Empty);
                    m_GlobalAssetList.Add(name, info);
                }
                info.AddParent(parent.displayName);
                return info;
            }
        }
        public 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);
        }
        public static int RegisterAsset(AssetInfo asset, string bundle)
        {
            if(m_DependencyTracker.ContainsKey(asset.fullAssetName))
            {
                m_DependencyTracker[asset.fullAssetName].Add(bundle);
                int count = m_DependencyTracker[asset.fullAssetName].Count;
                if (count > 1)
                    asset.SetMessageFlag(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles, true);
                return count;
            }
            var bundles = new HashSet<string>();
            bundles.Add(bundle);
            m_DependencyTracker.Add(asset.fullAssetName, bundles);
            return 1;
        }
        public static void UnRegisterAsset(AssetInfo asset, string bundle)
        {
            if (m_DependencyTracker == null || asset == null)
                return;
            if (m_DependencyTracker.ContainsKey(asset.fullAssetName))
            {
                m_DependencyTracker[asset.fullAssetName].Remove(bundle);
                int count = m_DependencyTracker[asset.fullAssetName].Count;
                switch (count)
                {
                    case 0:
                        m_DependencyTracker.Remove(asset.fullAssetName);
                        break;
                    case 1:
                        asset.SetMessageFlag(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles, false);
                        break;
                    default:
                        break;
                }
            }
        }
        public static IEnumerable<string> CheckDependencyTracker(AssetInfo asset)
        {
            if (m_DependencyTracker.ContainsKey(asset.fullAssetName))
            {
                return m_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 public void LogError(string message)
        {
            Debug.LogError("AssetBundleBrowser: " + message);
        }
        static public void LogWarning(string message)
        {
            DebugEx.LogWarning("AssetBundleBrowser: " + message);
        }
        static public Texture2D GetFolderIcon()
        {
            if (m_folderIcon == null)
                FindBundleIcons();
            return m_folderIcon;
        }
        static public Texture2D GetBundleIcon()
        {
            if (m_bundleIcon == null)
                FindBundleIcons();
            return m_bundleIcon;
        }
        static public Texture2D GetSceneIcon()
        {
            if (m_sceneIcon == null)
                FindBundleIcons();
            return m_sceneIcon;
        }
        static private void FindBundleIcons()
        {
            m_folderIcon = EditorGUIUtility.FindTexture("Folder Icon");
            string[] icons = AssetDatabase.FindAssets("ABundleBrowserIconY1756");
            foreach (string i in icons)
            {
                string name = AssetDatabase.GUIDToAssetPath(i);
                if (name.Contains("ABundleBrowserIconY1756Basic.png"))
                    m_bundleIcon = (Texture2D)AssetDatabase.LoadAssetAtPath(name, typeof(Texture2D));
                else if (name.Contains("ABundleBrowserIconY1756Scene.png"))
                    m_sceneIcon = (Texture2D)AssetDatabase.LoadAssetAtPath(name, typeof(Texture2D));
            }
        }
    }
}
Assets/Editor/AssetBundleBrowser/AssetBundleModel/ABModel.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 2d70d587215726c40ad3dd9d300187b4
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/AssetBundleModel/ABModelAssetInfo.cs
New file
@@ -0,0 +1,228 @@
using System;
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.IMGUI.Controls;
namespace UnityEngine.AssetBundles.AssetBundleModel
{
    public class AssetTreeItem : TreeViewItem
    {
        private AssetInfo m_asset;
        public AssetInfo asset
        {
            get { return m_asset; }
        }
        public AssetTreeItem() : base(-1, -1) { }
        public 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);
        public Color itemColor
        {
            get
            {
                if (m_color.a == 0.0f && m_asset != null)
                {
                    m_color = m_asset.GetColor();
                }
                return m_color;
            }
            set { m_color = value; }
        }
        public Texture2D MessageIcon()
        {
            return MessageSystem.GetIcon(HighestMessageLevel());
        }
        public MessageType HighestMessageLevel()
        {
            return m_asset != null ?
                m_asset.HighestMessageLevel() : MessageType.Error;
        }
        public 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;
        }
    }
    public class AssetInfo
    {
        public bool isScene { get; set; }
        public bool isFolder { get; set; }
        public 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();
        public AssetInfo(string inName, string bundleName="")
        {
            fullAssetName = inName;
            m_BundleName = bundleName;
            m_Parents = new HashSet<string>();
            isScene = false;
            isFolder = false;
        }
        public 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;
            }
        }
        public string displayName
        {
            get { return m_DisplayName; }
        }
        public string bundleName
        { get { return m_BundleName == "" ? "auto" : m_BundleName; } }
        public Color GetColor()
        {
            if (m_BundleName == "")
                return Model.k_LightGrey;
            else
                return Color.white;
        }
        public bool IsMessageSet(MessageSystem.MessageFlag flag)
        {
            return m_AssetMessages.IsSet(flag);
        }
        public void SetMessageFlag(MessageSystem.MessageFlag flag, bool on)
        {
            m_AssetMessages.SetFlag(flag, on);
        }
        public MessageType HighestMessageLevel()
        {
            return m_AssetMessages.HighestMessageLevel();
        }
        public 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 (m_BundleName == string.Empty && 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));
            }
            messages.Add(new MessageSystem.Message(displayName + "\n" + "Path: " + fullAssetName, MessageType.Info));
            return messages;
        }
        public void AddParent(string name)
        {
            m_Parents.Add(name);
        }
        public void RemoveParent(string name)
        {
            m_Parents.Remove(name);
        }
        public string GetSizeString()
        {
            if (fileSize == 0)
                return "--";
            return EditorUtility.FormatBytes(fileSize);
        }
        List<AssetInfo> m_dependencies = null;
        public 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;
        }
    }
}
Assets/Editor/AssetBundleBrowser/AssetBundleModel/ABModelAssetInfo.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: fa05db261cceb4f4e866a0d21a2bf0bd
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/AssetBundleModel/ABModelBundleInfo.cs
New file
@@ -0,0 +1,964 @@
using System;
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.IMGUI.Controls;
namespace UnityEngine.AssetBundles.AssetBundleModel
{
    public class BundleTreeItem : TreeViewItem
    {
        private BundleInfo m_Bundle;
        public BundleInfo bundle
        {
            get { return m_Bundle; }
        }
        public BundleTreeItem(BundleInfo b, int depth, Texture2D iconTexture) : base(b.nameHashCode, depth, b.displayName)
        {
            m_Bundle = b;
            icon = iconTexture;
            children = new List<TreeViewItem>();
        }
        public MessageSystem.Message BundleMessage()
        {
            return m_Bundle.HighestMessage();
        }
    }
    public 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.
        public BundleNameData(string name) { SetName(name); }
        public BundleNameData(string path, string name)
        {
            string finalName = path == "" ? "" : path + '/';
            finalName += name;
            SetName(finalName);
        }
        public override int GetHashCode()
        {
            return fullNativeName.GetHashCode();
        }
        public string fullNativeName
        { get { return m_FullNativeName; } }
        public void SetBundleName(string bundleName, string variantName)
        {
            string name = bundleName;
            name += (variantName == "") ? "" : "." + variantName;
            SetName(name);
        }
        public string bundleName
        {
            get { return m_FullBundleName; }
            //set { SetName(value); }
        }
        public string shortName
        {
            get { return m_ShortName; }
        }
        public string variant
        {
            get { return m_VariantName; }
            set
            {
                m_VariantName = value;
                m_FullNativeName = m_FullBundleName;
                m_FullNativeName += (m_VariantName == "") ? "" : "." + m_VariantName;
            }
        }
        public 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;
        }
        public 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 += (m_VariantName == "") ? "" : "." + m_VariantName;
        }
    }
    public abstract class BundleInfo
    {
        protected BundleFolderInfo m_Parent;
        protected bool m_DoneUpdating;
        protected bool m_Dirty;
        public BundleNameData m_Name;
        protected MessageSystem.MessageState m_BundleMessages = new MessageSystem.MessageState();
        protected MessageSystem.Message m_CachedHighMessage = null;
        public BundleInfo(string name, BundleFolderInfo parent)
        {
            m_Name = new BundleNameData(name);
            m_Parent = parent;
        }
        public BundleFolderInfo parent
        { get { return m_Parent; } }
        public virtual string displayName
        {
            get { return m_Name.shortName; }
        }
        public virtual int nameHashCode
        {
            get { return m_Name.GetHashCode(); }
        }
        public abstract BundleTreeItem CreateTreeView(int depth);
        protected virtual void RefreshMessages()
        {
            RefreshEmptyStatus();
            RefreshDupeAssetWarning();
            var flag = m_BundleMessages.HighestMessageFlag();
            m_CachedHighMessage = MessageSystem.GetMessage(flag);
        }
        public abstract bool RefreshEmptyStatus();
        public abstract bool RefreshDupeAssetWarning();
        public virtual MessageSystem.Message HighestMessage()
        {
            if (m_CachedHighMessage == null)
                RefreshMessages();
            return m_CachedHighMessage;
        }
        public bool IsMessageSet(MessageSystem.MessageFlag flag)
        {
            return m_BundleMessages.IsSet(flag);
        }
        public void SetMessageFlag(MessageSystem.MessageFlag flag, bool on)
        {
            m_BundleMessages.SetFlag(flag, on);
        }
        public List<MessageSystem.Message> GetMessages()
        {
            return m_BundleMessages.GetMessages();
        }
        public bool HasMessages()
        {
            return m_BundleMessages.HasMessages();
        }
        public 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;
        }
        public virtual void HandleDelete(bool isRootOfDelete, string forcedNewName="", string forcedNewVariant = "")
        {
            if(isRootOfDelete)
            {
                m_Parent.HandleChildRename(m_Name.shortName, string.Empty);
            }
        }
        abstract public void RefreshAssetList();
        abstract public void AddAssetsToNode(AssetTreeItem node);
        abstract public void Update();
        public virtual bool doneUpdating
        { get { return m_DoneUpdating; } }
        public virtual bool dirty
        { get { return m_Dirty; } }
        public void ForceNeedUpdate()
        {
            m_DoneUpdating = false;
            m_Dirty = true;
        }
        abstract public void HandleReparent(string parentName, BundleFolderInfo newParent = null);
        abstract public List<AssetInfo> GetDependencies();
    }
    public 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;
        public 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);
            }
        }
        public 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;
        }
        public override void HandleDelete(bool isRootOfDelete, string forcedNewName="", string forcedNewVariant="")
        {
            RefreshAssetList();
            base.HandleDelete(isRootOfDelete);
            Model.MoveAssetToBundle(m_ConcreteAssets, forcedNewName, forcedNewVariant);
        }
        public string TotalSize()
        {
            if (m_TotalSize == 0)
                return "--";
            return EditorUtility.FormatBytes(m_TotalSize);
        }
        public 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 (bundleName == string.Empty)
                {
                    ///we get here if the current asset is only added due to being in an explicitly added folder
                    var partialPath = assetName;
                    while(
                        partialPath != string.Empty &&
                        partialPath != "Assets" &&
                        bundleName == string.Empty)
                    {
                        partialPath = partialPath.Substring(0, partialPath.LastIndexOf('/'));
                        bundleName = Model.GetBundleName(partialPath);
                    }
                    if(bundleName != string.Empty)
                    {
                        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;
        }
        public 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;
        }
        public HashSet<string> GetBundleDependencies()
        {
            return m_BundleDependencies;
        }
        public 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 (parentBundle == string.Empty)
                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);
                }
            }
        }
        public override bool RefreshDupeAssetWarning()
        {
            foreach(var asset in m_DependentAssets)
            {
                if (asset != null && asset.IsMessageSet(MessageSystem.MessageFlag.AssetsDuplicatedInMultBundles))
                {
                    SetDuplicateWarning();
                    return true;
                }
            }
            return false;
        }
        public bool IsEmpty()
        {
            return (m_ConcreteAssets.Count == 0);
        }
        public 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;
        }
        public bool isSceneBundle
        { get { return m_IsSceneBundle; } }
        public override BundleTreeItem CreateTreeView(int depth)
        {
            RefreshAssetList();
            RefreshMessages();
            if (isSceneBundle)
                return new BundleTreeItem(this, depth, Model.GetSceneIcon());
            else
                return new BundleTreeItem(this, depth, Model.GetBundleIcon());
        }
        public override void HandleReparent(string parentName, BundleFolderInfo newParent = null)
        {
            RefreshAssetList();
            string newName = (parentName=="") ? "" : parentName + '/';
            newName += m_Name.shortName;
            if (newName == m_Name.bundleName)
                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);
        }
        public override List<AssetInfo> GetDependencies()
        {
            return m_DependentAssets;
        }
    }
    public class BundleVariantDataInfo : BundleDataInfo
    {
        protected List<AssetInfo> m_FolderIncludeAssets = new List<AssetInfo>();
        public BundleVariantDataInfo(string name, BundleFolderInfo parent) : base(name, parent)
        {
        }
        ~BundleVariantDataInfo()
        {
            //parent should be auto called
        }
        public override string displayName
        {
            get { return m_Name.variant; }
        }
        public override void Update()
        {
            base.Update();
            (m_Parent as BundleVariantFolderInfo).ValidateVariants();
        }
        public override void RefreshAssetList()
        {
            m_FolderIncludeAssets.Clear();
            base.RefreshAssetList();
            if(m_DependentAssets.Count > 0)
                m_FolderIncludeAssets = new List<AssetInfo>(m_DependentAssets);
        }
        public bool IsSceneVariant()
        {
            RefreshAssetList();
            return isSceneBundle;
        }
        public 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;
        }
        public 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);
        }
        public 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;
        }
    }
    public abstract class BundleFolderInfo : BundleInfo
    {
        protected Dictionary<string, BundleInfo> m_Children;
        public BundleFolderInfo(string name, BundleFolderInfo parent) : base(name, parent)
        {
            m_Children = new Dictionary<string, BundleInfo>();
        }
        public 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);
        }
        public BundleInfo GetChild(string name)
        {
            if (name == null)
                return null;
            BundleInfo info = null;
            if (m_Children.TryGetValue(name, out info))
                return info;
            return null;
        }
        public Dictionary<string, BundleInfo>.ValueCollection GetChildList()
        {
            return m_Children.Values;
        }
        public abstract void AddChild(BundleInfo info);
        public 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;
        }
        public 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();
        }
        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();
        }
        public 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;
        }
        public override void RefreshAssetList()
        {
            foreach (var child in m_Children)
            {
                child.Value.RefreshAssetList();
            }
        }
        public 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;
        }
        public override void AddAssetsToNode(AssetTreeItem node)
        {
            foreach (var child in m_Children)
            {
                child.Value.AddAssetsToNode(node);
            }
            m_Dirty = false;
        }
        public virtual bool HandleChildRename(string oldName, string newName)
        {
            if (newName != string.Empty && 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 (newName != string.Empty)
                    m_Children.Add(newName, info);
            }
            return true;
        }
        public 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();
        }
        public override bool doneUpdating
        {
            get
            {
                foreach (var child in m_Children)
                {
                    m_DoneUpdating &= child.Value.doneUpdating;
                }
                return base.doneUpdating;
            }
        }
        public override List<AssetInfo> GetDependencies()
        {
            List<AssetInfo> assets = new List<AssetInfo>();
            foreach (var child in m_Children)
            {
                assets.AddRange(child.Value.GetDependencies());
            }
            return assets;
        }
    }
    public class BundleFolderConcreteInfo : BundleFolderInfo
    {
        public BundleFolderConcreteInfo(string name, BundleFolderInfo parent) : base(name, parent)
        {
        }
        public BundleFolderConcreteInfo(List<string> path, int depth, BundleFolderInfo parent) : base(path, depth, parent)
        {
        }
        public override void AddChild(BundleInfo info)
        {
            m_Children.Add(info.displayName, info);
        }
        public 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;
        }
        public override void HandleReparent(string parentName, BundleFolderInfo newParent = null)
        {
            string newName = (parentName == "") ? "" : parentName + '/';
            newName += displayName;
            if (newName == m_Name.bundleName)
                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);
        }
    }
    public class BundleVariantFolderInfo : BundleFolderInfo
    {
        public BundleVariantFolderInfo(string name, BundleFolderInfo parent) : base(name, parent)
        {
        }
        public override void AddChild(BundleInfo info)
        {
            m_Children.Add(info.m_Name.variant, info);
        }
        private bool m_validated;
        public override void Update()
        {
            m_validated = false;
            base.Update();
            if(!m_validated)
               ValidateVariants();
        }
        public 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);
        }
        public 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;
        }
        public override void HandleReparent(string parentName, BundleFolderInfo newParent = null)
        {
            string newName = (parentName == "") ? "" : parentName + '/';
            newName += displayName;
            if (newName == m_Name.bundleName)
                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) ;
        }
        public override bool HandleChildRename(string oldName, string newName)
        {
            var result = base.HandleChildRename(oldName, newName);
            if (m_Children.Count == 0)
                HandleDelete(true);
            return result;
        }
    }
}
Assets/Editor/AssetBundleBrowser/AssetBundleModel/ABModelBundleInfo.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5221bce31edb15f4b929b93f967fe170
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/AssetBundleTree.cs
New file
@@ -0,0 +1,638 @@
using UnityEditor;
using UnityEditorInternal;
using System.Collections.Generic;
using UnityEditor.IMGUI.Controls;
using System.Linq;
using System;
namespace UnityEngine.AssetBundles
{
    internal class AssetBundleTree : TreeView
    {
        AssetBundleManageTab m_Controller;
        private bool m_ContextOnItem = false;
        List<UnityEngine.Object> m_EmptyObjectList = new List<Object>();
        public 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.displayName.Length > 0;
        }
        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)
                    DebugEx.LogWarning("There were no duplicated assets that existed across all selected bundles.");
                else
                    DebugEx.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
        {
            public bool hasBundleFolder = false;
            public bool hasScene = false;
            public bool hasNonScene = false;
            public bool hasVariantChild = false;
            public List<AssetBundleModel.BundleInfo> draggedNodes;
            public AssetBundleModel.BundleTreeItem targetNode;
            public DragAndDropArgs args;
            public string[] paths;
            public 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)
        {
            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);
        }
    }
}
Assets/Editor/AssetBundleBrowser/AssetBundleTree.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 32cb0432916e2e94f991f14040535d8d
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/AssetListTree.cs
New file
@@ -0,0 +1,444 @@
using UnityEditor;
using UnityEditorInternal;
using System.Collections.Generic;
using UnityEditor.IMGUI.Controls;
using System.Linq;
using System;
namespace UnityEngine.AssetBundles
{
    internal class AssetListTree : TreeView
    {
        List<AssetBundleModel.BundleInfo> m_SourceBundles = new List<AssetBundleModel.BundleInfo>();
        AssetBundleManageTab m_Controller;
        List<UnityEngine.Object> m_EmptyObjectList = new List<Object>();
        public 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
        }
        public enum SortOption
        {
            Asset,
            Bundle,
            Size,
            Message
        }
        SortOption[] m_SortOptions =
        {
            SortOption.Asset,
            SortOption.Bundle,
            SortOption.Size,
            SortOption.Message
        };
        public AssetListTree(TreeViewState state, MultiColumnHeaderState mchs, AssetBundleManageTab ctrl ) : base(state, new MultiColumnHeader(mchs))
        {
            m_Controller = ctrl;
            showBorder = true;
            showAlternatingRowBackgrounds = true;
            DefaultStyles.label.richText = true;
            multiColumnHeader.sortingChanged += OnSortingChanged;
        }
        public 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);
                        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)
        {
            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(args))
            {
                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(DragAndDropArgs args)
        {
            //can't do drag & drop if data source is read only
            if (AssetBundles.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 (node.asset.bundleName != string.Empty)
                    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
    {
        public static IOrderedEnumerable<T> Order<T, TKey>(this IEnumerable<T> source, Func<T, TKey> selector, bool ascending)
        {
            if (ascending)
            {
                return source.OrderBy(selector);
            }
            else
            {
                return source.OrderByDescending(selector);
            }
        }
        public static IOrderedEnumerable<T> ThenBy<T, TKey>(this IOrderedEnumerable<T> source, Func<T, TKey> selector, bool ascending)
        {
            if (ascending)
            {
                return source.ThenBy(selector);
            }
            else
            {
                return source.ThenByDescending(selector);
            }
        }
    }
}
Assets/Editor/AssetBundleBrowser/AssetListTree.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 18a3570ba42065e47b3bc4b91c1b6fa7
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/BundleDetailList.cs
New file
@@ -0,0 +1,173 @@
using UnityEditor;
using UnityEditorInternal;
using System.Collections.Generic;
using UnityEditor.IMGUI.Controls;
using System.Linq;
using System;
namespace UnityEngine.AssetBundles
{
    internal class BundleDetailItem : TreeViewItem
    {
        public BundleDetailItem(int id, int depth, string displayName, MessageType type) : base(id, depth, displayName)
        {
            MessageLevel = type;
        }
        public 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";
        public BundleDetailList(TreeViewState state) : base(state)
        {
            m_Selecteditems = new HashSet<AssetBundleModel.BundleDataInfo>();
            showBorder = true;
        }
        public 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 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);
                }
            }
        }
    }
}
Assets/Editor/AssetBundleBrowser/BundleDetailList.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7c62cc7d8f2f5a94290ec50aa5195dee
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/Icons.meta
New file
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 08c232e713e870a4db3d8f89985d8009
folderAsset: yes
timeCreated: 1499908885
licenseType: Pro
DefaultImporter:
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/Icons/ABundleBrowserIconY1756Basic.png
Assets/Editor/AssetBundleBrowser/Icons/ABundleBrowserIconY1756Basic.png.meta
New file
@@ -0,0 +1,68 @@
fileFormatVersion: 2
guid: cfb66cdcbb6d96c4ab5bed7d7101cfa2
timeCreated: 1499908888
licenseType: Pro
TextureImporter:
  fileIDToRecycleName: {}
  serializedVersion: 4
  mipmaps:
    mipMapMode: 0
    enableMipMap: 1
    sRGBTexture: 1
    linearTexture: 0
    fadeOut: 0
    borderMipMap: 0
    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:
    filterMode: -1
    aniso: -1
    mipBias: -1
    wrapMode: -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
  maxTextureSizeSet: 0
  compressionQualitySet: 0
  textureFormatSet: 0
  platformSettings:
  - buildTarget: DefaultTexturePlatform
    maxTextureSize: 2048
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
  spriteSheet:
    serializedVersion: 2
    sprites: []
    outline: []
  spritePackingTag:
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/Icons/ABundleBrowserIconY1756Scene.png
Assets/Editor/AssetBundleBrowser/Icons/ABundleBrowserIconY1756Scene.png.meta
New file
@@ -0,0 +1,68 @@
fileFormatVersion: 2
guid: 54684548eedd3744abd8030b861fae40
timeCreated: 1499908887
licenseType: Pro
TextureImporter:
  fileIDToRecycleName: {}
  serializedVersion: 4
  mipmaps:
    mipMapMode: 0
    enableMipMap: 1
    sRGBTexture: 1
    linearTexture: 0
    fadeOut: 0
    borderMipMap: 0
    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:
    filterMode: -1
    aniso: -1
    mipBias: -1
    wrapMode: -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
  maxTextureSizeSet: 0
  compressionQualitySet: 0
  textureFormatSet: 0
  platformSettings:
  - buildTarget: DefaultTexturePlatform
    maxTextureSize: 2048
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
  spriteSheet:
    serializedVersion: 2
    sprites: []
    outline: []
  spritePackingTag:
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/InspectTab.meta
New file
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 390759a6bd7b0e64791496f154446dd0
folderAsset: yes
timeCreated: 1499908885
licenseType: Pro
DefaultImporter:
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/InspectTab/AssetBundleInspectTab.cs
New file
@@ -0,0 +1,237 @@
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace UnityEngine.AssetBundles
{
    [System.Serializable]
    public class AssetBundleInspectTab
    {
        Rect m_Position;
        [SerializeField]
        private Vector2 m_ScrollPosition;
        [SerializeField]
        private InspectTabData m_Data;
        private List<string> m_BundleList = new List<string>();
        private InspectBundleTree m_BundleTreeView;
        [SerializeField]
        private TreeViewState m_BundleTreeState;
        public Editor m_Editor = null;
        //[SerializeField]
        private List<AssetBundle> m_LoadedBundles;
        private SingleBundleInspector m_SingleInspector;
        public AssetBundleInspectTab()
        {
            m_LoadedBundles = new List<AssetBundle>();
            m_SingleInspector = new SingleBundleInspector();
        }
        public void SaveBundle(AssetBundle b)
        {
            m_LoadedBundles.Add(b);
        }
        public void OnEnable(Rect pos, EditorWindow parent)
        {
            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 List<string>();
            if (m_BundleTreeState == null)
                m_BundleTreeState = new TreeViewState();
            m_BundleTreeView = new InspectBundleTree(m_BundleTreeState, this);
            m_BundleTreeView.Reload();
            RefreshBundles();
        }
        public 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();
        }
        public void OnGUI(Rect pos)
        {
            m_Position = pos;
            if (Application.isPlaying)
            {
                var style = 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()
        {
            //////input path
            EditorGUILayout.Space();
            GUILayout.BeginHorizontal();
            var originalPath = m_Data.m_BundlePath;
            m_Data.m_BundlePath = EditorGUILayout.TextField("Bundle Path", m_Data.m_BundlePath);
            if (GUILayout.Button("Browse", GUILayout.MaxWidth(75f)))
                BrowseForFolder();
            GUILayout.EndHorizontal();
            EditorGUILayout.Space();
            if (originalPath != m_Data.m_BundlePath)
            {
                RefreshBundles();
            }
            if (m_BundleList.Count > 0)
            {
                m_BundleTreeView.OnGUI(new Rect(m_Position.x, m_Position.y + 30, m_Position.width / 2.0f, m_Position.height - 30));
                m_SingleInspector.OnGUI(new Rect(m_Position.x + m_Position.width / 2.0f, m_Position.y + 30, m_Position.width / 2.0f, m_Position.height - 30));
            }
        }
        //TODO - this is largely copied from BuildTab, should maybe be shared code.
        private void BrowseForFolder()
        {
            var newPath = EditorUtility.OpenFolderPanel("Bundle Folder", m_Data.m_BundlePath, string.Empty);
            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.m_BundlePath = newPath;
            }
        }
        public void RefreshBundles()
        {
            ClearData();
            //DesignDebug.Log("Did someone say refresh?");
            //do some loading
            LoadBundles();
        }
        private void ClearData()
        {
            m_SingleInspector.SetBundle(null);
            foreach (var bundle in m_LoadedBundles)
            {
                if (bundle != null) //get into this situation on a rare restart weirdness.
                    bundle.Unload(true);
            }
            m_LoadedBundles.Clear();
        }
        private void AddFilePathToList(string path)
        {
            //////////////////////////////////////
            /// code to handle appended hash things
            //var files = Directory.GetFiles(path);
            //Array.Sort(files);
            //int size = files.Length;
            //for (int i = 0; i < size; i++)
            //{
            //    ... do something...
            //}
            //////////////////////////////////////
            foreach (var file in Directory.GetFiles(path))
            {
                if (Path.GetExtension(file) == ".manifest")
                {
                    var f = file.Substring(0, file.LastIndexOf('.')).Replace('\\', '/');
                    if (File.Exists(f))
                        m_BundleList.Add(f);
                    else
                        DebugEx.Log("Expected bundle not found: " + f + ". Note: Browser does not yet support inspecting bundles with hash appended.");
                }
            }
            foreach (var dir in Directory.GetDirectories(path))
            {
                AddFilePathToList(dir);
            }
        }
        private void LoadBundles()
        {
            if (m_Data.m_BundlePath == string.Empty)
                return;
            //find assets
            if (m_BundleList == null)
                m_BundleList = new List<string>();
            m_BundleList.Clear();
            if (Directory.Exists(m_Data.m_BundlePath))
            {
                AddFilePathToList(m_Data.m_BundlePath);
            }
            m_BundleTreeView.Reload();
        }
        public List<string> BundleList
        { get { return m_BundleList; } }
        public void SetBundleItem(InspectTreeItem selected)
        {
            if (selected == null)
                m_SingleInspector.SetBundle(null);
            else
                m_SingleInspector.SetBundle(selected.bundle, selected.bundlePath);
        }
        [System.Serializable]
        public class InspectTabData
        {
            public string m_BundlePath = string.Empty;
        }
    }
}
Assets/Editor/AssetBundleBrowser/InspectTab/AssetBundleInspectTab.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 390e28c21cef1024a87a0e52278e0314
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/InspectTab/InspectSingleBundle.cs
New file
@@ -0,0 +1,84 @@
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using System.Collections.Generic;
using System.IO;
using System;
namespace UnityEngine.AssetBundles
{
    class SingleBundleInspector
    {
        public static string currentPath { get; set; }
        public SingleBundleInspector() { }
        private Editor m_Editor = null;
        private Rect m_Position;
        [SerializeField]
        private Vector2 m_ScrollPosition;
        public void SetBundle(AssetBundle bundle, string path = "")
        {
            //static var...
            currentPath = path;
            //members
            m_Editor = null;
            if (bundle != null)
                m_Editor = Editor.CreateEditor(bundle);
        }
        public void OnGUI(Rect pos)
        {
            if (m_Editor == null)
                return;
            m_Position = pos;
            DrawBundleData();
        }
        private void DrawBundleData()
        {
            GUILayout.BeginArea(m_Position);
            m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition);
            m_Editor.OnInspectorGUI();
            EditorGUILayout.EndScrollView();
            GUILayout.EndArea();
        }
    }
    [CustomEditor(typeof(AssetBundle))]
    public class LevelScriptEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            AssetBundle bundle = target as AssetBundle;
            using (new EditorGUI.DisabledScope(true))
            {
                var leftStyle = GUI.skin.GetStyle("Label");
                leftStyle.alignment = TextAnchor.UpperLeft;
                GUILayout.Label(new GUIContent("Name: " + bundle.name), leftStyle);
                long fileSize = -1;
                if(SingleBundleInspector.currentPath != string.Empty && 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);
            }
            base.OnInspectorGUI();
        }
    }
}
Assets/Editor/AssetBundleBrowser/InspectTab/InspectSingleBundle.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 32505061201db464096788f93e39fe4d
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/InspectTab/InspectTreeView.cs
New file
@@ -0,0 +1,111 @@
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using System.Collections.Generic;
using System.IO;
using System;
namespace UnityEngine.AssetBundles
{
    public class InspectTreeItem : TreeViewItem
    {
        private string m_BundlePath;
        public string bundlePath
        {
            get { return m_BundlePath; }
        }
        private AssetBundle m_Bundle;
        private AssetBundleInspectTab m_InspectTab;
        //public InspectTreeItem(int id, int depth, string displayName) : base(id, depth, displayName)
        public InspectTreeItem(string path, AssetBundleInspectTab inspectTab) : base(path.GetHashCode(), 0, path)
        {
            m_BundlePath = path;
            m_Bundle = null;
            m_InspectTab = inspectTab;
        }
        public AssetBundle bundle
        {
            get
            {
                if (m_Bundle == null)
                    LoadBundle();
                return m_Bundle;
            }
        }
        public void LoadBundle()
        {
            if (m_Bundle == null)
            {
                m_Bundle = AssetBundle.LoadFromFile(m_BundlePath);
                m_InspectTab.SaveBundle(m_Bundle);
                //AssetBundleManifest manifest = m_Bundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
                //if (manifest != null)
                //{
                //    //this is where we could get some overall data. if we wanted it. which we might. someday.
                //}
                //gotta actually load assets to keep inspector from crashing :(
                var content = m_Bundle.GetAllAssetNames();
                foreach (var c in content)
                {
                    m_Bundle.LoadAsset(c);
                }
            }
        }
    }
    class InspectBundleTree : TreeView
    {
        AssetBundleInspectTab m_InspectTab;
        public 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)
                DebugEx.Log("Unknown problem in AssetBundle Browser Inspect tab.  Restart Browser and try again, or file ticket on github.");
            else
            {
                foreach (var b in m_InspectTab.BundleList)
                {
                    root.AddChild(new InspectTreeItem(b, m_InspectTab));
                }
            }
            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 SelectionChanged(IList<int> selectedIds)
        {
            base.SelectionChanged(selectedIds);
            if (selectedIds.Count > 0)
            {
                m_InspectTab.SetBundleItem(FindItem(selectedIds[0], rootItem) as InspectTreeItem);
            }
            else
                m_InspectTab.SetBundleItem(null);
        }
        protected override bool CanMultiSelect(TreeViewItem item)
        {
            return false;
        }
    }
}
Assets/Editor/AssetBundleBrowser/InspectTab/InspectTreeView.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: adb20806b5333c64aa5e67e4f9343622
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/MessageList.cs
New file
@@ -0,0 +1,120 @@
using UnityEditor;
using UnityEditorInternal;
using System.Collections.Generic;
using UnityEditor.IMGUI.Controls;
using System.Linq;
using System;
namespace UnityEngine.AssetBundles
{
    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;
        public 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>();
        }
        public 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 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;
        }
    }
}
Assets/Editor/AssetBundleBrowser/MessageList.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e71964deafc80d94489d3315d34b579d
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleBrowser/MessageSystem.cs
New file
@@ -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 UnityEngine.AssetBundles
{
    public class MessageSystem
    {
        private static Texture2D m_ErrorIcon = null;
        private static Texture2D m_WarningIcon = null;
        private static Texture2D m_InfoIcon = null;
        private static Dictionary<MessageFlag, Message> m_MessageLookup = null;
        [Flags]
        public 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,
        }
        public 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;
            public MessageState()
            {
                m_MessageFlags = MessageFlag.None;
                m_MessageSet = new HashSet<MessageFlag>();
            }
            public void Clear()
            {
                m_MessageFlags = MessageFlag.None;
                m_MessageSet.Clear();
            }
            public 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);
                }
            }
            public bool IsSet(MessageFlag flag)
            {
                return (m_MessageFlags & flag) == flag;
            }
            public bool HasMessages()
            {
                return (m_MessageFlags != MessageFlag.None);
            }
            public 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;
            }
            public MessageFlag HighestMessageFlag()
            {
                MessageFlag high = MessageFlag.None;
                foreach(var f in m_MessageSet)
                {
                    if (f > high)
                        high = f;
                }
                return high;
            }
            public List<Message> GetMessages()
            {
                var msgs = new List<Message>();
                foreach(var f in m_MessageSet)
                {
                    msgs.Add(GetMessage(f));
                }
                return msgs;
            }
        }
        public 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 (m_ErrorIcon == null)
                FindMessageIcons();
            return m_ErrorIcon;
        }
        private static Texture2D GetWarningIcon()
        {
            if (m_WarningIcon == null)
                FindMessageIcons();
            return m_WarningIcon;
        }
        private static Texture2D GetInfoIcon()
        {
            if (m_InfoIcon == null)
                FindMessageIcons();
            return m_InfoIcon;
        }
        private static void FindMessageIcons()
        {
            m_ErrorIcon = EditorGUIUtility.FindTexture("console.errorIcon");
            m_WarningIcon = EditorGUIUtility.FindTexture("console.warnicon");
            m_InfoIcon = EditorGUIUtility.FindTexture("console.infoIcon");
        }
        public class Message
        {
            public Message(string msg, MessageType sev)
            {
                message = msg;
                severity = sev;
            }
            public MessageType severity;
            public string message;
            public Texture2D icon
            {
                get
                {
                    return GetIcon(severity);
                }
            }
        }
        public static Message GetMessage(MessageFlag lookup)
        {
            if (m_MessageLookup == null)
                InitMessages();
            Message msg = null;
            m_MessageLookup.TryGetValue(lookup, out msg);
            if (msg == null)
                msg = m_MessageLookup[MessageFlag.None];
            return msg;
        }
        private static void InitMessages()
        {
            m_MessageLookup = new Dictionary<MessageFlag, Message>();
            m_MessageLookup.Add(MessageFlag.None, new Message(string.Empty, MessageType.None));
            m_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));
            m_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));
            m_MessageLookup.Add(MessageFlag.WarningInChildren, new Message("Warning in child(ren)", MessageType.Warning));
            m_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));
            m_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));
            m_MessageLookup.Add(MessageFlag.ErrorInChildren, new Message("Error in child(ren)", MessageType.Error));
            m_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));
            m_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));
        }
    }
}
Assets/Editor/AssetBundleBrowser/MessageSystem.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4082a2bafddd01345ac7078067be0095
timeCreated: 1499908886
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/AssetBundleUtilityEditor.cs
New file
@@ -0,0 +1,68 @@
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(AssetBundleUtility))]
public class AssetBundleUtilityEditor : Editor {
    private string m_LoadAssetBundleName = "ui/texture";
    private string m_LoadAssetName = "Button_Blue_A";
    private string m_UnloadAssetBundleName = "ui/texture";
    private bool m_UnloadLoadedObject = false;
    private bool m_IncludeDependenices = false;
    private string m_UnloadAssetName = "Button_Blue_A";
    public override void OnInspectorGUI() {
        m_LoadAssetBundleName = EditorGUILayout.TextField("AssetBundle名称", m_LoadAssetBundleName);
        m_LoadAssetName = EditorGUILayout.TextField("Asset名称", m_LoadAssetName);
        GUILayout.BeginHorizontal();
        if (GUILayout.Button("同步加载Asset")) {
            AssetBundleUtility.Instance.Sync_LoadAsset(m_LoadAssetBundleName, m_LoadAssetName);
        }
        if (GUILayout.Button("异步协程加载Asset")) {
            AssetBundleUtility.Instance.Co_LoadAsset(m_LoadAssetBundleName, m_LoadAssetName);
        }
        GUILayout.EndHorizontal();
        GUILayout.Space(10);
        m_UnloadAssetBundleName = EditorGUILayout.TextField("AssetBundle名称", m_UnloadAssetBundleName);
        m_UnloadLoadedObject = GUILayout.Toggle(m_UnloadLoadedObject, "同时卸载引用资源");
        m_IncludeDependenices = GUILayout.Toggle(m_IncludeDependenices, "同时卸载依赖包");
        if (GUILayout.Button("卸载AssetBundle")) {
            AssetBundleUtility.Instance.UnloadAssetBundle(m_UnloadAssetBundleName, m_UnloadLoadedObject, m_IncludeDependenices);
        }
        GUILayout.Space(10);
        GUILayout.BeginHorizontal();
        m_UnloadAssetName = EditorGUILayout.TextField("Asset名称", m_UnloadAssetName);
        if (GUILayout.Button("卸载Asset")) {
            AssetBundleUtility.Instance.UnloadAsset(m_UnloadAssetBundleName, m_UnloadAssetName);
        }
        GUILayout.EndHorizontal();
        if (GUILayout.Button("卸载所有AssetBundle")) {
            AssetBundleUtility.Instance.UnloadAll();
        }
        if (GUILayout.Button("调用Resources.UnloadUnUsed()")) {
            Resources.UnloadUnusedAssets();
        }
        if (GUILayout.Button("调用System.GC.Collect()")) {
            System.GC.Collect();
        }
    }
}
Assets/Editor/AssetBundleUtilityEditor.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3a5db09113674b343b6ffe3166154650
timeCreated: 1503232241
licenseType: Free
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/Logo/gtgame.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 15bfde05b66ec4341851ecfdfe2f04e5
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/Logo/gtgame/Icon.png
Assets/Editor/Logo/gtgame/Icon.png.meta
New file
@@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: ac584e55bf0df494694449ee1780d805
timeCreated: 1521082299
licenseType: Pro
TextureImporter:
  fileIDToRecycleName: {}
  serializedVersion: 4
  mipmaps:
    mipMapMode: 0
    enableMipMap: 0
    sRGBTexture: 1
    linearTexture: 0
    fadeOut: 0
    borderMipMap: 0
    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:
    filterMode: -1
    aniso: -1
    mipBias: -1
    wrapMode: -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
  maxTextureSizeSet: 0
  compressionQualitySet: 0
  textureFormatSet: 0
  platformSettings:
  - buildTarget: DefaultTexturePlatform
    maxTextureSize: 2048
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
  - buildTarget: Standalone
    maxTextureSize: 2048
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
  - buildTarget: iPhone
    maxTextureSize: 2048
    textureFormat: 4
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 1
  - buildTarget: Android
    maxTextureSize: 2048
    textureFormat: 4
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 1
  spriteSheet:
    serializedVersion: 2
    sprites: []
    outline: []
  spritePackingTag:
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/Logo/gtgame/Launch_1.png
Assets/Editor/Logo/gtgame/Launch_1.png.meta
New file
@@ -0,0 +1,128 @@
fileFormatVersion: 2
guid: 1acb149cfb080764ab981c0d335e05c0
TextureImporter:
  internalIDToNameTable: []
  externalObjects: {}
  serializedVersion: 11
  mipmaps:
    mipMapMode: 0
    enableMipMap: 0
    sRGBTexture: 1
    linearTexture: 0
    fadeOut: 0
    borderMipMap: 0
    mipMapsPreserveCoverage: 0
    alphaTestReferenceValue: 0.5
    mipMapFadeDistanceStart: 1
    mipMapFadeDistanceEnd: 3
  bumpmap:
    convertToNormalMap: 0
    externalNormalMap: 0
    heightScale: 0.25
    normalMapFilter: 0
  isReadable: 0
  streamingMipmaps: 0
  streamingMipmapsPriority: 0
  grayScaleToAlpha: 0
  generateCubemap: 6
  cubemapConvolution: 0
  seamlessCubemap: 0
  textureFormat: 1
  maxTextureSize: 2048
  textureSettings:
    serializedVersion: 2
    filterMode: 1
    aniso: -1
    mipBias: -100
    wrapU: 1
    wrapV: 1
    wrapW: 1
  nPOTScale: 0
  lightmap: 0
  compressionQuality: 50
  spriteMode: 1
  spriteExtrude: 1
  spriteMeshType: 1
  alignment: 0
  spritePivot: {x: 0.5, y: 0.5}
  spritePixelsToUnits: 100
  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
  spriteGenerateFallbackPhysicsShape: 1
  alphaUsage: 1
  alphaIsTransparency: 1
  spriteTessellationDetail: -1
  textureType: 8
  textureShape: 1
  singleChannelComponent: 0
  maxTextureSizeSet: 0
  compressionQualitySet: 0
  textureFormatSet: 0
  applyGammaDecoding: 1
  platformSettings:
  - serializedVersion: 3
    buildTarget: DefaultTexturePlatform
    maxTextureSize: 2048
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 1
  - serializedVersion: 3
    buildTarget: Standalone
    maxTextureSize: 2048
    resizeAlgorithm: 0
    textureFormat: 4
    textureCompression: 1
    compressionQuality: 1
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 1
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 1
  - serializedVersion: 3
    buildTarget: Android
    maxTextureSize: 1024
    resizeAlgorithm: 0
    textureFormat: 34
    textureCompression: 1
    compressionQuality: 1
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 1
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 1
  - serializedVersion: 3
    buildTarget: iPhone
    maxTextureSize: 1024
    resizeAlgorithm: 0
    textureFormat: 32
    textureCompression: 1
    compressionQuality: 1
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 1
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 1
  spriteSheet:
    serializedVersion: 2
    sprites: []
    outline: []
    physicsShape: []
    bones: []
    spriteID: 5e97eb03825dee720800000000000000
    internalID: 0
    vertices: []
    indices:
    edges: []
    weights: []
    secondaryTextures: []
  spritePackingTag:
  pSDRemoveMatte: 0
  pSDShowRemoveMatteOption: 0
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/Logo/gtgame/LoginBackGround.png
Assets/Editor/Logo/gtgame/LoginBackGround.png.meta
New file
@@ -0,0 +1,68 @@
fileFormatVersion: 2
guid: def12bc929e317046ac9dbcec54c3598
timeCreated: 1555914219
licenseType: Free
TextureImporter:
  fileIDToRecycleName: {}
  serializedVersion: 4
  mipmaps:
    mipMapMode: 0
    enableMipMap: 1
    sRGBTexture: 1
    linearTexture: 0
    fadeOut: 0
    borderMipMap: 0
    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:
    filterMode: -1
    aniso: -1
    mipBias: -1
    wrapMode: -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
  maxTextureSizeSet: 0
  compressionQualitySet: 0
  textureFormatSet: 0
  platformSettings:
  - buildTarget: DefaultTexturePlatform
    maxTextureSize: 2048
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
  spriteSheet:
    serializedVersion: 2
    sprites: []
    outline: []
  spritePackingTag:
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/Logo/gtgame/SplashImage.png
Assets/Editor/Logo/gtgame/SplashImage.png.meta
New file
@@ -0,0 +1,128 @@
fileFormatVersion: 2
guid: 3b92dd2ea17cdf342bfb6ea448a300e1
TextureImporter:
  internalIDToNameTable: []
  externalObjects: {}
  serializedVersion: 11
  mipmaps:
    mipMapMode: 0
    enableMipMap: 0
    sRGBTexture: 1
    linearTexture: 0
    fadeOut: 0
    borderMipMap: 0
    mipMapsPreserveCoverage: 0
    alphaTestReferenceValue: 0.5
    mipMapFadeDistanceStart: 1
    mipMapFadeDistanceEnd: 3
  bumpmap:
    convertToNormalMap: 0
    externalNormalMap: 0
    heightScale: 0.25
    normalMapFilter: 0
  isReadable: 0
  streamingMipmaps: 0
  streamingMipmapsPriority: 0
  grayScaleToAlpha: 0
  generateCubemap: 6
  cubemapConvolution: 0
  seamlessCubemap: 0
  textureFormat: 1
  maxTextureSize: 2048
  textureSettings:
    serializedVersion: 2
    filterMode: 0
    aniso: -1
    mipBias: -100
    wrapU: 1
    wrapV: 1
    wrapW: 1
  nPOTScale: 0
  lightmap: 0
  compressionQuality: 50
  spriteMode: 1
  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: 0
  alphaIsTransparency: 1
  spriteTessellationDetail: -1
  textureType: 8
  textureShape: 1
  singleChannelComponent: 0
  maxTextureSizeSet: 0
  compressionQualitySet: 0
  textureFormatSet: 0
  applyGammaDecoding: 1
  platformSettings:
  - serializedVersion: 3
    buildTarget: DefaultTexturePlatform
    maxTextureSize: 2048
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 1
  - 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: 1
  - serializedVersion: 3
    buildTarget: Android
    maxTextureSize: 2048
    resizeAlgorithm: 0
    textureFormat: 7
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 1
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 1
  - serializedVersion: 3
    buildTarget: iPhone
    maxTextureSize: 2048
    resizeAlgorithm: 0
    textureFormat: 7
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 1
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 1
  spriteSheet:
    serializedVersion: 2
    sprites: []
    outline: []
    physicsShape: []
    bones: []
    spriteID: 5e97eb03825dee720800000000000000
    internalID: 0
    vertices: []
    indices:
    edges: []
    weights: []
    secondaryTextures: []
  spritePackingTag:
  pSDRemoveMatte: 0
  pSDShowRemoveMatteOption: 0
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/Logo/gtgame/TB_DL_Logo.png
Assets/Editor/Logo/gtgame/TB_DL_Logo.png.meta
New file
@@ -0,0 +1,128 @@
fileFormatVersion: 2
guid: 3622e3598d53ef44b920180e89f04a41
TextureImporter:
  internalIDToNameTable: []
  externalObjects: {}
  serializedVersion: 11
  mipmaps:
    mipMapMode: 0
    enableMipMap: 0
    sRGBTexture: 1
    linearTexture: 0
    fadeOut: 0
    borderMipMap: 0
    mipMapsPreserveCoverage: 0
    alphaTestReferenceValue: 0.5
    mipMapFadeDistanceStart: 1
    mipMapFadeDistanceEnd: 3
  bumpmap:
    convertToNormalMap: 0
    externalNormalMap: 0
    heightScale: 0.25
    normalMapFilter: 0
  isReadable: 0
  streamingMipmaps: 0
  streamingMipmapsPriority: 0
  grayScaleToAlpha: 0
  generateCubemap: 6
  cubemapConvolution: 0
  seamlessCubemap: 0
  textureFormat: 1
  maxTextureSize: 2048
  textureSettings:
    serializedVersion: 2
    filterMode: 1
    aniso: -1
    mipBias: -100
    wrapU: 1
    wrapV: 1
    wrapW: 1
  nPOTScale: 0
  lightmap: 0
  compressionQuality: 50
  spriteMode: 1
  spriteExtrude: 1
  spriteMeshType: 1
  alignment: 0
  spritePivot: {x: 0.5, y: 0.5}
  spritePixelsToUnits: 100
  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
  spriteGenerateFallbackPhysicsShape: 1
  alphaUsage: 1
  alphaIsTransparency: 1
  spriteTessellationDetail: -1
  textureType: 8
  textureShape: 1
  singleChannelComponent: 0
  maxTextureSizeSet: 0
  compressionQualitySet: 0
  textureFormatSet: 0
  applyGammaDecoding: 1
  platformSettings:
  - serializedVersion: 3
    buildTarget: DefaultTexturePlatform
    maxTextureSize: 2048
    resizeAlgorithm: 0
    textureFormat: -1
    textureCompression: 1
    compressionQuality: 50
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 0
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 1
  - serializedVersion: 3
    buildTarget: Standalone
    maxTextureSize: 2048
    resizeAlgorithm: 0
    textureFormat: 4
    textureCompression: 1
    compressionQuality: 1
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 1
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 1
  - serializedVersion: 3
    buildTarget: Android
    maxTextureSize: 512
    resizeAlgorithm: 0
    textureFormat: 47
    textureCompression: 1
    compressionQuality: 1
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 1
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 1
  - serializedVersion: 3
    buildTarget: iPhone
    maxTextureSize: 2048
    resizeAlgorithm: 0
    textureFormat: 33
    textureCompression: 1
    compressionQuality: 1
    crunchedCompression: 0
    allowsAlphaSplitting: 0
    overridden: 1
    androidETC2FallbackOverride: 0
    forceMaximumCompressionQuality_BC6H_BC7: 1
  spriteSheet:
    serializedVersion: 2
    sprites: []
    outline: []
    physicsShape: []
    bones: []
    spriteID: 5e97eb03825dee720800000000000000
    internalID: 0
    vertices: []
    indices:
    edges: []
    weights: []
    secondaryTextures: []
  spritePackingTag:
  pSDRemoveMatte: 0
  pSDShowRemoveMatteOption: 0
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/Tool/AssetBundleBuildTool.cs
@@ -6,47 +6,47 @@
namespace Assets.Editor.Tool
{
    public class AssetBundleBuildTool
    {
        [MenuItem("Tools/AB增量打包(不设置Label)")]
        static void DoIt()
        {
            BuildAssetBundleOptions opt = BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.DeterministicAssetBundle | BuildAssetBundleOptions.StrictMode;
    // public class AssetBundleBuildTool
    // {
    //     [MenuItem("Tools/AB增量打包(不设置Label)")]
    //     static void DoIt()
    //     {
    //         BuildAssetBundleOptions opt = BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.DeterministicAssetBundle | BuildAssetBundleOptions.StrictMode;
            string outputPath = StringUtility.Contact(System.Environment.CurrentDirectory, "/AssetBundles/", EditorUserBuildSettings.activeBuildTarget.ToString());
            string streamingPath = StringUtility.Contact(Application.streamingAssetsPath, Path.AltDirectorySeparatorChar, EditorUserBuildSettings.activeBuildTarget.ToString());
    //         string outputPath = StringUtility.Contact(System.Environment.CurrentDirectory, "/AssetBundles/", EditorUserBuildSettings.activeBuildTarget.ToString());
    //         string streamingPath = StringUtility.Contact(Application.streamingAssetsPath, Path.AltDirectorySeparatorChar, EditorUserBuildSettings.activeBuildTarget.ToString());
            if (!Directory.Exists(outputPath))
                Directory.CreateDirectory(outputPath);
    //         if (!Directory.Exists(outputPath))
    //             Directory.CreateDirectory(outputPath);
            AssetBundleBuildExtersion.Build(outputPath, "builtin", opt, EditorUserBuildSettings.activeBuildTarget, false);
    //         AssetBundleBuildExtersion.Build(outputPath, "builtin", opt, EditorUserBuildSettings.activeBuildTarget, false);
            AssetBundleBuildExtersion.Build(outputPath, "audio", opt, EditorUserBuildSettings.activeBuildTarget, false);
    //         AssetBundleBuildExtersion.Build(outputPath, "audio", opt, EditorUserBuildSettings.activeBuildTarget, false);
            AssetBundleBuildExtersion.Build(outputPath, "mobeffectshader", opt, EditorUserBuildSettings.activeBuildTarget, false);
    //         AssetBundleBuildExtersion.Build(outputPath, "mobeffectshader", opt, EditorUserBuildSettings.activeBuildTarget, false);
            AssetBundleBuildExtersion.Build(outputPath, "config", opt, EditorUserBuildSettings.activeBuildTarget, false);
            TableTool.CopyConfigsToOutPutPath(StringUtility.Contact(outputPath, "/config"));
    //         AssetBundleBuildExtersion.Build(outputPath, "config", opt, EditorUserBuildSettings.activeBuildTarget, false);
    //         TableTool.CopyConfigsToOutPutPath(StringUtility.Contact(outputPath, "/config"));
            LuaBuildHelper.OnPreBuild();
            UpdateLuaSetting.SetAllLuaAssetBundleName();
            AssetBundleBuildExtersion.Build(outputPath, "lua", opt, EditorUserBuildSettings.activeBuildTarget, false);
            LuaBuildHelper.OnPostBuild();
    //         LuaBuildHelper.OnPreBuild();
    //         UpdateLuaSetting.SetAllLuaAssetBundleName();
    //         AssetBundleBuildExtersion.Build(outputPath, "lua", opt, EditorUserBuildSettings.activeBuildTarget, false);
    //         LuaBuildHelper.OnPostBuild();
            AssetBundleBuildExtersion.Build(outputPath, "maps", opt, EditorUserBuildSettings.activeBuildTarget, false);
    //         AssetBundleBuildExtersion.Build(outputPath, "maps", opt, EditorUserBuildSettings.activeBuildTarget, false);
            AssetBundleBuildExtersion.Build(outputPath, "ui", opt, EditorUserBuildSettings.activeBuildTarget, false);
    //         AssetBundleBuildExtersion.Build(outputPath, "ui", opt, EditorUserBuildSettings.activeBuildTarget, false);
            var fileInfos = new List<FileInfo>();
            FileExtersion.GetAllDirectoryFileInfos(outputPath, fileInfos);
            AssetsVersionMaker.WriteAssetsVersionFile(outputPath, fileInfos);
    //         var fileInfos = new List<FileInfo>();
    //         FileExtersion.GetAllDirectoryFileInfos(outputPath, fileInfos);
    //         AssetsVersionMaker.WriteAssetsVersionFile(outputPath, fileInfos);
            if (Directory.Exists(streamingPath))
                Directory.Delete(streamingPath, true);
    //         if (Directory.Exists(streamingPath))
    //             Directory.Delete(streamingPath, true);
            FileExtersion.DirectoryCopy(outputPath, streamingPath);
    //         FileExtersion.DirectoryCopy(outputPath, streamingPath);
        }
    }
    //     }
    // }
}
Assets/Editor/Tool/ClientPackage.cs
@@ -350,7 +350,6 @@
    public static void BuildApk(string _sdkPath, string _output, string _publisher, int _buildIndex, bool _development)
    {
        PreBuild(_publisher, _buildIndex);
        var auditTimeFile = StringUtility.Contact(Application.dataPath, Path.DirectorySeparatorChar, "Resources/Config/AuditTime.txt");
        if (File.Exists(auditTimeFile))
        {
Assets/Editor/Tool/UpdateAssetBundleName.cs
@@ -7,9 +7,9 @@
public class UpdateAllSetting
{
    [MenuItem("程序/设置资源包名/更新全部AssetBundleName")]
    [MenuItem("程序/设置资源包名/更新全部ABLabel(不包括lua)")]
    public static void SetAllAssetBundleName()
    {
    {
        UpdateSpriteSetting.SetAllSpriteAssetBundleName();
        UpdateUIWindowSetting.SetAllUIWindowAssetBundleName();
        UpdateUIPrefabSetting.SetAllUIPrefabAssetBundleName();
@@ -20,8 +20,10 @@
        UpdateLevelSetting.SetAllLevelAssetBundleName();
        UpdateAudioSetting.SetAllAudioAssetBundleName();
        UpdateVideoSetting.SetAllVideoAssetBundleName();
        UpdateLuaSetting.SetAllLuaAssetBundleName();
        // UpdateLuaSetting.SetAllLuaAssetBundleName();
        UpdateBuiltInSetting.SetBuiltinAssetBundleName();
        AssetDatabase.Refresh();
        DebugEx.Log("资源包名全部更新完成!");
    }
}
@@ -55,11 +57,11 @@
            var importerPath = spriteRelativePath + Path.DirectorySeparatorChar + pathStringArray[pathStringArray.Length - 1] + Path.DirectorySeparatorChar + file.Name;
            var importer = AssetImporter.GetAtPath(importerPath);
            importer.assetBundleName = "ui/sprite/" + pathStringArray[pathStringArray.Length - 1].ToLower();
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        DebugEx.Log("Sprite资源包名更新完成!");
        // AssetDatabase.SaveAssets();
        // AssetDatabase.Refresh();
    }
}
@@ -80,9 +82,8 @@
            var importer = AssetImporter.GetAtPath(path);
            importer.assetBundleName = "ui/window";
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        guids = AssetDatabase.FindAssets("t:prefab", new string[] { assetRelativePath2 });
        foreach (var guid in guids)
        {
@@ -90,11 +91,11 @@
            var importer = AssetImporter.GetAtPath(path);
            importer.assetBundleName = StringUtility.Contact("ui/prioritywindow/", Path.GetFileNameWithoutExtension(path).ToLower());
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        DebugEx.Log("Window资源包名更新完成!");
        // AssetDatabase.SaveAssets();
        // AssetDatabase.Refresh();
    }
}
@@ -121,7 +122,7 @@
            var importerPath = prefabAssetRelativePath + Path.DirectorySeparatorChar + file.Name;
            var importer = AssetImporter.GetAtPath(importerPath);
            importer.assetBundleName = "ui/prefab";
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        allFiles = new DirectoryInfo(bossShowRootPath).GetFiles("*.prefab", SearchOption.TopDirectoryOnly);
@@ -130,7 +131,7 @@
            var importerPath = bossShowAssetRelativePath + Path.DirectorySeparatorChar + file.Name;
            var importer = AssetImporter.GetAtPath(importerPath);
            importer.assetBundleName = "ui/bossshow";
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        allFiles = new DirectoryInfo(godWeaponRootPath).GetFiles("*.prefab", SearchOption.TopDirectoryOnly);
@@ -139,7 +140,7 @@
            var importerPath = godWeaponAssetRelativePath + Path.DirectorySeparatorChar + file.Name;
            var importer = AssetImporter.GetAtPath(importerPath);
            importer.assetBundleName = "ui/godweapon";
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        allFiles = new DirectoryInfo(treasureRootPath).GetFiles("*.prefab", SearchOption.AllDirectories);
@@ -149,11 +150,11 @@
            var importerPath = treasureAssetRelativePath + Path.DirectorySeparatorChar + pathStringArray[pathStringArray.Length - 1] + Path.DirectorySeparatorChar + file.Name;
            var importer = AssetImporter.GetAtPath(importerPath);
            importer.assetBundleName = "ui/treasure/" + pathStringArray[pathStringArray.Length - 1].ToLower();
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        DebugEx.Log("Prefab资源包名更新完成!");
        // AssetDatabase.SaveAssets();
        // AssetDatabase.Refresh();
    }
@@ -175,11 +176,11 @@
            var importerPath = assetPath + pathStringArray[pathStringArray.Length - 1] + Path.DirectorySeparatorChar + file.Name;
            var importer = AssetImporter.GetAtPath(importerPath);
            importer.assetBundleName = "effect/" + pathStringArray[pathStringArray.Length - 1].ToLower();
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        DebugEx.Log("Effect资源包名更新完成!");
        // AssetDatabase.SaveAssets();
        // AssetDatabase.Refresh();
    }
}
@@ -215,7 +216,7 @@
                                                 .Replace("Prefab_Hand", "");
            importer.assetBundleName = StringUtility.Contact("mob/prefab_race", hostfix);
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        allFiles = new DirectoryInfo(createroleRoot).GetFiles("*.prefab", SearchOption.TopDirectoryOnly);
@@ -225,7 +226,7 @@
            var extersion = Path.GetExtension(file.FullName);
            var importer = AssetImporter.GetAtPath(importerPath);
            importer.assetBundleName = "mob/createrole";
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        //var zsMaterialFiles = new DirectoryInfo(zsMaterialPath_Origin).GetFiles("*.mat", SearchOption.TopDirectoryOnly);
@@ -268,7 +269,7 @@
                string _abName = Path.GetFileNameWithoutExtension(_file.Name).Replace("_02", "").Replace("_Dm", "").Replace("_Dm_02", "");
                _importer.assetBundleName = "mob/prefab_race_" + _abName;
            }
            EditorUtility.SetDirty(_importer);
            // EditorUtility.SetDirty(_importer);
        }
        var fsMaterialPathOutFiles = new DirectoryInfo(fsMaterialPath_OutPut).GetFiles("*.mat", SearchOption.TopDirectoryOnly);
@@ -287,11 +288,11 @@
                string _abName = Path.GetFileNameWithoutExtension(_file.Name).Replace("_02", "").Replace("_Dm", "").Replace("_Dm_02", "");
                _importer.assetBundleName = "mob/prefab_race_" + _abName;
            }
            EditorUtility.SetDirty(_importer);
            // EditorUtility.SetDirty(_importer);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        // AssetDatabase.SaveAssets();
        // AssetDatabase.Refresh();
        //foreach (var file in zsMaterialFiles)
        //{
@@ -312,7 +313,7 @@
        //    importer.assetBundleName = "mob/a_fs_materials";
        //    EditorUtility.SetDirty(importer);
        //}
        DebugEx.Log("Mob资源包名更新完成!");
        //AssetDatabase.SaveAssets();
        //AssetDatabase.Refresh();
    }
@@ -332,11 +333,11 @@
            var importerPath = assetPath + Path.DirectorySeparatorChar + file.Name;
            var importer = AssetImporter.GetAtPath(importerPath);
            importer.assetBundleName = "graphic/shader";
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        DebugEx.Log("Shader资源包名更新完成!");
        // AssetDatabase.SaveAssets();
        // AssetDatabase.Refresh();
    }
}
@@ -361,12 +362,12 @@
                var importerPath = assetPath + relativePath + Path.DirectorySeparatorChar + file.Name;
                var importer = AssetImporter.GetAtPath(importerPath);
                importer.assetBundleName = "config/scriptableobjects";
                EditorUtility.SetDirty(importer);
                // EditorUtility.SetDirty(importer);
            }
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        DebugEx.Log("ScriptableObject资源包名更新完成!");
        // AssetDatabase.SaveAssets();
        // AssetDatabase.Refresh();
    }
}
@@ -400,7 +401,7 @@
            var importerPath = assetPath + Path.DirectorySeparatorChar + file.Name;
            var importer = AssetImporter.GetAtPath(importerPath);
            importer.assetBundleName = "maps/" + Path.GetFileNameWithoutExtension(file.FullName).ToLower();
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        var createRoleAssets = AssetDatabase.FindAssets("t:prefab", new string[] { "Assets/ResourcesOut/Scene/CreateRole" });
@@ -408,7 +409,7 @@
        {
            var importer = AssetImporter.GetAtPath(AssetDatabase.GUIDToAssetPath(item));
            importer.assetBundleName = "maps/createrole";
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        var textures = AssetDatabase.FindAssets("t:Texture2D", new string[] { "Assets/ResourcesOut/Scene/Textures" });
@@ -416,11 +417,11 @@
        {
            var importer = AssetImporter.GetAtPath(AssetDatabase.GUIDToAssetPath(item));
            importer.assetBundleName = "maps/textures";
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        DebugEx.Log("Level资源包名更新完成!");
        // AssetDatabase.SaveAssets();
        // AssetDatabase.Refresh();
    }
}
@@ -441,11 +442,11 @@
            var importerPath = assetPath + pathStringArray[pathStringArray.Length - 1] + Path.DirectorySeparatorChar + file.Name;
            var importer = AssetImporter.GetAtPath(importerPath);
            importer.assetBundleName = "audio/" + pathStringArray[pathStringArray.Length - 1].ToLower();
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        DebugEx.Log("Audio资源包名更新完成!");
        // AssetDatabase.SaveAssets();
        // AssetDatabase.Refresh();
    }
}
@@ -457,17 +458,19 @@
    [MenuItem("程序/设置资源包名/更新Video(All) AssetBundleName")]
    public static void SetAllVideoAssetBundleName()
    {
        if (!Directory.Exists(rootPath))
            return;
        var allFiles = new DirectoryInfo(rootPath).GetFiles("*.mp4", SearchOption.AllDirectories);
        foreach (var file in allFiles)
        {
            var importerPath = assetPath + file.Name;
            var importer = AssetImporter.GetAtPath(importerPath);
            importer.assetBundleName = "video/mp4";
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        DebugEx.Log("Video资源包名更新完成!");
        // AssetDatabase.SaveAssets();
        // AssetDatabase.Refresh();
    }
}
@@ -490,11 +493,11 @@
            var importerPath = assetPath + relativeDirectory + Path.DirectorySeparatorChar + file.Name;
            var importer = AssetImporter.GetAtPath(importerPath);
            importer.assetBundleName = "lua/" + relativeDirectory.ToLower();
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        DebugEx.Log("Lua资源包名更新完成!");
        // AssetDatabase.SaveAssets();
        // AssetDatabase.Refresh();
    }
}
@@ -524,10 +527,10 @@
            var importerPath = assetPath + relativeDirectory + Path.DirectorySeparatorChar + file.Name;
            var importer = AssetImporter.GetAtPath(importerPath);
            importer.assetBundleName = "builtin/" + relativeDirectory.ToLower();
            EditorUtility.SetDirty(importer);
            // EditorUtility.SetDirty(importer);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        DebugEx.Log("BuiltIn资源包名更新完成!");
        // AssetDatabase.SaveAssets();
        // AssetDatabase.Refresh();
    }
}
Assets/Editor/VersionConfigs/Versions.txt
@@ -1,11 +1,11 @@
Id    name    AppId    VersionAuthority    m_Version    m_ClientPackageFlag    m_Branch    m_GameId    m_AssetAccess    m_PartAssetPackage    m_ProductName    m_BundleIdentifier    m_KeystoreFileName    m_KeystorePassword    m_KeystoreAlias    m_KeystoreAliasPassword    m_AppleDeveloperTeamID    m_DebugVersion    m_IsBanShu    m_LogoPosition    m_BanHao    m_SpID    m_Recharge    m_CreateRolePattern
版本标识    版本名称    渠道id    版本权限,0是测试版本,1是发布版本    版本号    客户端标识    分支    游戏项目标识    资源,0NullAsset,1HalfAsset,2FullAsset,3IgnoreDownLoad    是否分包,0不分包,1分包    产品名    产品包名    签名文件名    签名文件密码    签名文件别名    签名文件别名密码    开发者账号密码    是否debug版本,0否1是    是否版署版本,0否1是    登录界面的Logo位置    版号    运营商ID    充值界面风格    创角场景风格
9999    TheSecondWorld    test    0    2.0.600    aaa    2    xbqy    1    1    仙宝奇缘    com.secondworld.snxxz    thesecondworld    thesecondworld2018    thesecondworld    thesecondworld2018        0    0    (-32,144)            0
10000    TheSecondWorld    test    0    1.100.1    aaa    7    xbqy    1    1    仙宝奇缘    com.secondworld.snxxz    thesecondworld    thesecondworld2018    thesecondworld    thesecondworld2018        0    0    (-32,144)            0
1    xbqy    226114725    1    2.0.600    test    900    xbqy    2    1    仙宝奇缘    com.shandangceshi.snxxz    shandangceshi    shandangceshi2018    shandangceshi    shandangceshi2018        0    0    (-32,144)        226114725    0
15    mgxbqy    mgxbqy    1    2.0.600    5001    1    xbqy    1    1    梦灵传说    com.mhtj.mg    shandangceshi    shandangceshi2018    shandangceshi    shandangceshi2018        0    0    (0,80)        mggame    0    1
16    mgxbqy    mgxbqy    1    2.0.600    5001    2    xbqy    1    1    梦灵传说    com.mhtj.mg    shandangceshi    shandangceshi2018    shandangceshi    shandangceshi2018        0    0    (0,80)        mggame    0    1
900    mgxbqy    mgxbqy    1    2.0.600    5001    2    xbqy    3    1    梦灵传说    com.mhtj.mg    shandangceshi    shandangceshi2018    shandangceshi    shandangceshi2018        0    0    (0,80)        mggame    0    1
Id    name    AppId    VersionAuthority    m_Version    m_ClientPackageFlag    m_Branch    m_GameId    m_AssetAccess    m_PartAssetPackage    m_ProductName    m_BundleIdentifier    m_KeystoreFileName    m_KeystorePassword    m_KeystoreAlias    m_KeystoreAliasPassword    m_AppleDeveloperTeamID    m_DebugVersion    m_IsBanShu    m_LogoPosition    m_BanHao    m_SpID    m_Recharge    m_CreateRolePattern
版本标识    版本名称    渠道id    版本权限,0是测试版本,1是发布版本    版本号    客户端标识    分支    游戏项目标识    资源,0NullAsset,1HalfAsset,2FullAsset,3IgnoreDownLoad    是否分包,0不分包,1分包    产品名    产品包名    签名文件名    签名文件密码    签名文件别名    签名文件别名密码    开发者账号密码    是否debug版本,0否1是    是否版署版本,0否1是    登录界面的Logo位置    版号    运营商ID    充值界面风格    创角场景风格
9999    TheSecondWorld    test    0    2.0.600    aaa    2    xbqy    1    1    仙宝奇缘    com.secondworld.snxxz    thesecondworld    thesecondworld2018    thesecondworld    thesecondworld2018        0    0    (-32,144)            0
10000    TheSecondWorld    test    0    1.100.1    aaa    7    xbqy    1    1    仙宝奇缘    com.secondworld.snxxz    thesecondworld    thesecondworld2018    thesecondworld    thesecondworld2018        0    0    (-32,144)            0
1    xbqy    226114725    1    2.0.600    test    900    xbqy    2    1    仙宝奇缘    com.shandangceshi.snxxz    shandangceshi    shandangceshi2018    shandangceshi    shandangceshi2018        0    0    (-32,144)        226114725    0
15    mgxbqy    mgxbqy    1    2.0.600    5001    1    xbqy    1    1    梦灵传说    com.mhtj.mg    shandangceshi    shandangceshi2018    shandangceshi    shandangceshi2018        0    0    (0,80)        mggame    0    1
16    mgxbqy    mgxbqy    1    2.0.600    5001    2    xbqy    1    1    梦灵传说    com.mhtj.mg    shandangceshi    shandangceshi2018    shandangceshi    shandangceshi2018        0    0    (0,80)        mggame    0    1
900    mgxbqy    mgxbqy    1    2.0.600    5001    2    xbqy    3    1    梦灵传说    com.mhtj.mg    shandangceshi    shandangceshi2018    shandangceshi    shandangceshi2018        0    0    (0,80)        mggame    0    1
9998    xmyjgame    xmyjgame    1    1.100.2    aaa    4    xbqy    1    1    仙魔战场    com.xfzc.yj.quick    mengxiandao    mengxiandao2020    mengxiandao    mengxiandao2020        0    0    (-15,64)    出版单位名称:天津电子出版社有限公司 著作权人名称:广州秒乐网络科技有限公司</r>运营单位:广州游路网络科技有限公司 游戏内容类别:移动游戏 批文号:国新出审[2019]1132号 游戏版号:ISBN 978-7-498-06329-8    xmyjgame    0    
9527    TheSecondWorld    test    0    1.100.1    aaa    2    xbqy    3    1    仙宝奇缘    com.secondworld.snxxz    thesecondworld    thesecondworld2018    thesecondworld    thesecondworld2018        0    0     (-32,144)            0
9528    gtgame    gtgame    1    1.0.0    aaa    1    xbqy    3    1    镇魔诀    com.sanxiagame.zmjgp    thesecondworld    thesecondworld2018    thesecondworld    thesecondworld2018                (0,80)        gtgame    0    1
9527    TheSecondWorld    test    0    1.100.1    aaa    2    xbqy    3    1    仙宝奇缘    com.secondworld.snxxz    thesecondworld    thesecondworld2018    thesecondworld    thesecondworld2018        0    0     (-32,144)            0
9528    gtgame    gtgame    1    1.0.0    aaa    1    xbqy    3    1    镇魔诀    com.sanxiagame.zmjgp    thesecondworld    thesecondworld2018    thesecondworld    thesecondworld2018        0    0    (0,80)        gtgame    0    1
Assets/Plugins/Android/AndroidManifest.xml
New file
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN-->
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.unity3d.player"
    xmlns:tools="http://schemas.android.com/tools">
    <application>
        <activity android:name="com.secondworld.sdk.GameActivity"
                  android:theme="@style/UnityThemeSelector">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        </activity>
    </application>
</manifest>
Assets/Plugins/Android/AndroidManifest.xml.meta
New file
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 44ea7b20ff03e7c479f5a35eac4f2ef4
TextScriptImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Plugins/Android/mainTemplate.gradle
New file
@@ -0,0 +1,39 @@
// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN
apply plugin: 'com.android.library'
//**APPLY_PLUGINS**
apply from: 'deps.gradle'
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
**DEPS**}
android {
    compileSdkVersion **APIVERSION**
    buildToolsVersion '**BUILDTOOLS**'
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    defaultConfig {
        minSdkVersion **MINSDKVERSION**
        targetSdkVersion **TARGETSDKVERSION**
        ndk {
            abiFilters **ABIFILTERS**
        }
        versionCode **VERSIONCODE**
        versionName '**VERSIONNAME**'
        consumerProguardFiles 'proguard-unity.txt'**USER_PROGUARD**
    }
    lintOptions {
        abortOnError false
    }
    aaptOptions {
        ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~"
    }**PACKAGING_OPTIONS**
}**REPOSITORIES****SOURCE_BUILD_SETUP**
**EXTERNAL_SOURCES**
Assets/Plugins/Android/mainTemplate.gradle.meta
New file
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b2f2a20fb46444e4fa7af5d82a94bba1
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Resources/VersionConfig.asset
@@ -13,7 +13,7 @@
  m_Name: VersionConfig
  m_EditorClassIdentifier: 
  m_AppId: gtgame
  m_SpID:
  m_SpID: gtgame
  m_VersionAuthority: 1
  m_Version: 1.0.0
  m_ClientPackageFlag: aaa
@@ -29,7 +29,7 @@
  m_AppleDeveloperTeamID: 
  m_DebugVersion: 0
  m_IsBanShu: 0
  m_BuildTime: 20/11/25--15:58
  m_BuildIndex: 59
  m_LogoPosition: {x: 0, y: 0}
  m_BuildTime: 20/11/27--17:40
  m_BuildIndex: 7
  m_LogoPosition: {x: 0, y: 80}
  m_BanHao: 
ProjectSettings/ProjectSettings.asset
@@ -13,7 +13,7 @@
  useOnDemandResources: 0
  accelerometerFrequency: 0
  companyName: TheSecondWorld
  productName: "\u4ED9\u5B9D\u5947\u7F18"
  productName: "\u9547\u9B54\u8BC0"
  defaultCursor: {fileID: 0}
  cursorHotspot: {x: 0, y: 0}
  m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
@@ -40,7 +40,7 @@
    width: 1
    height: 1
  m_SplashScreenLogos:
  - logo: {fileID: 0}
  - logo: {fileID: 21300000, guid: 3b92dd2ea17cdf342bfb6ea448a300e1, type: 3}
    duration: 3
  m_VirtualRealitySplashScreen: {fileID: 0}
  m_ShowUnitySplashAds: 0
@@ -133,7 +133,7 @@
    16:10: 1
    16:9: 1
    Others: 1
  bundleVersion: 1100001
  bundleVersion: 1000000
  preloadedAssets: []
  metroInputSource: 0
  wsaTransparentSwapchain: 0
@@ -177,7 +177,7 @@
  androidSupportedAspectRatio: 1
  androidMaxAspectRatio: 2.1
  applicationIdentifier:
    Android: com.secondworld.snxxz
    Android: com.sanxiagame.zmjgp
    Standalone: com.secondworld.snxxz
    iPhone: com.secondworld.snxxz
  buildNumber: {}
@@ -261,7 +261,7 @@
  templateDefaultScene: 
  AndroidTargetArchitectures: 3
  AndroidSplashScreenScale: 2
  androidSplashScreen: {fileID: 2800000, guid: 179f9801f106906489c8b6bcc9896c8a, type: 3}
  androidSplashScreen: {fileID: 2800000, guid: 3b92dd2ea17cdf342bfb6ea448a300e1, type: 3}
  AndroidKeystoreName: '{inproject}: Assets/Editor/Keystore/thesecondworld.keystore'
  AndroidKeyaliasName: thesecondworld
  AndroidBuildApkPerCpuArchitecture: 0
@@ -459,37 +459,37 @@
      m_Kind: 1
      m_SubKind: 
    - m_Textures:
      - {fileID: 0}
      - {fileID: 2800000, guid: ac584e55bf0df494694449ee1780d805, type: 3}
      m_Width: 192
      m_Height: 192
      m_Kind: 0
      m_SubKind: 
    - m_Textures:
      - {fileID: 0}
      - {fileID: 2800000, guid: ac584e55bf0df494694449ee1780d805, type: 3}
      m_Width: 144
      m_Height: 144
      m_Kind: 0
      m_SubKind: 
    - m_Textures:
      - {fileID: 0}
      - {fileID: 2800000, guid: ac584e55bf0df494694449ee1780d805, type: 3}
      m_Width: 96
      m_Height: 96
      m_Kind: 0
      m_SubKind: 
    - m_Textures:
      - {fileID: 0}
      - {fileID: 2800000, guid: ac584e55bf0df494694449ee1780d805, type: 3}
      m_Width: 72
      m_Height: 72
      m_Kind: 0
      m_SubKind: 
    - m_Textures:
      - {fileID: 0}
      - {fileID: 2800000, guid: ac584e55bf0df494694449ee1780d805, type: 3}
      m_Width: 48
      m_Height: 48
      m_Kind: 0
      m_SubKind: 
    - m_Textures:
      - {fileID: 0}
      - {fileID: 2800000, guid: ac584e55bf0df494694449ee1780d805, type: 3}
      m_Width: 36
      m_Height: 36
      m_Kind: 0