A game about forced loneliness, made by TACStudios
1#if UNITY_EDITOR
2using System;
3using System.Diagnostics.CodeAnalysis;
4using System.IO;
5using System.Reflection;
6using UnityEditor;
7
8namespace UnityEngine.InputSystem.Editor
9{
10 internal static class EditorHelpers
11 {
12 // Provides an abstraction layer on top of EditorGUIUtility to allow replacing the underlying buffer.
13 public static Action<string> SetSystemCopyBufferContents = s => EditorGUIUtility.systemCopyBuffer = s;
14
15 // Provides an abstraction layer on top of EditorGUIUtility to allow replacing the underlying buffer.
16 public static Func<string> GetSystemCopyBufferContents = () => EditorGUIUtility.systemCopyBuffer;
17
18 // Attempts to retrieve the asset GUID associated with the given asset. If asset is null or the asset
19 // is not associated with a GUID or the operation fails for any other reason the return value will be null.
20 public static string GetAssetGUID(Object asset)
21 {
22 return !AssetDatabase.TryGetGUIDAndLocalFileIdentifier(asset, out var assetGuid, out long _)
23 ? null : assetGuid;
24 }
25
26 // SerializedProperty.tooltip *should* give us the tooltip as per [Tooltip] attribute. Alas, for some
27 // reason, it's not happening.
28 public static string GetTooltip(this SerializedProperty property)
29 {
30 if (!string.IsNullOrEmpty(property.tooltip))
31 return property.tooltip;
32
33 var field = property.GetField();
34 if (field != null)
35 {
36 var tooltipAttribute = field.GetCustomAttribute<TooltipAttribute>();
37 if (tooltipAttribute != null)
38 return tooltipAttribute.tooltip;
39 }
40
41 return string.Empty;
42 }
43
44 public static string GetHyperlink(string text, string path)
45 {
46 return "<a href=\"" + path + $"\">{text}</a>";
47 }
48
49 public static string GetHyperlink(string path)
50 {
51 return GetHyperlink(path, path);
52 }
53
54 public static void RestartEditorAndRecompileScripts(bool dryRun = false)
55 {
56 // The API here are not public. Use reflection to get to them.
57 var editorApplicationType = typeof(EditorApplication);
58 var restartEditorAndRecompileScripts =
59 editorApplicationType.GetMethod("RestartEditorAndRecompileScripts",
60 BindingFlags.NonPublic | BindingFlags.Static);
61 if (!dryRun)
62 restartEditorAndRecompileScripts.Invoke(null, null);
63 else if (restartEditorAndRecompileScripts == null)
64 throw new MissingMethodException(editorApplicationType.FullName, "RestartEditorAndRecompileScripts");
65 }
66
67 // Attempts to make an asset editable in the underlying version control system and returns true if successful.
68 public static bool CheckOut(string path)
69 {
70 if (string.IsNullOrEmpty(path))
71 throw new ArgumentNullException(nameof(path));
72
73 // Make path relative to project folder.
74 var projectPath = Application.dataPath;
75 if (path.StartsWith(projectPath) && path.Length > projectPath.Length &&
76 (path[projectPath.Length] == '/' || path[projectPath.Length] == '\\'))
77 path = path.Substring(0, projectPath.Length + 1);
78
79 return AssetDatabase.MakeEditable(path);
80 }
81
82 /// <summary>
83 /// Attempts to checkout an asset for editing at the given path and overwrite its file content with
84 /// the given asset text content.
85 /// </summary>
86 /// <param name="assetPath">Path to asset to be checkout out and overwritten.</param>
87 /// <param name="text">The new file content.</param>
88 /// <returns>true if the file was successfully checkout for editing and the file was written.
89 /// This function may return false if unable to checkout the file for editing in the underlying
90 /// version control system.</returns>
91 internal static bool WriteAsset(string assetPath, string text)
92 {
93 // Attempt to checkout the file path for editing and inform the user if this fails.
94 if (!CheckOut(assetPath))
95 return false;
96
97 // (Over)write file text content.
98 File.WriteAllText(GetPhysicalPath(assetPath), text);
99
100 // Reimport the asset (indirectly triggers ADB notification callbacks)
101 AssetDatabase.ImportAsset(assetPath);
102
103 return true;
104 }
105
106 /// <summary>
107 /// Saves an asset to the given <c>assetPath</c> with file content corresponding to <c>text</c>
108 /// if the current content of the asset given by <c>assetPath</c> is different or the asset do not exist.
109 /// </summary>
110 /// <param name="assetPath">Destination asset path.</param>
111 /// <param name="text">The new desired text content to be written to the asset.</param>
112 /// <returns><c>true</c> if the asset was successfully modified or created, else <c>false</c>.</returns>
113 internal static bool SaveAsset(string assetPath, string text)
114 {
115 var existingJson = File.Exists(assetPath) ? File.ReadAllText(assetPath) : string.Empty;
116
117 // Return immediately if file content has not changed, i.e. touching the file would not yield a difference.
118 if (text == existingJson)
119 return false;
120
121 // Attempt to write asset to disc (including checkout the file) and inform the user if this fails.
122 if (WriteAsset(assetPath, text))
123 return true;
124
125 Debug.LogError($"Unable save asset to \"{assetPath}\" since the asset-path could not be checked-out as editable in the underlying version-control system.");
126 return false;
127 }
128
129 // Maps path into a physical path.
130 public static string GetPhysicalPath(string path)
131 {
132 // Note that we can only get physical path for 2021.2 or newer
133#if UNITY_2021_2_OR_NEWER
134 return FileUtil.GetPhysicalPath(path);
135#else
136 return path;
137#endif
138 }
139 }
140}
141#endif // UNITY_EDITOR