From aa68ee6f2092b691ea3e6c8c6fcf6cae3c2ab745 Mon Sep 17 00:00:00 2001 From: David Briscoe Date: Mon, 28 Dec 2020 17:09:48 -0800 Subject: [PATCH 1/4] Don't assume install directory Use CallerFilePath to fetch the install directory for the ignore file. --- FindReferencesInProject2.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/FindReferencesInProject2.cs b/FindReferencesInProject2.cs index df5e5a3..ae4aeb2 100644 --- a/FindReferencesInProject2.cs +++ b/FindReferencesInProject2.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Runtime.CompilerServices; using System.Threading; using UnityEditor; using UnityEngine; @@ -11,9 +12,18 @@ public static class FindReferencesInProject2 private const string MenuItemName = "Assets/Find References In Project %#&f"; private const string MetaExtension = ".meta"; + private static string InstallDirectory = "Assets/Editor/FindReferencesInProject2"; + + private static void UpdateInstallDirectory([CallerFilePath] string executingFilePath = "") + { + InstallDirectory = Path.GetDirectoryName(executingFilePath); + } + [MenuItem(MenuItemName, false, 25)] public static void Find() { + UpdateInstallDirectory(); + bool isMacOS = Application.platform == RuntimePlatform.OSXEditor; int totalWaitMilliseconds = isMacOS ? 2 * 1000 : 300 * 1000; int cpuCount = Environment.ProcessorCount; @@ -40,11 +50,12 @@ public static void Find() } else { + var ignore_file = Path.Combine(InstallDirectory, "ignore.txt"); psi.FileName = Path.Combine(Environment.CurrentDirectory, @"Tools\FindReferencesInProject2\rg.exe"); psi.Arguments = string.Format("--case-sensitive --follow --files-with-matches --no-text --fixed-strings " + - "--ignore-file Assets/Editor/FindReferencesInProject2/ignore.txt " + + "--ignore-file {3} " + "--threads {0} --regexp {1} -- {2}", - cpuCount, selectedAssetGUID, appDataPath); + cpuCount, selectedAssetGUID, appDataPath, ignore_file); } psi.UseShellExecute = false; From 329d0a64e0b7d81e21f5c71577257f3453739c4f Mon Sep 17 00:00:00 2001 From: David Briscoe Date: Mon, 28 Dec 2020 17:11:52 -0800 Subject: [PATCH 2/4] Allow rg to be in the PATH If rg isn't in the assumed location, assume it's in the PATH. Everything should continue working as before, but people who have it in their PATH don't need to install it in each of their Unity projects. Add instructions when ripgrep cannot be found. --- FindReferencesInProject2.cs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/FindReferencesInProject2.cs b/FindReferencesInProject2.cs index ae4aeb2..61e0cda 100644 --- a/FindReferencesInProject2.cs +++ b/FindReferencesInProject2.cs @@ -51,7 +51,13 @@ public static void Find() else { var ignore_file = Path.Combine(InstallDirectory, "ignore.txt"); - psi.FileName = Path.Combine(Environment.CurrentDirectory, @"Tools\FindReferencesInProject2\rg.exe"); + var filepath = Path.Combine(Environment.CurrentDirectory, @"Tools\FindReferencesInProject2\rg.exe"); + if (!File.Exists(filepath)) + { + // Assume it's in our path. + filepath = "rg.exe"; + } + psi.FileName = filepath; psi.Arguments = string.Format("--case-sensitive --follow --files-with-matches --no-text --fixed-strings " + "--ignore-file {3} " + "--threads {0} --regexp {1} -- {2}", @@ -87,7 +93,19 @@ public static void Find() output.AppendLine("Error: " + e.Data); }; - process.Start(); + try + { + process.Start(); + } + catch (SystemException) + { + if (!isMacOS) + { + var destination = Path.Combine(Environment.CurrentDirectory, @"Tools\FindReferencesInProject2"); + UnityEngine.Debug.LogError($"Couldn't find ripgrep. Download ripgrep from https://github.com/BurntSushi/ripgrep/releases/latest and extract rg.exe to {destination} or add it to your PATH."); + } + throw; + } process.BeginOutputReadLine(); process.BeginErrorReadLine(); From d50d548061b9ec34ed25ff826434a00c1a8c785e Mon Sep 17 00:00:00 2001 From: David Briscoe Date: Fri, 29 Jan 2021 22:18:52 -0800 Subject: [PATCH 3/4] Remove snapshot image from repository --- README.md | 2 +- Snapshot.png | Bin 25262 -> 0 bytes 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 Snapshot.png diff --git a/README.md b/README.md index 9b1fca3..d14ac52 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Find asset references super fast in Unity project. Both on macOS and Windows. -![Snapshot](Snapshot.png) +![Snapshot](https://user-images.githubusercontent.com/43559/106349160-9af4c300-6280-11eb-88e9-23db004026f6.png) ## Usage diff --git a/Snapshot.png b/Snapshot.png deleted file mode 100644 index 9bb5d88754df2d9502e167a716ae6c3fa09cd33c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25262 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 Olmps_v>s?!`TYx4pU<)Y From ac4f14a522c69281c4bfee6a8eb95b287e7a4124 Mon Sep 17 00:00:00 2001 From: David Briscoe Date: Fri, 29 Jan 2021 22:19:14 -0800 Subject: [PATCH 4/4] Make into a package Packages are easier to install than raw scripts. Just add to your manifest and you're off! Move code into a folder and add an asmdef. Add metas (and remove meta from gitignore). --- .gitignore | 1 - Editor.meta | 8 + .../FindReferencesInProject2.cs | 344 +++++++++--------- Editor/FindReferencesInProject2.cs.meta | 11 + Editor/findrefs.Editor.asmdef | 10 + Editor/findrefs.Editor.asmdef.meta | 7 + ignore.txt => Editor/ignore.txt | 144 ++++---- Editor/ignore.txt.meta | 7 + LICENSE.meta | 7 + README.md | 24 +- README.md.meta | 7 + package.json | 12 + package.json.meta | 7 + 13 files changed, 339 insertions(+), 250 deletions(-) create mode 100644 Editor.meta rename FindReferencesInProject2.cs => Editor/FindReferencesInProject2.cs (97%) create mode 100644 Editor/FindReferencesInProject2.cs.meta create mode 100644 Editor/findrefs.Editor.asmdef create mode 100644 Editor/findrefs.Editor.asmdef.meta rename ignore.txt => Editor/ignore.txt (88%) create mode 100644 Editor/ignore.txt.meta create mode 100644 LICENSE.meta create mode 100644 README.md.meta create mode 100644 package.json create mode 100644 package.json.meta diff --git a/.gitignore b/.gitignore index 70aa86c..e69de29 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +0,0 @@ -*.meta diff --git a/Editor.meta b/Editor.meta new file mode 100644 index 0000000..bb5b1d7 --- /dev/null +++ b/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b9b0b14c91b041c4da81d8752603d9d0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FindReferencesInProject2.cs b/Editor/FindReferencesInProject2.cs similarity index 97% rename from FindReferencesInProject2.cs rename to Editor/FindReferencesInProject2.cs index 61e0cda..94f8597 100644 --- a/FindReferencesInProject2.cs +++ b/Editor/FindReferencesInProject2.cs @@ -1,172 +1,172 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Runtime.CompilerServices; -using System.Threading; -using UnityEditor; -using UnityEngine; - -public static class FindReferencesInProject2 -{ - private const string MenuItemName = "Assets/Find References In Project %#&f"; - private const string MetaExtension = ".meta"; - - private static string InstallDirectory = "Assets/Editor/FindReferencesInProject2"; - - private static void UpdateInstallDirectory([CallerFilePath] string executingFilePath = "") - { - InstallDirectory = Path.GetDirectoryName(executingFilePath); - } - - [MenuItem(MenuItemName, false, 25)] - public static void Find() - { - UpdateInstallDirectory(); - - bool isMacOS = Application.platform == RuntimePlatform.OSXEditor; - int totalWaitMilliseconds = isMacOS ? 2 * 1000 : 300 * 1000; - int cpuCount = Environment.ProcessorCount; - string appDataPath = Application.dataPath; - - var selectedObject = Selection.activeObject; - string selectedAssetPath = AssetDatabase.GetAssetPath(selectedObject); - string selectedAssetGUID = AssetDatabase.AssetPathToGUID(selectedAssetPath); - string selectedAssetMetaPath = selectedAssetPath + MetaExtension; - - var references = new List(); - var output = new System.Text.StringBuilder(); - - var stopwatch = new Stopwatch(); - stopwatch.Start(); - - var psi = new ProcessStartInfo(); - psi.WindowStyle = ProcessWindowStyle.Minimized; - - if (isMacOS) - { - psi.FileName = "/usr/bin/mdfind"; - psi.Arguments = string.Format("-onlyin {0} {1}", appDataPath, selectedAssetGUID); - } - else - { - var ignore_file = Path.Combine(InstallDirectory, "ignore.txt"); - var filepath = Path.Combine(Environment.CurrentDirectory, @"Tools\FindReferencesInProject2\rg.exe"); - if (!File.Exists(filepath)) - { - // Assume it's in our path. - filepath = "rg.exe"; - } - psi.FileName = filepath; - psi.Arguments = string.Format("--case-sensitive --follow --files-with-matches --no-text --fixed-strings " + - "--ignore-file {3} " + - "--threads {0} --regexp {1} -- {2}", - cpuCount, selectedAssetGUID, appDataPath, ignore_file); - } - - psi.UseShellExecute = false; - psi.RedirectStandardOutput = true; - psi.RedirectStandardError = true; - - var process = new Process(); - process.StartInfo = psi; - - process.OutputDataReceived += (sender, e) => - { - if (string.IsNullOrEmpty(e.Data)) - return; - - string relativePath = e.Data.Replace(appDataPath, "Assets").Replace("\\", "/"); - - // skip the meta file of whatever we have selected - if (relativePath == selectedAssetMetaPath) - return; - - references.Add(relativePath); - }; - - process.ErrorDataReceived += (sender, e) => - { - if (string.IsNullOrEmpty(e.Data)) - return; - - output.AppendLine("Error: " + e.Data); - }; - - try - { - process.Start(); - } - catch (SystemException) - { - if (!isMacOS) - { - var destination = Path.Combine(Environment.CurrentDirectory, @"Tools\FindReferencesInProject2"); - UnityEngine.Debug.LogError($"Couldn't find ripgrep. Download ripgrep from https://github.com/BurntSushi/ripgrep/releases/latest and extract rg.exe to {destination} or add it to your PATH."); - } - throw; - } - process.BeginOutputReadLine(); - process.BeginErrorReadLine(); - - while (!process.HasExited) - { - if (stopwatch.ElapsedMilliseconds < totalWaitMilliseconds) - { - float progress = (float)((double)stopwatch.ElapsedMilliseconds / totalWaitMilliseconds); - string info = string.Format("Finding {0}/{1}s {2:P2}", stopwatch.ElapsedMilliseconds / 1000, - totalWaitMilliseconds / 1000, progress); - bool canceled = EditorUtility.DisplayCancelableProgressBar("Find References in Project", info, progress); - - if (canceled) - { - process.Kill(); - break; - } - - Thread.Sleep(100); - } - else - { - process.Kill(); - break; - } - } - - foreach (string file in references) - { - string guid = AssetDatabase.AssetPathToGUID(file); - output.AppendLine(string.Format("{0} {1}", guid, file)); - - string assetPath = file; - if (file.EndsWith(MetaExtension)) - { - assetPath = file.Substring(0, file.Length - MetaExtension.Length); - } - - UnityEngine.Debug.Log(string.Format("{0}\n{1}", file, guid), AssetDatabase.LoadMainAssetAtPath(assetPath)); - } - - EditorUtility.ClearProgressBar(); - stopwatch.Stop(); - - string content = string.Format( - "{0} {1} found for object: \"{2}\" path: \"{3}\" guid: \"{4}\" total time: {5}s\n\n{6}", - references.Count, references.Count > 2 ? "references" : "reference", selectedObject.name, selectedAssetPath, - selectedAssetGUID, stopwatch.ElapsedMilliseconds / 1000d, output); - UnityEngine.Debug.LogWarning(content, selectedObject); - } - - [MenuItem(MenuItemName, true)] - private static bool FindValidate() - { - var obj = Selection.activeObject; - if (obj != null && AssetDatabase.Contains(obj)) - { - string path = AssetDatabase.GetAssetPath(obj); - return !AssetDatabase.IsValidFolder(path); - } - - return false; - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; +using System.Threading; +using UnityEditor; +using UnityEngine; + +public static class FindReferencesInProject2 +{ + private const string MenuItemName = "Assets/Find References In Project %#&f"; + private const string MetaExtension = ".meta"; + + private static string InstallDirectory = "Assets/Editor/FindReferencesInProject2"; + + private static void UpdateInstallDirectory([CallerFilePath] string executingFilePath = "") + { + InstallDirectory = Path.GetDirectoryName(executingFilePath); + } + + [MenuItem(MenuItemName, false, 25)] + public static void Find() + { + UpdateInstallDirectory(); + + bool isMacOS = Application.platform == RuntimePlatform.OSXEditor; + int totalWaitMilliseconds = isMacOS ? 2 * 1000 : 300 * 1000; + int cpuCount = Environment.ProcessorCount; + string appDataPath = Application.dataPath; + + var selectedObject = Selection.activeObject; + string selectedAssetPath = AssetDatabase.GetAssetPath(selectedObject); + string selectedAssetGUID = AssetDatabase.AssetPathToGUID(selectedAssetPath); + string selectedAssetMetaPath = selectedAssetPath + MetaExtension; + + var references = new List(); + var output = new System.Text.StringBuilder(); + + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + var psi = new ProcessStartInfo(); + psi.WindowStyle = ProcessWindowStyle.Minimized; + + if (isMacOS) + { + psi.FileName = "/usr/bin/mdfind"; + psi.Arguments = string.Format("-onlyin {0} {1}", appDataPath, selectedAssetGUID); + } + else + { + var ignore_file = Path.Combine(InstallDirectory, "ignore.txt"); + var filepath = Path.Combine(Environment.CurrentDirectory, @"Tools\FindReferencesInProject2\rg.exe"); + if (!File.Exists(filepath)) + { + // Assume it's in our path. + filepath = "rg.exe"; + } + psi.FileName = filepath; + psi.Arguments = string.Format("--case-sensitive --follow --files-with-matches --no-text --fixed-strings " + + "--ignore-file {3} " + + "--threads {0} --regexp {1} -- {2}", + cpuCount, selectedAssetGUID, appDataPath, ignore_file); + } + + psi.UseShellExecute = false; + psi.RedirectStandardOutput = true; + psi.RedirectStandardError = true; + + var process = new Process(); + process.StartInfo = psi; + + process.OutputDataReceived += (sender, e) => + { + if (string.IsNullOrEmpty(e.Data)) + return; + + string relativePath = e.Data.Replace(appDataPath, "Assets").Replace("\\", "/"); + + // skip the meta file of whatever we have selected + if (relativePath == selectedAssetMetaPath) + return; + + references.Add(relativePath); + }; + + process.ErrorDataReceived += (sender, e) => + { + if (string.IsNullOrEmpty(e.Data)) + return; + + output.AppendLine("Error: " + e.Data); + }; + + try + { + process.Start(); + } + catch (SystemException) + { + if (!isMacOS) + { + var destination = Path.Combine(Environment.CurrentDirectory, @"Tools\FindReferencesInProject2"); + UnityEngine.Debug.LogError($"Couldn't find ripgrep. Download ripgrep from https://github.com/BurntSushi/ripgrep/releases/latest and extract rg.exe to {destination} or add it to your PATH."); + } + throw; + } + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + while (!process.HasExited) + { + if (stopwatch.ElapsedMilliseconds < totalWaitMilliseconds) + { + float progress = (float)((double)stopwatch.ElapsedMilliseconds / totalWaitMilliseconds); + string info = string.Format("Finding {0}/{1}s {2:P2}", stopwatch.ElapsedMilliseconds / 1000, + totalWaitMilliseconds / 1000, progress); + bool canceled = EditorUtility.DisplayCancelableProgressBar("Find References in Project", info, progress); + + if (canceled) + { + process.Kill(); + break; + } + + Thread.Sleep(100); + } + else + { + process.Kill(); + break; + } + } + + foreach (string file in references) + { + string guid = AssetDatabase.AssetPathToGUID(file); + output.AppendLine(string.Format("{0} {1}", guid, file)); + + string assetPath = file; + if (file.EndsWith(MetaExtension)) + { + assetPath = file.Substring(0, file.Length - MetaExtension.Length); + } + + UnityEngine.Debug.Log(string.Format("{0}\n{1}", file, guid), AssetDatabase.LoadMainAssetAtPath(assetPath)); + } + + EditorUtility.ClearProgressBar(); + stopwatch.Stop(); + + string content = string.Format( + "{0} {1} found for object: \"{2}\" path: \"{3}\" guid: \"{4}\" total time: {5}s\n\n{6}", + references.Count, references.Count > 2 ? "references" : "reference", selectedObject.name, selectedAssetPath, + selectedAssetGUID, stopwatch.ElapsedMilliseconds / 1000d, output); + UnityEngine.Debug.LogWarning(content, selectedObject); + } + + [MenuItem(MenuItemName, true)] + private static bool FindValidate() + { + var obj = Selection.activeObject; + if (obj != null && AssetDatabase.Contains(obj)) + { + string path = AssetDatabase.GetAssetPath(obj); + return !AssetDatabase.IsValidFolder(path); + } + + return false; + } +} diff --git a/Editor/FindReferencesInProject2.cs.meta b/Editor/FindReferencesInProject2.cs.meta new file mode 100644 index 0000000..439beff --- /dev/null +++ b/Editor/FindReferencesInProject2.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 28b93a2d809b7f0439ed1828f60ab705 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/findrefs.Editor.asmdef b/Editor/findrefs.Editor.asmdef new file mode 100644 index 0000000..612681d --- /dev/null +++ b/Editor/findrefs.Editor.asmdef @@ -0,0 +1,10 @@ +{ + "name": "findrefs.Editor", + "references": [ + ], + "optionalUnityReferences": [ + ], + "includePlatforms": [ + "Editor" + ] +} diff --git a/Editor/findrefs.Editor.asmdef.meta b/Editor/findrefs.Editor.asmdef.meta new file mode 100644 index 0000000..dcaa3ce --- /dev/null +++ b/Editor/findrefs.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: aad0dfb391736c1419e6998db4554f01 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ignore.txt b/Editor/ignore.txt similarity index 88% rename from ignore.txt rename to Editor/ignore.txt index 4b3c8dd..9079e55 100644 --- a/ignore.txt +++ b/Editor/ignore.txt @@ -1,72 +1,72 @@ -# binary files -*.FBX -*.TGA -*.a -*.aar -*.ab -*.bmp -*.bundle -*.bytes -*.chm -*.chw -*.cubemap -*.dds -*.dll -*.exe -*.fbx -*.gif -*.jpg -*.mdb -*.mel -*.mp3 -*.otf -*.pdf -*.png -*.psd -*.swatch -*.tga -*.tif -*.ttf -*.unitypackage -*.wav -*.xlsx -*.zip - -# scripts -*.cs -*.h -*.m -*.mm - -# miscellaneous -*.cginc -*.xml -*.txt -*.swatch -*.md -*.json -*.mdb -*.bat -*.sh -*.jar -*.keystore -*.url -*.html -*.md5 -*.plist -*.modulemap -*.entitlements -*.framework -*.properties -*.XML -*.shader -*.compute - -# all meta except which contains GUID -*.meta - -!*.FBX.meta -!*.fbx.meta -!*.otf.meta -!*.shader.meta -!*.ttf.meta +# binary files +*.FBX +*.TGA +*.a +*.aar +*.ab +*.bmp +*.bundle +*.bytes +*.chm +*.chw +*.cubemap +*.dds +*.dll +*.exe +*.fbx +*.gif +*.jpg +*.mdb +*.mel +*.mp3 +*.otf +*.pdf +*.png +*.psd +*.swatch +*.tga +*.tif +*.ttf +*.unitypackage +*.wav +*.xlsx +*.zip + +# scripts +*.cs +*.h +*.m +*.mm + +# miscellaneous +*.cginc +*.xml +*.txt +*.swatch +*.md +*.json +*.mdb +*.bat +*.sh +*.jar +*.keystore +*.url +*.html +*.md5 +*.plist +*.modulemap +*.entitlements +*.framework +*.properties +*.XML +*.shader +*.compute + +# all meta except which contains GUID +*.meta + +!*.FBX.meta +!*.fbx.meta +!*.otf.meta +!*.shader.meta +!*.ttf.meta diff --git a/Editor/ignore.txt.meta b/Editor/ignore.txt.meta new file mode 100644 index 0000000..4cf1dc8 --- /dev/null +++ b/Editor/ignore.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b5449731d8719ce459839efa75103af3 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/LICENSE.meta b/LICENSE.meta new file mode 100644 index 0000000..69103dc --- /dev/null +++ b/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b6d9371dcdcc09f448196d6ff28c312c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md b/README.md index d14ac52..d2f146d 100644 --- a/README.md +++ b/README.md @@ -30,17 +30,31 @@ So it would takes about 5 seconds to search ~700M and ~7000 files on SSD. ## Install -### macOS +Add this line to your Packages/manifest.json: + + "com.github.idbrii.unity-findrefs": "https://github.com/idbrii/unity-findrefs.git#latest-release", -1. Clone repository into `Assets/Editor` directory. +### macOS Job done! It just uses the `mdfind` built in macOS and has no other dependencies. ### Windows -1. Clone repository into `Assets/Editor` directory. -2. Download `ripgrep` from [Latest release · BurntSushi/ripgrep](https://github.com/BurntSushi/ripgrep/releases/latest) and extract `rg.exe` to `Tools\FindReferencesInProject2` directory. -3. Click `Unlock file` in `rg.exe` Properties, or you will find it takes too long time to start first time. +#### Scoop + +If you're using [scoop](https://scoop.sh/), install ripgrep: + +``` +scoop install ripgrep +``` + +rg.exe is now in your PATH and usable by unity-findrefs. + + +#### Manual + +1. Download `ripgrep` from [Latest release · BurntSushi/ripgrep](https://github.com/BurntSushi/ripgrep/releases/latest) and extract `rg.exe` to `Tools\FindReferencesInProject2` directory. +2. Click `Unlock file` in `rg.exe` Properties, or you will find it takes too long time to start first time. Note: It seems that `x86_64-pc-windows-msvc` has a smaller size in `ripgrep` release page. diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 0000000..1c1b6aa --- /dev/null +++ b/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c03ec6755814d544d873d404ad3afec4 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json new file mode 100644 index 0000000..b034a6a --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "com.github.idbrii.unity-findrefs", + "displayName": "findrefs", + "version": "2.0.0", + "unity": "2019.4", + "description": "Find references in your project", + "keywords": [ "editor", "reference", "search" ], + "category": "productivity", + "dependencies": {}, + "samples": [ + ] +} diff --git a/package.json.meta b/package.json.meta new file mode 100644 index 0000000..bd3cc49 --- /dev/null +++ b/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6fa60b0e4252a1d41ba841d6f0f1d0d0 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: