A game about forced loneliness, made by TACStudios
1#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
2
3using System;
4using System.Collections.Generic;
5using System.IO;
6using System.Linq;
7using UnityEditor;
8using UnityEngine.InputSystem.Utilities;
9
10namespace UnityEngine.InputSystem.Editor
11{
12 internal static class ProjectWideActionsAsset
13 {
14 private const string kDefaultAssetName = "InputSystem_Actions";
15 private const string kDefaultAssetPath = "Assets/" + kDefaultAssetName + ".inputactions";
16 private const string kDefaultTemplateAssetPath = "Packages/com.unity.inputsystem/InputSystem/Editor/ProjectWideActions/ProjectWideActionsTemplate.json";
17
18 internal static class ProjectSettingsProjectWideActionsAssetConverter
19 {
20 class ProjectSettingsPostprocessor : AssetPostprocessor
21 {
22#if UNITY_2021_2_OR_NEWER
23 private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths, bool didDomainReload)
24#else
25 private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
26#endif
27 {
28 if (!Application.isPlaying)
29 {
30 // If the Library folder is deleted, InputSystem will fail to retrieve the assigned Project-wide Asset because this look-up occurs
31 // during initialization while the Library is being rebuilt. So, afterwards perform another check and assign PWA asset if needed.
32 var pwaAsset = ProjectWideActionsBuildProvider.actionsToIncludeInPlayerBuild;
33 if (InputSystem.actions == null && pwaAsset != null)
34 InputSystem.actions = pwaAsset;
35 }
36 }
37 }
38 }
39
40 // Returns the default asset path for where to create project-wide actions asset.
41 internal static string defaultAssetPath => kDefaultAssetPath;
42
43 // Returns the default template JSON content.
44 internal static string GetDefaultAssetJson()
45 {
46 return File.ReadAllText(EditorHelpers.GetPhysicalPath(kDefaultTemplateAssetPath));
47 }
48
49 // Creates an asset at the given path containing the default template JSON.
50 internal static InputActionAsset CreateDefaultAssetAtPath(string assetPath = kDefaultAssetPath)
51 {
52 return CreateAssetAtPathFromJson(assetPath, File.ReadAllText(EditorHelpers.GetPhysicalPath(kDefaultTemplateAssetPath)));
53 }
54
55 // These may be moved out to internal types if decided to extend validation at a later point.
56
57 /// <summary>
58 /// Interface for reporting asset verification errors.
59 /// </summary>
60 internal interface IReportInputActionAssetVerificationErrors
61 {
62 /// <summary>
63 /// Reports a failure to comply to requirements with a message meaningful to the user.
64 /// </summary>
65 /// <param name="message">User-friendly error message.</param>
66 void Report(string message);
67 }
68
69 /// <summary>
70 /// Interface for asset verification.
71 /// </summary>
72 internal interface IInputActionAssetVerifier
73 {
74 /// <summary>
75 /// Verifies the given asset.
76 /// </summary>
77 /// <param name="asset">The asset to be verified</param>
78 /// <param name="reporter">The reporter to be used to report failure to meet requirements.</param>
79 public void Verify(InputActionAsset asset, IReportInputActionAssetVerificationErrors reporter);
80 }
81
82 /// <summary>
83 /// Verifier managing verification and reporting of asset compliance with external requirements.
84 /// </summary>
85 class Verifier : IReportInputActionAssetVerificationErrors
86 {
87 private readonly IReportInputActionAssetVerificationErrors m_Reporter;
88
89 // Default verification error reporter which generates feedback as debug warnings.
90 private class DefaultInputActionAssetVerificationReporter : IReportInputActionAssetVerificationErrors
91 {
92 public void Report(string message)
93 {
94 Debug.LogWarning(message);
95 }
96 }
97
98 /// <summary>
99 /// Constructs a an instance associated with the given reporter.
100 /// </summary>
101 /// <param name="reporter">The associated reporter instance. If null, a default reporter will be constructed.</param>
102 public Verifier(IReportInputActionAssetVerificationErrors reporter = null)
103 {
104 m_Reporter = reporter ?? new DefaultInputActionAssetVerificationReporter();
105 errors = 0;
106 }
107
108 #region IReportInputActionAssetVerificationErrors interface
109
110 /// <inheritdoc cref="IReportInputActionAssetVerificationErrors"/>
111 public void Report(string message)
112 {
113 ++errors;
114
115 try
116 {
117 m_Reporter.Report(message);
118 }
119 catch (Exception e)
120 {
121 // Only log unexpected but non-fatal exception
122 Debug.LogException(e);
123 }
124 }
125
126 #endregion
127
128 /// <summary>
129 /// Returns the total number of errors seen in verification (accumulative).
130 /// </summary>
131 public int errors { get; private set; }
132
133 /// <summary>
134 /// Returns <c>true</c> if the number of reported errors in verification is zero, else <c>false</c>.
135 /// </summary>
136 public bool isValid => errors == 0;
137
138 private static List<Func<IInputActionAssetVerifier>> s_VerifierFactories;
139
140 /// <summary>
141 /// Registers a factory instance.
142 /// </summary>
143 /// <param name="factory">The factory instance.</param>
144 /// <returns>true if successfully added, <c>false</c> if the factory have already been registered.</returns>
145 public static bool RegisterFactory(Func<IInputActionAssetVerifier> factory)
146 {
147 if (s_VerifierFactories == null)
148 s_VerifierFactories = new List<Func<IInputActionAssetVerifier>>(1);
149 if (s_VerifierFactories.Contains(factory))
150 return false;
151 s_VerifierFactories.Add(factory);
152 return true;
153 }
154
155 /// <summary>
156 /// Unregisters a factory instance that has previously been registered.
157 /// </summary>
158 /// <param name="factory">The factory instance to be removed.</param>
159 /// <returns>true if successfully unregistered, <c>false</c> if the given factory instance could not be found.</returns>
160 public static bool UnregisterFactory(Func<IInputActionAssetVerifier> factory)
161 {
162 return s_VerifierFactories.Remove(factory);
163 }
164
165 /// <summary>
166 /// Verifies the given project-wide input action asset using all registered verifiers.
167 /// </summary>
168 /// <param name="asset">The asset to be verified.</param>
169 /// <returns><c>true</c> if no verification errors occurred, else <c>false</c>.</returns>
170 /// <remarks>
171 /// Throws <c>System.ArgumentNullException</c> if <c>asset</c> is <c>null</c>.
172 ///
173 /// If any registered factory and/or verifier instance throws an exception this will be evaluated
174 /// as a verification error since the execution of the verifier could not continue. However, any
175 /// exceptions thrown will be caught and logged but not stop execution of the calling thread.
176 /// </remarks>
177 bool Verify(InputActionAsset asset)
178 {
179 if (asset == null)
180 throw new ArgumentNullException(nameof(asset));
181
182 if (s_VerifierFactories == null || s_VerifierFactories.Count == 0)
183 return true;
184
185 var instance = new Verifier(m_Reporter);
186 foreach (var factory in s_VerifierFactories)
187 {
188 try
189 {
190 factory.Invoke().Verify(asset, instance);
191 }
192 catch (Exception e)
193 {
194 // Only log unexpected but non-fatal exception and count to fail verification
195 ++errors;
196 Debug.LogException(e);
197 }
198 }
199
200 return errors == 0;
201 }
202
203 /// <summary>
204 /// Verifies the given project-wide input action asset using all registered verifiers.
205 /// </summary>
206 /// <param name="asset">The asset to be verified.</param>
207 /// <param name="reporter">The reporter to be used. If this argument is <c>null</c> the default reporter will be used.</param>
208 /// <returns><c>true</c> if no verification errors occurred, else <c>false</c>.</returns>
209 /// <remarks>Throws <c>System.ArgumentNullException</c> if <c>asset</c> is <c>null</c>.</remarks>
210 public static bool Verify(InputActionAsset asset, IReportInputActionAssetVerificationErrors reporter = null)
211 {
212 return (s_VerifierFactories == null || s_VerifierFactories.Count == 0) || new Verifier(reporter).Verify(asset);
213 }
214 }
215
216 internal static bool Verify(InputActionAsset asset, IReportInputActionAssetVerificationErrors reporter = null)
217 {
218 return Verifier.Verify(asset, reporter);
219 }
220
221 internal static bool RegisterInputActionAssetVerifier(Func<IInputActionAssetVerifier> factory)
222 {
223 return Verifier.RegisterFactory(factory);
224 }
225
226 internal static bool UnregisterInputActionAssetVerifier(Func<IInputActionAssetVerifier> factory)
227 {
228 return Verifier.UnregisterFactory(factory);
229 }
230
231 // Creates an asset at the given path containing the given JSON content.
232 private static InputActionAsset CreateAssetAtPathFromJson(string assetPath, string json)
233 {
234 // Note that the extra work here is to override the JSON name from the source asset
235 var inputActionAsset = InputActionAsset.FromJson(json);
236 inputActionAsset.name = InputActionImporter.NameFromAssetPath(assetPath);
237 InputActionAssetManager.SaveAsset(assetPath, inputActionAsset.ToJson());
238 return AssetDatabase.LoadAssetAtPath<InputActionAsset>(assetPath);
239 }
240 }
241}
242#endif // UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS