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