using System.Globalization; //#define FR2_DEBUG_BRACE_LEVEL //#define FR2_DEBUG_SYMBOL //#define FR2_DEBUG using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; #if FR2_ADDRESSABLE using UnityEditor.AddressableAssets; using UnityEngine.AddressableAssets; #endif using UnityObject = UnityEngine.Object; namespace vietlabs.fr2 { public enum FR2_AssetType { UNKNOWN, FOLDER, SCRIPT, SCENE, DLL, REFERENCABLE, BINARY_ASSET, MODEL, TERRAIN, NON_READABLE } public enum FR2_AssetState { NEW, CACHE, MISSING } [Serializable] public class FR2_Asset { // ------------------------------ CONSTANTS --------------------------- private static readonly HashSet SCRIPT_EXTENSIONS = new HashSet { ".cs", ".js", ".boo", ".h", ".java", ".cpp", ".m", ".mm" }; private static readonly HashSet REFERENCABLE_EXTENSIONS = new HashSet { ".anim", ".controller", ".mat", ".unity", ".guiskin", ".prefab", ".overridecontroller", ".mask", ".rendertexture", ".cubemap", ".flare", ".mat", ".prefab", ".physicsmaterial", ".fontsettings", ".asset", ".prefs", ".spriteatlas" }; private static readonly Dictionary HashClasses = new Dictionary(); internal static Dictionary cacheImage = new Dictionary(); private bool _isExcluded; private Dictionary> _UseGUIDs; private float excludeTS; public static float ignoreTS; // ----------------------------- DRAW --------------------------------------- [NonSerialized] private GUIContent fileSizeText; // ----------------------------- DRAW --------------------------------------- [SerializeField] public string guid; // easy to recalculate: will not cache [NonSerialized] private bool m_pathLoaded; [NonSerialized] private string m_assetFolder; [NonSerialized] private string m_assetName; [NonSerialized] private string m_assetPath; [NonSerialized] private string m_extension; [NonSerialized] private bool m_inEditor; [NonSerialized] private bool m_inPlugins; [NonSerialized] private bool m_inResources; [NonSerialized] private bool m_inStreamingAsset; [NonSerialized] private bool m_isAssetFile; // Need to read FileInfo: soft-cache (always re-read when needed) [SerializeField] public FR2_AssetType type; [SerializeField] private string m_fileInfoHash; [SerializeField] private string m_assetbundle; [SerializeField] private string m_addressable; [SerializeField] private string m_atlas; [SerializeField] private long m_fileSize; [SerializeField] private int m_assetChangeTS; // Realtime when asset changed (trigger by import asset operation) [SerializeField] private int m_fileInfoReadTS; // Realtime when asset being read [SerializeField] private int m_fileWriteTS; // file's lastModification (file content + meta) [SerializeField] private int m_cachefileWriteTS; // file's lastModification at the time the content being read [SerializeField] internal int refreshStamp; // use to check if asset has been deleted (refreshStamp not updated) // Do not cache [NonSerialized] internal FR2_AssetState state; internal Dictionary UsedByMap = new Dictionary(); internal HashSet HashUsedByClassesIds = new HashSet(); [SerializeField] private List UseGUIDsList = new List(); public FR2_Asset(string guid) { this.guid = guid; type = FR2_AssetType.UNKNOWN; } // ----------------------- PATH INFO ------------------------ public void LoadPathInfo() { if (m_pathLoaded) return; m_pathLoaded = true; m_assetPath = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(assetPath)) { state = FR2_AssetState.MISSING; return; } #if FR2_DEBUG Debug.LogWarning("Refreshing ... " + loadInfoTS + ":" + AssetDatabase.GUIDToAssetPath(guid)); if (!m_assetPath.StartsWith("Assets")) { Debug.Log("LoadAssetInfo: " + m_assetPath); } #endif FR2_Unity.SplitPath(m_assetPath, out m_assetName, out m_extension, out m_assetFolder); if (m_assetFolder.StartsWith("Assets/")) { m_assetFolder = m_assetFolder.Substring(7); } else if (!FR2_Unity.StringStartsWith(m_assetPath, "Packages/", "Project Settings/", "Library/")) { m_assetFolder = "built-in/"; } m_inEditor = m_assetPath.Contains("/Editor/") || m_assetPath.Contains("/Editor Default Resources/"); m_inResources = m_assetPath.Contains("/Resources/"); m_inStreamingAsset = m_assetPath.Contains("/StreamingAssets/"); m_inPlugins = m_assetPath.Contains("/Plugins/"); m_isAssetFile = m_assetPath.EndsWith(".asset", StringComparison.Ordinal); } public string assetName { get { LoadPathInfo(); return m_assetName; } } public string assetPath { get { if (!string.IsNullOrEmpty(m_assetPath)) return m_assetPath; m_assetPath = AssetDatabase.GUIDToAssetPath(guid); if (string.IsNullOrEmpty(m_assetPath)) { state = FR2_AssetState.MISSING; } return m_assetPath; } } public string parentFolderPath { get { LoadPathInfo(); return m_assetFolder; } } public string assetFolder { get { LoadPathInfo(); return m_assetFolder; } } public string extension { get { LoadPathInfo(); return m_extension; } } public bool inEditor { get { LoadPathInfo(); return m_inEditor; } } public bool inPlugins { get { LoadPathInfo(); return m_inPlugins; } } public bool inResources { get { LoadPathInfo(); return m_inResources; } } public bool inStreamingAsset { get { LoadPathInfo(); return m_inStreamingAsset; } } // ----------------------- TYPE INFO ------------------------ internal bool IsFolder { get { return type == FR2_AssetType.FOLDER; } } internal bool IsScript { get { return type == FR2_AssetType.SCRIPT; } } internal bool IsMissing { get { return state == FR2_AssetState.MISSING; } } internal bool IsReferencable { get { return type == FR2_AssetType.REFERENCABLE || type == FR2_AssetType.SCENE; }} internal bool IsBinaryAsset { get { return type == FR2_AssetType.BINARY_ASSET || type == FR2_AssetType.MODEL || type == FR2_AssetType.TERRAIN; }} // ----------------------- PATH INFO ------------------------ public bool fileInfoDirty { get { return (type == FR2_AssetType.UNKNOWN) || (m_fileInfoReadTS <= m_assetChangeTS); } } public bool fileContentDirty { get { return m_fileWriteTS != m_cachefileWriteTS; } } public bool isDirty { get { return fileInfoDirty || fileContentDirty; } } bool ExistOnDisk() { if (IsMissing) return false; // asset not exist - no need to check FileSystem! if (type == FR2_AssetType.FOLDER || type == FR2_AssetType.UNKNOWN) { if (Directory.Exists(m_assetPath)) { if (type == FR2_AssetType.UNKNOWN) type = FR2_AssetType.FOLDER; return true; } if (type == FR2_AssetType.FOLDER) return false; } // must be file here if (!File.Exists(m_assetPath)) return false; if (type == FR2_AssetType.UNKNOWN) GuessAssetType(); return true; } internal void LoadFileInfo() { if (!fileInfoDirty) return; if (string.IsNullOrEmpty(m_assetPath)) LoadPathInfo(); // always reload Path Info //Debug.Log("--> Read: " + assetPath + " --> " + m_fileInfoReadTS + "<" + m_assetChangeTS); m_fileInfoReadTS = FR2_Unity.Epoch(DateTime.Now); if (IsMissing) { Debug.LogWarning("Should never be here! - missing files can not trigger LoadFileInfo()"); return; } if (!ExistOnDisk()) { state = FR2_AssetState.MISSING; return; } if (type == FR2_AssetType.FOLDER) return; // nothing to read var assetType = AssetDatabase.GetMainAssetTypeAtPath(m_assetPath); if (assetType == typeof(FR2_Cache)) return; var info = new FileInfo(m_assetPath); m_fileSize = info.Length; m_fileInfoHash = info.Length + info.Extension; m_addressable = FR2_Unity.GetAddressable(guid); //if (!string.IsNullOrEmpty(m_addressable)) Debug.LogWarning(guid + " --> " + m_addressable); m_assetbundle = AssetDatabase.GetImplicitAssetBundleName(m_assetPath); if (assetType == typeof(Texture2D)) { var importer = AssetImporter.GetAtPath(m_assetPath); if (importer is TextureImporter) { var tImporter = importer as TextureImporter; if (tImporter.qualifiesForSpritePacking) { m_atlas = tImporter.spritePackingTag; } } } // check if file content changed var metaInfo = new FileInfo(m_assetPath + ".meta"); var assetTime = FR2_Unity.Epoch(info.LastWriteTime); var metaTime = FR2_Unity.Epoch(metaInfo.LastWriteTime); // update fileChangeTimeStamp m_fileWriteTS = Mathf.Max(metaTime, assetTime); } internal string fileInfoHash { get { LoadFileInfo(); return m_fileInfoHash; } } internal long fileSize { get { LoadFileInfo(); return m_fileSize; } } public string AtlasName { get { LoadFileInfo(); return m_atlas;}} public string AssetBundleName { get { LoadFileInfo(); return m_assetbundle;}} public string AddressableName { get { LoadFileInfo(); return m_addressable; }} public Dictionary> UseGUIDs { get { if (_UseGUIDs != null) { return _UseGUIDs; } _UseGUIDs = new Dictionary>(UseGUIDsList.Count); for (var i = 0; i < UseGUIDsList.Count; i++) { string guid = UseGUIDsList[i].guid; if (_UseGUIDs.ContainsKey(guid)) { for (var j = 0; j < UseGUIDsList[i].ids.Count; j++) { int val = UseGUIDsList[i].ids[j]; if (_UseGUIDs[guid].Contains(val)) { continue; } _UseGUIDs[guid].Add(UseGUIDsList[i].ids[j]); } } else { _UseGUIDs.Add(guid, new HashSet(UseGUIDsList[i].ids)); } } return _UseGUIDs; } } // ------------------------------- GETTERS ----------------------------- internal bool IsExcluded { get { if (excludeTS >= ignoreTS) { return _isExcluded; } excludeTS = ignoreTS; _isExcluded = false; HashSet h = FR2_Setting.IgnoreAsset; foreach (string item in FR2_Setting.IgnoreAsset) { if (m_assetPath.StartsWith(item, false, CultureInfo.InvariantCulture)) { _isExcluded = true; break; } } return _isExcluded; } } public void AddUsedBy(string guid, FR2_Asset asset) { if (UsedByMap.ContainsKey(guid)) { return; } if(guid == this.guid) { //Debug.LogWarning("self used"); return; } UsedByMap.Add(guid, asset); HashSet output; if (HashUsedByClassesIds == null) { HashUsedByClassesIds = new HashSet(); } if (asset.UseGUIDs.TryGetValue(this.guid, out output)) { foreach (int item in output) { HashUsedByClassesIds.Add(item); } } // int classId = HashUseByClassesIds } public int UsageCount() { return UsedByMap.Count; } public override string ToString() { return string.Format("FR2_Asset[{0}]", m_assetName); } //--------------------------------- STATIC ---------------------------- internal static bool IsValidGUID(string guid) { return AssetDatabase.GUIDToAssetPath(guid) != FR2_Cache.CachePath; // just skip FR2_Cache asset } internal void MarkAsDirty(bool isMoved = true, bool force = false) { if (isMoved) { var newPath = AssetDatabase.GUIDToAssetPath(guid); if (newPath != m_assetPath) { m_pathLoaded = false; m_assetPath = newPath; } } state = FR2_AssetState.CACHE; m_assetChangeTS = FR2_Unity.Epoch(DateTime.Now); // re-read FileInfo if (force) m_cachefileWriteTS = 0; } // --------------------------------- APIs ------------------------------ internal void GuessAssetType() { if (SCRIPT_EXTENSIONS.Contains(m_extension)) { type = FR2_AssetType.SCRIPT; } else if (REFERENCABLE_EXTENSIONS.Contains(m_extension)) { bool isUnity = m_extension == ".unity"; type = isUnity ? FR2_AssetType.SCENE : FR2_AssetType.REFERENCABLE; if (m_extension == ".asset" || isUnity || m_extension == ".spriteatlas") { var buffer = new byte[5]; try { FileStream stream = File.OpenRead(m_assetPath); stream.Read(buffer, 0, 5); stream.Close(); } #if FR2_DEBUG catch (Exception e) { Debug.LogWarning("Guess Asset Type error :: " + e + "\n" + m_assetPath); #else catch { #endif state = FR2_AssetState.MISSING; return; } string str = string.Empty; foreach (byte t in buffer) { str += (char) t; } if (str != "%YAML") { type = FR2_AssetType.BINARY_ASSET; } } } else if (m_extension == ".fbx") { type = FR2_AssetType.MODEL; } else if (m_extension == ".dll") { type = FR2_AssetType.DLL; } else { type = FR2_AssetType.NON_READABLE; } } internal void LoadContent() { if (!fileContentDirty) return; m_cachefileWriteTS = m_fileWriteTS; if (IsMissing || type == FR2_AssetType.NON_READABLE) { return; } if (type == FR2_AssetType.DLL) { #if FR2_DEBUG Debug.LogWarning("Parsing DLL not yet supportted "); #endif return; } if (!ExistOnDisk()) { state = FR2_AssetState.MISSING; return; } ClearUseGUIDs(); if (IsFolder) { LoadFolder(); } else if (IsReferencable) { LoadYAML2(); } else if (IsBinaryAsset) { LoadBinaryAsset(); } } internal void AddUseGUID(string fguid, int fFileId = -1, bool checkExist = true) { // if (checkExist && UseGUIDs.ContainsKey(fguid)) return; if (!IsValidGUID(fguid)) { return; } if (!UseGUIDs.ContainsKey(fguid)) { UseGUIDsList.Add(new Classes { guid = fguid, ids = new List() }); UseGUIDs.Add(fguid, new HashSet()); } if (fFileId != -1) { if (UseGUIDs[fguid].Contains(fFileId)) { return; } UseGUIDs[fguid].Add(fFileId); Classes i = UseGUIDsList.FirstOrDefault(x => x.guid == fguid); if (i != null) { i.ids.Add(fFileId); } } } // ----------------------------- STATIC --------------------------------------- internal static int SortByExtension(FR2_Asset a1, FR2_Asset a2) { if (a1 == null) { return -1; } if (a2 == null) { return 1; } int result = string.Compare(a1.m_extension, a2.m_extension, StringComparison.Ordinal); return result == 0 ? string.Compare(a1.m_assetName, a2.m_assetName, StringComparison.Ordinal) : result; } internal static List FindUsage(FR2_Asset asset) { if (asset == null) { return null; } List refs = FR2_Cache.Api.FindAssets(asset.UseGUIDs.Keys.ToArray(), true); return refs; } internal static List FindUsedBy(FR2_Asset asset) { return asset.UsedByMap.Values.ToList(); } internal static List FindUsageGUIDs(FR2_Asset asset, bool includeScriptSymbols) { var result = new HashSet(); if (asset == null) { Debug.LogWarning("Asset invalid : " + asset.m_assetName); return result.ToList(); } // for (var i = 0;i < asset.UseGUIDs.Count; i++) // { // result.Add(asset.UseGUIDs[i]); // } foreach (KeyValuePair> item in asset.UseGUIDs) { result.Add(item.Key); } //if (!includeScriptSymbols) return result.ToList(); //if (asset.ScriptUsage != null) //{ // for (var i = 0; i < asset.ScriptUsage.Count; i++) // { // var symbolList = FR2_Cache.Api.FindAllSymbol(asset.ScriptUsage[i]); // if (symbolList.Contains(asset)) continue; // var symbol = symbolList[0]; // if (symbol == null || result.Contains(symbol.guid)) continue; // result.Add(symbol.guid); // } //} return result.ToList(); } internal static List FindUsedByGUIDs(FR2_Asset asset) { return asset.UsedByMap.Keys.ToList(); } internal float Draw(Rect r, bool highlight, bool drawPath = true, bool showFileSize = true, bool showABName = false, bool showAtlasName = false, bool showUsageIcon = true, IWindow window = null ){ bool singleLine = r.height <= 18f; float rw = r.width; bool selected = FR2_Bookmark.Contains(guid); r.height = 16f; bool hasMouse = Event.current.type == EventType.MouseUp && r.Contains(Event.current.mousePosition); if (hasMouse && Event.current.button == 1) { var menu = new GenericMenu(); if (m_extension == ".prefab") { menu.AddItem(new GUIContent("Edit in Scene"), false, EditPrefab); } menu.AddItem(new GUIContent("Open"), false, Open); menu.AddItem(new GUIContent("Ping"), false, Ping); menu.AddItem(new GUIContent(guid), false, CopyGUID); //menu.AddItem(new GUIContent("Reload"), false, Reload); menu.AddSeparator(string.Empty); menu.AddItem(new GUIContent("Bookmark"), selected, AddToSelection); menu.AddSeparator(string.Empty); menu.AddItem(new GUIContent("Copy path"), false, CopyAssetPath); menu.AddItem(new GUIContent("Copy full path"), false, CopyAssetPathFull); //if (IsScript) //{ // menu.AddSeparator(string.Empty); // AddArray(menu, ScriptSymbols, "+ ", "Definitions", "No Definition", false); // menu.AddSeparator(string.Empty); // AddArray(menu, ScriptUsage, "-> ", "Depends", "No Dependency", true); //} menu.ShowAsContext(); Event.current.Use(); } if (IsMissing) { if (!singleLine) { r.y += 16f; } if (Event.current.type != EventType.Repaint) { return 0; } GUI.Label(r, "(missing) " + guid, EditorStyles.whiteBoldLabel); return 0; } Rect iconRect = GUI2.LeftRect(16f, ref r); if (Event.current.type == EventType.Repaint) { Texture icon = AssetDatabase.GetCachedIcon(m_assetPath); if (icon != null) { GUI.DrawTexture(iconRect, icon); } } if (Event.current.type == EventType.MouseDown && Event.current.button == 0) { Rect pingRect = FR2_Setting.PingRow ? new Rect(0, r.y, r.x + r.width, r.height) : iconRect; if (pingRect.Contains(Event.current.mousePosition)) { if (Event.current.control || Event.current.command) { if (selected) { RemoveFromSelection(); } else { AddToSelection(); } if (window != null) { window.Repaint(); } } else { Ping(); } //Event.current.Use(); } } if (Event.current.type != EventType.Repaint) { return 0; } if (UsedByMap != null && UsedByMap.Count > 0) { var str = new GUIContent(UsedByMap.Count.ToString()); Rect countRect = iconRect; countRect.x -= 16f; countRect.xMin = -10f; GUI.Label(countRect, str, GUI2.miniLabelAlignRight); } float pathW = drawPath ? EditorStyles.miniLabel.CalcSize(new GUIContent(m_assetFolder)).x : 0; float nameW = EditorStyles.boldLabel.CalcSize(new GUIContent(m_assetName)).x; Color cc = FR2_Cache.Api.setting.SelectedColor; if (singleLine) { Rect lbRect = GUI2.LeftRect(pathW + nameW, ref r); if (selected) { Color c1 = GUI.color; GUI.color = cc; GUI.DrawTexture(lbRect, EditorGUIUtility.whiteTexture); GUI.color = c1; } if (drawPath) { Color c2 = GUI.color; GUI.color = new Color(c2.r, c2.g, c2.b, c2.a*0.5f); GUI.Label(GUI2.LeftRect(pathW, ref lbRect), m_assetFolder, EditorStyles.miniLabel); GUI.color = c2; lbRect.xMin -= 4f; GUI.Label(lbRect, m_assetName, EditorStyles.boldLabel); } else { GUI.Label(lbRect, m_assetName); } } else { if (drawPath) { GUI.Label(new Rect(r.x, r.y + 16f, r.width, r.height), m_assetFolder, EditorStyles.miniLabel); } Rect lbRect = GUI2.LeftRect(nameW, ref r); if (selected) { GUI2.Rect(lbRect, cc); } GUI.Label(lbRect, m_assetName, EditorStyles.boldLabel); } var rr = GUI2.RightRect(10f, ref r); //margin if (highlight) { rr.xMin += 2f; rr.width = 1f; GUI2.Rect(rr, GUI2.darkGreen); } Color c = GUI.color; GUI.color = new Color(c.r, c.g, c.b, c.a*0.5f); if (showFileSize) { Rect fsRect = GUI2.RightRect(40f, ref r); // filesize label if (fileSizeText == null) { fileSizeText = new GUIContent(FR2_Helper.GetfileSizeString(fileSize)); } GUI.Label(fsRect, fileSizeText, GUI2.miniLabelAlignRight); } if (!string.IsNullOrEmpty(m_addressable)) { Rect adRect = GUI2.RightRect(100f, ref r); GUI.Label(adRect, m_addressable, GUI2.miniLabelAlignRight); } if (showUsageIcon && HashUsedByClassesIds != null) { foreach (int item in HashUsedByClassesIds) { if (!FR2_Unity.HashClassesNormal.ContainsKey(item)) { continue; } string name = FR2_Unity.HashClassesNormal[item]; Type t = null; if (!HashClasses.TryGetValue(item, out t)) { t = FR2_Unity.GetType(name); HashClasses.Add(item, t); } GUIContent content = null; var isExisted = cacheImage.TryGetValue(name, out content); if (content == null) content = new GUIContent(EditorGUIUtility.ObjectContent(null, t).image, name); if (!isExisted) { cacheImage.Add(name, content); } else { cacheImage[name] = content; } if (content != null) { try { GUI.Label(GUI2.RightRect(15f, ref r), content, GUI2.miniLabelAlignRight); } #if !FR2_DEBUG catch {} #else catch (Exception e) { UnityEngine.Debug.LogWarning(e); } #endif } } } if (showAtlasName) { GUI2.RightRect(10f, ref r); //margin Rect abRect = GUI2.RightRect(120f, ref r); // filesize label if (!string.IsNullOrEmpty(m_atlas)) { GUI.Label(abRect, m_atlas, GUI2.miniLabelAlignRight); } } if (showABName) { GUI2.RightRect(10f, ref r); //margin Rect abRect = GUI2.RightRect(100f, ref r); // filesize label if (!string.IsNullOrEmpty(m_assetbundle)) { GUI.Label(abRect, m_assetbundle, GUI2.miniLabelAlignRight); } } if (true) { GUI2.RightRect(10f, ref r); //margin Rect abRect = GUI2.RightRect(100f, ref r); // filesize label if (!string.IsNullOrEmpty(m_addressable)) { GUI.Label(abRect, m_addressable, GUI2.miniLabelAlignRight); } } GUI.color = c; if (Event.current.type == EventType.Repaint) { return rw < pathW + nameW ? 32f : 18f; } return r.height; } internal GenericMenu AddArray(GenericMenu menu, List list, string prefix, string title, string emptyTitle, bool showAsset, int max = 10) { //if (list.Count > 0) //{ // if (list.Count > max) // { // prefix = string.Format("{0} _{1}/", title, list.Count) + prefix; // } // //for (var i = 0; i < list.Count; i++) // //{ // // var def = list[i]; // // var suffix = showAsset ? "/" + FR2_Cache.Api.FindSymbol(def).assetName : string.Empty; // // menu.AddItem(new GUIContent(prefix + def + suffix), false, () => OpenScript(def)); // //} //} //else { menu.AddItem(new GUIContent(emptyTitle), true, null); } return menu; } internal void CopyGUID() { EditorGUIUtility.systemCopyBuffer = guid; Debug.Log(guid); } internal void CopyName() { EditorGUIUtility.systemCopyBuffer = m_assetName; Debug.Log(m_assetName); } internal void CopyAssetPath() { EditorGUIUtility.systemCopyBuffer = m_assetPath; Debug.Log(m_assetPath); } internal void CopyAssetPathFull() { string fullName = new FileInfo(m_assetPath).FullName; EditorGUIUtility.systemCopyBuffer = fullName; Debug.Log(fullName); } internal void AddToSelection() { if (!FR2_Bookmark.Contains(guid)) { FR2_Bookmark.Add(guid); } //var list = Selection.objects.ToList(); //var obj = FR2_Unity.LoadAssetAtPath(assetPath); //if (!list.Contains(obj)) //{ // list.Add(obj); // Selection.objects = list.ToArray(); //} } internal void RemoveFromSelection() { if (FR2_Bookmark.Contains(guid)) { FR2_Bookmark.Remove(guid); } } internal void Ping() { EditorGUIUtility.PingObject( AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject)) ); } internal void Open() { AssetDatabase.OpenAsset( AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject)) ); } internal void EditPrefab() { UnityObject prefab = AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject)); UnityObject.Instantiate(prefab); } //internal void OpenScript(string definition) //{ // var asset = FR2_Cache.Api.FindSymbol(definition); // if (asset == null) return; // EditorGUIUtility.PingObject( // AssetDatabase.LoadAssetAtPath(asset.assetPath, typeof(Object)) // ); //} // ----------------------------- SERIALIZED UTILS --------------------------------------- // ----------------------------- LOAD ASSETS --------------------------------------- internal void LoadGameObject(GameObject go) { Component[] compList = go.GetComponentsInChildren(); for (var i = 0; i < compList.Length; i++) { LoadSerialized(compList[i]); } } internal void LoadSerialized(UnityObject target) { SerializedProperty[] props = FR2_Unity.xGetSerializedProperties(target, true); for (var i = 0; i < props.Length; i++) { if (props[i].propertyType != SerializedPropertyType.ObjectReference) { continue; } UnityObject refObj = props[i].objectReferenceValue; if (refObj == null) { continue; } string refGUID = AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath(refObj) ); //Debug.Log("Found Reference BinaryAsset <" + assetPath + "> : " + refGUID + ":" + refObj); AddUseGUID(refGUID); } } internal void LoadTerrainData(TerrainData terrain) { #if UNITY_2018_3_OR_NEWER TerrainLayer[] arr0 = terrain.terrainLayers; for (var i = 0; i < arr0.Length; i++) { string aPath = AssetDatabase.GetAssetPath(arr0[i]); string refGUID = AssetDatabase.AssetPathToGUID(aPath); AddUseGUID(refGUID); } #endif DetailPrototype[] arr = terrain.detailPrototypes; for (var i = 0; i < arr.Length; i++) { string aPath = AssetDatabase.GetAssetPath(arr[i].prototypeTexture); string refGUID = AssetDatabase.AssetPathToGUID(aPath); AddUseGUID(refGUID); } TreePrototype[] arr2 = terrain.treePrototypes; for (var i = 0; i < arr2.Length; i++) { string aPath = AssetDatabase.GetAssetPath(arr2[i].prefab); string refGUID = AssetDatabase.AssetPathToGUID(aPath); AddUseGUID(refGUID); } FR2_Unity.TerrainTextureData[] arr3 = FR2_Unity.GetTerrainTextureDatas(terrain); for (var i = 0; i < arr3.Length; i++) { FR2_Unity.TerrainTextureData texs = arr3[i]; for (var k = 0; k < texs.textures.Length; k++) { Texture2D tex = texs.textures[k]; if (tex == null) { continue; } string aPath = AssetDatabase.GetAssetPath(tex); if (string.IsNullOrEmpty(aPath)) { continue; } string refGUID = AssetDatabase.AssetPathToGUID(aPath); if (string.IsNullOrEmpty(refGUID)) { continue; } AddUseGUID(refGUID); } } } private void ClearUseGUIDs() { #if FR2_DEBUG Debug.Log("ClearUseGUIDs: " + assetPath); #endif UseGUIDs.Clear(); UseGUIDsList.Clear(); } static int binaryLoaded; internal void LoadBinaryAsset() { ClearUseGUIDs(); UnityObject assetData = AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject)); if (assetData is GameObject) { type = FR2_AssetType.MODEL; LoadGameObject(assetData as GameObject); } else if (assetData is TerrainData) { type = FR2_AssetType.TERRAIN; LoadTerrainData(assetData as TerrainData); } else { LoadSerialized(assetData); } #if FR2_DEBUG Debug.Log("LoadBinaryAsset :: " + assetData + ":" + type); #endif assetData = null; if (binaryLoaded++ <= 30) return; binaryLoaded = 0; FR2_Unity.UnloadUnusedAssets(); } internal void LoadYAML() { if (!File.Exists(m_assetPath)) { state = FR2_AssetState.MISSING; return; } if (m_isAssetFile) { var s = AssetDatabase.LoadAssetAtPath(m_assetPath); if (s != null) { return; } } string text = string.Empty; try { text = File.ReadAllText(m_assetPath); } #if FR2_DEBUG catch (Exception e) { Debug.LogWarning("Guess Asset Type error :: " + e + "\n" + assetPath); #else catch { #endif state = FR2_AssetState.MISSING; return; } #if FR2_DEBUG Debug.Log("LoadYAML: " + assetPath); #endif //if(assetPath.Contains("Myriad Pro - Bold SDF")) //{ // Debug.Log("no ne"); //} // PERFORMANCE HOG! // var matches = Regex.Matches(text, @"\bguid: [a-f0-9]{32}\b"); MatchCollection matches = Regex.Matches(text, @".*guid: [a-f0-9]{32}.*\n"); foreach (Match match in matches) { Match guidMatch = Regex.Match(match.Value, @"\bguid: [a-f0-9]{32}\b"); string refGUID = guidMatch.Value.Replace("guid: ", string.Empty); Match fileIdMatch = Regex.Match(match.Value, @"\bfileID: ([0-9]*).*"); int id = -1; try { id = int.Parse(fileIdMatch.Groups[1].Value) / 100000; } catch { } AddUseGUID(refGUID, id); } //var idx = text.IndexOf("guid: "); //var counter=0; //while (idx != -1) //{ // var guid = text.Substring(idx + 6, 32); // if (UseGUIDs.Contains(guid)) continue; // AddUseGUID(guid); // idx += 39; // if (idx > text.Length-40) break; // //Debug.Log(assetName + ":" + guid); // idx = text.IndexOf("guid: ", idx + 39); // if (counter++ > 100) break; //} //if (counter > 100){ // Debug.LogWarning("Never finish on " + assetName); //} } internal void LoadYAML2() { if (!File.Exists(m_assetPath)) { state = FR2_AssetState.MISSING; return; } if (m_assetPath == "ProjectSettings/EditorBuildSettings.asset") { var listScenes = EditorBuildSettings.scenes; foreach (var scene in listScenes) { if (!scene.enabled) continue; var path = scene.path; var guid = AssetDatabase.AssetPathToGUID(path); AddUseGUID(guid, 0); #if FR2_DEBUG Debug.Log("AddScene: " + path); #endif } } // var text = string.Empty; try { using (var sr = new StreamReader(m_assetPath)) { while (sr.Peek() >= 0) { string line = sr.ReadLine(); int index = line.IndexOf("guid: "); if (index < 0) { continue; } string refGUID = line.Substring(index + 6, 32); int indexFileId = line.IndexOf("fileID: "); int fileID = -1; if (indexFileId >= 0) { indexFileId += 8; string fileIDStr = line.Substring(indexFileId, line.IndexOf(',', indexFileId) - indexFileId); try { fileID = int.Parse(fileIDStr) / 100000; } catch { } } AddUseGUID(refGUID, fileID); } } #if FR2_DEBUG if (UseGUIDsList.Count > 0) { Debug.Log(assetPath + ":" + UseGUIDsList.Count); } #endif } #if FR2_DEBUG catch (Exception e) { Debug.LogWarning("Guess Asset Type error :: " + e + "\n" + assetPath); #else catch { #endif state = FR2_AssetState.MISSING; } } internal void LoadFolder() { if (!Directory.Exists(m_assetPath)) { state = FR2_AssetState.MISSING; return; } // do not analyse folders outside project if (!m_assetPath.StartsWith("Assets/")) return; try { string[] files = Directory.GetFiles(m_assetPath); string[] dirs = Directory.GetDirectories(m_assetPath); foreach (string f in files) { if (f.EndsWith(".meta", StringComparison.Ordinal)) { continue; } string fguid = AssetDatabase.AssetPathToGUID(f); if (string.IsNullOrEmpty(fguid)) { continue; } // AddUseGUID(fguid, true); AddUseGUID(fguid); } foreach (string d in dirs) { string fguid = AssetDatabase.AssetPathToGUID(d); if (string.IsNullOrEmpty(fguid)) { continue; } // AddUseGUID(fguid, true); AddUseGUID(fguid); } } #if FR2_DEBUG catch (Exception e) { Debug.LogWarning("LoadFolder() error :: " + e + "\n" + assetPath); #else catch { #endif state = FR2_AssetState.MISSING; } //Debug.Log("Load Folder :: " + assetName + ":" + type + ":" + UseGUIDs.Count); } // ----------------------------- REPLACE GUIDS --------------------------------------- internal bool ReplaceReference(string fromGUID, string toGUID, TerrainData terrain = null) { if (IsMissing) { return false; } if (IsReferencable) { string text = string.Empty; if (!File.Exists(m_assetPath)) { state = FR2_AssetState.MISSING; return false; } try { text = File.ReadAllText(m_assetPath).Replace("\r", "\n"); File.WriteAllText(m_assetPath, text.Replace(fromGUID, toGUID)); // AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.Default); return true; } catch (Exception e) { state = FR2_AssetState.MISSING; //#if FR2_DEBUG Debug.LogWarning("Replace Reference error :: " + e + "\n" + m_assetPath); //#endif } return false; } if (type == FR2_AssetType.TERRAIN) { var fromObj = FR2_Unity.LoadAssetWithGUID(fromGUID); var toObj = FR2_Unity.LoadAssetWithGUID(toGUID); var found = 0; // var terrain = AssetDatabase.LoadAssetAtPath(assetPath, typeof(Object)) as TerrainData; if (fromObj is Texture2D) { DetailPrototype[] arr = terrain.detailPrototypes; for (var i = 0; i < arr.Length; i++) { if (arr[i].prototypeTexture == (Texture2D) fromObj) { found++; arr[i].prototypeTexture = (Texture2D) toObj; } } terrain.detailPrototypes = arr; FR2_Unity.ReplaceTerrainTextureDatas(terrain, (Texture2D) fromObj, (Texture2D) toObj); } if (fromObj is GameObject) { TreePrototype[] arr2 = terrain.treePrototypes; for (var i = 0; i < arr2.Length; i++) { if (arr2[i].prefab == (GameObject) fromObj) { found++; arr2[i].prefab = (GameObject) toObj; } } terrain.treePrototypes = arr2; } // EditorUtility.SetDirty(terrain); // AssetDatabase.SaveAssets(); fromObj = null; toObj = null; terrain = null; // FR2_Unity.UnloadUnusedAssets(); return found > 0; } Debug.LogWarning("Something wrong, should never be here - Ignored <" + m_assetPath + "> : not a readable type, can not replace ! " + type); return false; } internal bool ReplaceReference(string fromGUID, string toGUID, long toFileId, TerrainData terrain = null) { Debug.Log("ReplaceReference: from " + fromGUID + " to: " + toGUID + " toFileId: " + toFileId); if (IsMissing) { // Debug.Log("this asset is missing"); return false; } if (IsReferencable) { string text = string.Empty; if (!File.Exists(m_assetPath)) { state = FR2_AssetState.MISSING; // Debug.Log("this asset not exits"); return false; } try { var sb = new StringBuilder(); text = File.ReadAllText(assetPath).Replace("\r", "\n"); var lines = text.Split('\n'); //string result = ""; for(int i = 0; i < lines.Length; i++) { var line = lines[i]; if(line.IndexOf(fromGUID, StringComparison.Ordinal) >= 0) { if(toFileId > 0) { const string FileID = "fileID: "; var index = line.IndexOf(FileID, StringComparison.Ordinal); if(index >= 0) { var fromFileId = line.Substring(index + FileID.Length, line.IndexOf(',', index) - (index + FileID.Length)); long fileType = 0; if(!long.TryParse(fromFileId, out fileType)) { Debug.LogWarning("cannot parse file"); return false; } if (fileType.ToString().Substring(0,3) != toFileId.ToString().Substring(0,3)) { //difference file type Debug.LogWarning("Difference file type"); return false; } Debug.Log("ReplaceReference: fromFileId " + fromFileId + " to File Id " + toFileId); line = line.Replace(fromFileId, toFileId.ToString()); } } line = line.Replace(fromGUID, toGUID); } sb.Append(line); sb.AppendLine(); //result += line + "\n"; } //File.WriteAllText(assetPath, result.Trim()); File.WriteAllText(assetPath, sb.ToString()); //AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.Default); return true; } catch (Exception e) { state = FR2_AssetState.MISSING; //#if FR2_DEBUG Debug.LogWarning("Replace Reference error :: " + e + "\n" + m_assetPath); //#endif } return false; } if (type == FR2_AssetType.TERRAIN) { var fromObj = FR2_Unity.LoadAssetWithGUID(fromGUID); var toObj = FR2_Unity.LoadAssetWithGUID(toGUID); var found = 0; // var terrain = AssetDatabase.LoadAssetAtPath(assetPath, typeof(Object)) as TerrainData; if (fromObj is Texture2D) { DetailPrototype[] arr = terrain.detailPrototypes; for (var i = 0; i < arr.Length; i++) { if (arr[i].prototypeTexture == (Texture2D)fromObj) { found++; arr[i].prototypeTexture = (Texture2D)toObj; } } terrain.detailPrototypes = arr; FR2_Unity.ReplaceTerrainTextureDatas(terrain, (Texture2D)fromObj, (Texture2D)toObj); } if (fromObj is GameObject) { TreePrototype[] arr2 = terrain.treePrototypes; for (var i = 0; i < arr2.Length; i++) { if (arr2[i].prefab == (GameObject)fromObj) { found++; arr2[i].prefab = (GameObject)toObj; } } terrain.treePrototypes = arr2; } // EditorUtility.SetDirty(terrain); // AssetDatabase.SaveAssets(); fromObj = null; toObj = null; terrain = null; // FR2_Unity.UnloadUnusedAssets(); return found > 0; } Debug.LogWarning("Something wrong, should never be here - Ignored <" + m_assetPath + "> : not a readable type, can not replace ! " + type); return false; } [Serializable] private class Classes { public string guid; public List ids; } } }