com.wallstop-studios.unity-helpers 1.0.0-rc4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/.gitattributes +63 -0
  2. package/CHANGELOG.md +0 -0
  3. package/CHANGELOG.md.meta +7 -0
  4. package/Editor/AnimationCreator.cs +218 -0
  5. package/Editor/AnimationCreator.cs.meta +11 -0
  6. package/Editor/AnimationEventEditor.cs +742 -0
  7. package/Editor/AnimationEventEditor.cs.meta +11 -0
  8. package/Editor/PrefabCheckWizard.cs +140 -0
  9. package/Editor/PrefabCheckWizard.cs.meta +11 -0
  10. package/Editor/WallstopStudios.UnityHelpers.Editor.asmdef +16 -0
  11. package/Editor/WallstopStudios.UnityHelpers.Editor.asmdef.meta +7 -0
  12. package/Editor.meta +8 -0
  13. package/LICENSE +21 -0
  14. package/LICENSE.md +7 -0
  15. package/LICENSE.md.meta +7 -0
  16. package/LICENSE.meta +7 -0
  17. package/README.md +2 -0
  18. package/README.md.meta +7 -0
  19. package/Runtime/Core/Attributes/AnimationEventAttribute.cs +102 -0
  20. package/Runtime/Core/Attributes/AnimationEventAttribute.cs.meta +11 -0
  21. package/Runtime/Core/Attributes/AutomaticallyFindAttribute.cs +43 -0
  22. package/Runtime/Core/Attributes/AutomaticallyFindAttribute.cs.meta +11 -0
  23. package/Runtime/Core/Attributes/ChildComponentAttribute.cs +85 -0
  24. package/Runtime/Core/Attributes/ChildComponentAttribute.cs.meta +11 -0
  25. package/Runtime/Core/Attributes/KSerializableAttribute.cs +23 -0
  26. package/Runtime/Core/Attributes/KSerializableAttribute.cs.meta +11 -0
  27. package/Runtime/Core/Attributes/NotNullAttribute.cs +33 -0
  28. package/Runtime/Core/Attributes/NotNullAttribute.cs.meta +11 -0
  29. package/Runtime/Core/Attributes/ParentComponent.cs +85 -0
  30. package/Runtime/Core/Attributes/ParentComponent.cs.meta +11 -0
  31. package/Runtime/Core/Attributes/ReadOnlyAttribute.cs +8 -0
  32. package/Runtime/Core/Attributes/ReadOnlyAttribute.cs.meta +11 -0
  33. package/Runtime/Core/Attributes/RelationalComponentExtensions.cs +14 -0
  34. package/Runtime/Core/Attributes/RelationalComponentExtensions.cs.meta +11 -0
  35. package/Runtime/Core/Attributes/SiblingComponentAttribute.cs +89 -0
  36. package/Runtime/Core/Attributes/SiblingComponentAttribute.cs.meta +11 -0
  37. package/Runtime/Core/Attributes/ValidateAssignmentAttribute.cs +66 -0
  38. package/Runtime/Core/Attributes/ValidateAssignmentAttribute.cs.meta +11 -0
  39. package/Runtime/Core/Attributes.meta +8 -0
  40. package/Runtime/Core/DataStructure/Adapters/FastVector2Int.cs +91 -0
  41. package/Runtime/Core/DataStructure/Adapters/FastVector2Int.cs.meta +11 -0
  42. package/Runtime/Core/DataStructure/Adapters/FastVector3Int.cs +180 -0
  43. package/Runtime/Core/DataStructure/Adapters/FastVector3Int.cs.meta +11 -0
  44. package/Runtime/Core/DataStructure/Adapters/KGuid.cs +274 -0
  45. package/Runtime/Core/DataStructure/Adapters/KGuid.cs.meta +11 -0
  46. package/Runtime/Core/DataStructure/Adapters/KVector2.cs +79 -0
  47. package/Runtime/Core/DataStructure/Adapters/KVector2.cs.meta +11 -0
  48. package/Runtime/Core/DataStructure/Adapters.meta +8 -0
  49. package/Runtime/Core/DataStructure/Circle.cs +50 -0
  50. package/Runtime/Core/DataStructure/Circle.cs.meta +11 -0
  51. package/Runtime/Core/DataStructure/CyclicBuffer.cs +130 -0
  52. package/Runtime/Core/DataStructure/CyclicBuffer.cs.meta +11 -0
  53. package/Runtime/Core/DataStructure/ISpatialTree.cs +58 -0
  54. package/Runtime/Core/DataStructure/ISpatialTree.cs.meta +11 -0
  55. package/Runtime/Core/DataStructure/KDTree.cs +186 -0
  56. package/Runtime/Core/DataStructure/KDTree.cs.meta +11 -0
  57. package/Runtime/Core/DataStructure/QuadTree.cs +184 -0
  58. package/Runtime/Core/DataStructure/QuadTree.cs.meta +11 -0
  59. package/Runtime/Core/DataStructure/RTree.cs +247 -0
  60. package/Runtime/Core/DataStructure/RTree.cs.meta +11 -0
  61. package/Runtime/Core/DataStructure/StringWrapper.cs +90 -0
  62. package/Runtime/Core/DataStructure/StringWrapper.cs.meta +11 -0
  63. package/Runtime/Core/DataStructure/TimedCache.cs +50 -0
  64. package/Runtime/Core/DataStructure/TimedCache.cs.meta +11 -0
  65. package/Runtime/Core/DataStructure.meta +8 -0
  66. package/Runtime/Core/Extension/AnimatorExtensions.cs +25 -0
  67. package/Runtime/Core/Extension/AnimatorExtensions.cs.meta +11 -0
  68. package/Runtime/Core/Extension/CircleExtensions.cs +25 -0
  69. package/Runtime/Core/Extension/CircleExtensions.cs.meta +11 -0
  70. package/Runtime/Core/Extension/ColorExtensions.cs +72 -0
  71. package/Runtime/Core/Extension/ColorExtensions.cs.meta +11 -0
  72. package/Runtime/Core/Extension/DictionaryExtensions.cs +173 -0
  73. package/Runtime/Core/Extension/DictionaryExtensions.cs.meta +11 -0
  74. package/Runtime/Core/Extension/DirectionExtensions.cs +210 -0
  75. package/Runtime/Core/Extension/DirectionExtensions.cs.meta +11 -0
  76. package/Runtime/Core/Extension/HashSetExtensions.cs +12 -0
  77. package/Runtime/Core/Extension/HashSetExtensions.cs.meta +11 -0
  78. package/Runtime/Core/Extension/IEnumerableExtensions.cs +109 -0
  79. package/Runtime/Core/Extension/IEnumerableExtensions.cs.meta +11 -0
  80. package/Runtime/Core/Extension/IListExtensions.cs +49 -0
  81. package/Runtime/Core/Extension/IListExtensions.cs.meta +11 -0
  82. package/Runtime/Core/Extension/LoggingExtensions.cs +196 -0
  83. package/Runtime/Core/Extension/LoggingExtensions.cs.meta +11 -0
  84. package/Runtime/Core/Extension/RandomExtensions.cs +110 -0
  85. package/Runtime/Core/Extension/RandomExtensions.cs.meta +11 -0
  86. package/Runtime/Core/Extension/StringExtensions.cs +76 -0
  87. package/Runtime/Core/Extension/StringExtensions.cs.meta +11 -0
  88. package/Runtime/Core/Extension/UnityExtensions.cs +1409 -0
  89. package/Runtime/Core/Extension/UnityExtensions.cs.meta +11 -0
  90. package/Runtime/Core/Extension.meta +8 -0
  91. package/Runtime/Core/Helper/AssignUtilities.cs +14 -0
  92. package/Runtime/Core/Helper/AssignUtilities.cs.meta +11 -0
  93. package/Runtime/Core/Helper/Enumerables.cs +17 -0
  94. package/Runtime/Core/Helper/Enumerables.cs.meta +11 -0
  95. package/Runtime/Core/Helper/Geometry.cs +26 -0
  96. package/Runtime/Core/Helper/Geometry.cs.meta +11 -0
  97. package/Runtime/Core/Helper/Helpers.cs +1092 -0
  98. package/Runtime/Core/Helper/Helpers.cs.meta +11 -0
  99. package/Runtime/Core/Helper/IterationHelpers.cs +32 -0
  100. package/Runtime/Core/Helper/IterationHelpers.cs.meta +11 -0
  101. package/Runtime/Core/Helper/LifetimeHelpers.cs +12 -0
  102. package/Runtime/Core/Helper/LifetimeHelpers.cs.meta +11 -0
  103. package/Runtime/Core/Helper/Objects.cs +447 -0
  104. package/Runtime/Core/Helper/Objects.cs.meta +11 -0
  105. package/Runtime/Core/Helper/SpriteHelpers.cs +53 -0
  106. package/Runtime/Core/Helper/SpriteHelpers.cs.meta +11 -0
  107. package/Runtime/Core/Helper/StringInList.cs +31 -0
  108. package/Runtime/Core/Helper/StringInList.cs.meta +11 -0
  109. package/Runtime/Core/Helper/WallMath.cs +75 -0
  110. package/Runtime/Core/Helper/WallMath.cs.meta +11 -0
  111. package/Runtime/Core/Helper.meta +8 -0
  112. package/Runtime/Core/Math/Line.cs +51 -0
  113. package/Runtime/Core/Math/Line.cs.meta +11 -0
  114. package/Runtime/Core/Math/Parabola.cs +44 -0
  115. package/Runtime/Core/Math/Parabola.cs.meta +11 -0
  116. package/Runtime/Core/Math/PointPolygonCheck.cs +25 -0
  117. package/Runtime/Core/Math/PointPolygonCheck.cs.meta +11 -0
  118. package/Runtime/Core/Math/Range.cs +56 -0
  119. package/Runtime/Core/Math/Range.cs.meta +11 -0
  120. package/Runtime/Core/Math/XXHash.cs +308 -0
  121. package/Runtime/Core/Math/XXHash.cs.meta +11 -0
  122. package/Runtime/Core/Math.meta +8 -0
  123. package/Runtime/Core/Model/Direction.cs +26 -0
  124. package/Runtime/Core/Model/Direction.cs.meta +11 -0
  125. package/Runtime/Core/Model.meta +8 -0
  126. package/Runtime/Core/OneOf/FastOneOf.cs +145 -0
  127. package/Runtime/Core/OneOf/FastOneOf.cs.meta +11 -0
  128. package/Runtime/Core/OneOf/None.cs +6 -0
  129. package/Runtime/Core/OneOf/None.cs.meta +11 -0
  130. package/Runtime/Core/OneOf.meta +8 -0
  131. package/Runtime/Core/Random/AbstractRandom.cs +537 -0
  132. package/Runtime/Core/Random/AbstractRandom.cs.meta +11 -0
  133. package/Runtime/Core/Random/IRandom.cs +141 -0
  134. package/Runtime/Core/Random/IRandom.cs.meta +11 -0
  135. package/Runtime/Core/Random/NativePcgRandom.cs +97 -0
  136. package/Runtime/Core/Random/NativePcgRandom.cs.meta +11 -0
  137. package/Runtime/Core/Random/PcgRandom.cs +142 -0
  138. package/Runtime/Core/Random/PcgRandom.cs.meta +11 -0
  139. package/Runtime/Core/Random/RandomState.cs +92 -0
  140. package/Runtime/Core/Random/RandomState.cs.meta +11 -0
  141. package/Runtime/Core/Random/RandomUtilities.cs +26 -0
  142. package/Runtime/Core/Random/RandomUtilities.cs.meta +11 -0
  143. package/Runtime/Core/Random/SquirrelRandom.cs +82 -0
  144. package/Runtime/Core/Random/SquirrelRandom.cs.meta +11 -0
  145. package/Runtime/Core/Random/SystemRandom.cs +110 -0
  146. package/Runtime/Core/Random/SystemRandom.cs.meta +11 -0
  147. package/Runtime/Core/Random/ThreadLocalRandom.cs +11 -0
  148. package/Runtime/Core/Random/ThreadLocalRandom.cs.meta +11 -0
  149. package/Runtime/Core/Random/UnityRandom.cs +24 -0
  150. package/Runtime/Core/Random/UnityRandom.cs.meta +11 -0
  151. package/Runtime/Core/Random/XorShiftRandom.cs +45 -0
  152. package/Runtime/Core/Random/XorShiftRandom.cs.meta +11 -0
  153. package/Runtime/Core/Random.meta +8 -0
  154. package/Runtime/Core/Serialization/JsonConverters/Vector2Converter.cs +32 -0
  155. package/Runtime/Core/Serialization/JsonConverters/Vector2Converter.cs.meta +11 -0
  156. package/Runtime/Core/Serialization/JsonConverters/Vector3Converter.cs +32 -0
  157. package/Runtime/Core/Serialization/JsonConverters/Vector3Converter.cs.meta +11 -0
  158. package/Runtime/Core/Serialization/JsonConverters.meta +8 -0
  159. package/Runtime/Core/Serialization/Serializer.cs +125 -0
  160. package/Runtime/Core/Serialization/Serializer.cs.meta +11 -0
  161. package/Runtime/Core/Serialization.meta +8 -0
  162. package/Runtime/Core/Threading/SingleThreadedThreadPool.cs +102 -0
  163. package/Runtime/Core/Threading/SingleThreadedThreadPool.cs.meta +11 -0
  164. package/Runtime/Core/Threading.meta +8 -0
  165. package/Runtime/Core.meta +8 -0
  166. package/Runtime/Protobuf-Net/System.Buffers.dll +0 -0
  167. package/Runtime/Protobuf-Net/System.Buffers.dll.meta +33 -0
  168. package/Runtime/Protobuf-Net/System.Collections.Immutable.dll +0 -0
  169. package/Runtime/Protobuf-Net/System.Collections.Immutable.dll.meta +33 -0
  170. package/Runtime/Protobuf-Net/System.Numerics.Vectors.dll +0 -0
  171. package/Runtime/Protobuf-Net/System.Numerics.Vectors.dll.meta +33 -0
  172. package/Runtime/Protobuf-Net/System.Runtime.CompilerServices.Unsafe.dll +0 -0
  173. package/Runtime/Protobuf-Net/System.Runtime.CompilerServices.Unsafe.dll.meta +33 -0
  174. package/Runtime/Protobuf-Net/protobuf-net.Core.dll +0 -0
  175. package/Runtime/Protobuf-Net/protobuf-net.Core.dll.meta +33 -0
  176. package/Runtime/Protobuf-Net/protobuf-net.dll +0 -0
  177. package/Runtime/Protobuf-Net/protobuf-net.dll.meta +33 -0
  178. package/Runtime/Protobuf-Net.meta +8 -0
  179. package/Runtime/Utils/AnimationEventEqualityComparer.cs +149 -0
  180. package/Runtime/Utils/AnimationEventEqualityComparer.cs.meta +11 -0
  181. package/Runtime/Utils/AnimatorEnumStateMachine.cs +80 -0
  182. package/Runtime/Utils/AnimatorEnumStateMachine.cs.meta +11 -0
  183. package/Runtime/Utils/Buffers.cs +32 -0
  184. package/Runtime/Utils/Buffers.cs.meta +11 -0
  185. package/Runtime/Utils/CircleLineRenderer.cs +122 -0
  186. package/Runtime/Utils/CircleLineRenderer.cs.meta +11 -0
  187. package/Runtime/Utils/Oscillator.cs +25 -0
  188. package/Runtime/Utils/Oscillator.cs.meta +11 -0
  189. package/Runtime/Utils/SetTextureImportData.cs +67 -0
  190. package/Runtime/Utils/SetTextureImportData.cs.meta +11 -0
  191. package/Runtime/Utils.meta +8 -0
  192. package/Runtime/WallstopStudios.UnityHelpers.asmdef +14 -0
  193. package/Runtime/WallstopStudios.UnityHelpers.asmdef.meta +7 -0
  194. package/Runtime.meta +8 -0
  195. package/Tests/Editor/WallstopStudios.UnityHelpers.Tests.Editor.asmdef +17 -0
  196. package/Tests/Editor/WallstopStudios.UnityHelpers.Tests.Editor.asmdef.meta +7 -0
  197. package/Tests/Editor.meta +8 -0
  198. package/Tests/Runtime/DataStructures/BalancedKDTreeTests.cs +14 -0
  199. package/Tests/Runtime/DataStructures/BalancedKDTreeTests.cs.meta +11 -0
  200. package/Tests/Runtime/DataStructures/QuadTreeTests.cs +14 -0
  201. package/Tests/Runtime/DataStructures/QuadTreeTests.cs.meta +11 -0
  202. package/Tests/Runtime/DataStructures/SpatialTreeTests.cs +106 -0
  203. package/Tests/Runtime/DataStructures/SpatialTreeTests.cs.meta +11 -0
  204. package/Tests/Runtime/DataStructures/UnbalancedKDTreeTests.cs +14 -0
  205. package/Tests/Runtime/DataStructures/UnbalancedKDTreeTests.cs.meta +11 -0
  206. package/Tests/Runtime/DataStructures.meta +8 -0
  207. package/Tests/Runtime/Performance/KDTreePerformanceTests.cs +14 -0
  208. package/Tests/Runtime/Performance/KDTreePerformanceTests.cs.meta +11 -0
  209. package/Tests/Runtime/Performance/QuadTreePerformanceTests.cs +14 -0
  210. package/Tests/Runtime/Performance/QuadTreePerformanceTests.cs.meta +11 -0
  211. package/Tests/Runtime/Performance/RandomPerformanceTests.cs +76 -0
  212. package/Tests/Runtime/Performance/RandomPerformanceTests.cs.meta +11 -0
  213. package/Tests/Runtime/Performance/SpatialTreePerformanceTest.cs +141 -0
  214. package/Tests/Runtime/Performance/SpatialTreePerformanceTest.cs.meta +11 -0
  215. package/Tests/Runtime/Performance/UnbalancedKDTreeTests.cs +14 -0
  216. package/Tests/Runtime/Performance/UnbalancedKDTreeTests.cs.meta +11 -0
  217. package/Tests/Runtime/Performance.meta +8 -0
  218. package/Tests/Runtime/Random/PcgRandomTests.cs +9 -0
  219. package/Tests/Runtime/Random/PcgRandomTests.cs.meta +11 -0
  220. package/Tests/Runtime/Random/RandomTestBase.cs +117 -0
  221. package/Tests/Runtime/Random/RandomTestBase.cs.meta +11 -0
  222. package/Tests/Runtime/Random/SquirrelRandomTests.cs +9 -0
  223. package/Tests/Runtime/Random/SquirrelRandomTests.cs.meta +11 -0
  224. package/Tests/Runtime/Random/SystemRandomTests.cs +10 -0
  225. package/Tests/Runtime/Random/SystemRandomTests.cs.meta +11 -0
  226. package/Tests/Runtime/Random/UnityRandomTests.cs +9 -0
  227. package/Tests/Runtime/Random/UnityRandomTests.cs.meta +11 -0
  228. package/Tests/Runtime/Random/XorShiftRandomTests.cs +9 -0
  229. package/Tests/Runtime/Random/XorShiftRandomTests.cs.meta +11 -0
  230. package/Tests/Runtime/Random.meta +8 -0
  231. package/Tests/Runtime/WallstopStudios.UnityHelpers.Tests.Runtime.asmdef +22 -0
  232. package/Tests/Runtime/WallstopStudios.UnityHelpers.Tests.Runtime.asmdef.meta +7 -0
  233. package/Tests/Runtime.meta +8 -0
  234. package/Tests.meta +8 -0
  235. package/Third Party Notices.md +1 -0
  236. package/Third Party Notices.md.meta +7 -0
  237. package/package.json +35 -0
  238. package/package.json.meta +7 -0
@@ -0,0 +1,742 @@
1
+ namespace UnityHelpers.Editor
2
+ {
3
+ using System;
4
+ using System.Linq;
5
+ using System.Collections.Generic;
6
+ using System.Reflection;
7
+ using Core.Attributes;
8
+ using Core.Helper;
9
+ using UnityEngine;
10
+ using UnityEditor;
11
+ using Utils;
12
+
13
+ // https://gist.githubusercontent.com/yujen/5e1cd78e2a341260b38029de08a449da/raw/ac60c1002e0e14375de5b2b0a167af00df3f74b4/SeniaAnimationEventEditor.cs
14
+ public sealed class AnimationEventEditor : EditorWindow
15
+ {
16
+ private static readonly IReadOnlyDictionary<Type, IReadOnlyList<MethodInfo>> TypesToMethods;
17
+
18
+ static AnimationEventEditor()
19
+ {
20
+ Dictionary<Type, IReadOnlyList<MethodInfo>> typesToMethods = AppDomain.CurrentDomain
21
+ .GetAssemblies()
22
+ .SelectMany(assembly => assembly.GetTypes())
23
+ .Where(type => type.IsClass)
24
+ .Where(type => typeof(MonoBehaviour).IsAssignableFrom(type))
25
+ .ToDictionary(
26
+ type => type,
27
+ type => (IReadOnlyList<MethodInfo>)type.GetPossibleAnimatorEventsForType());
28
+ foreach (KeyValuePair<Type, IReadOnlyList<MethodInfo>> entry in typesToMethods.ToList())
29
+ {
30
+ if (entry.Value.Count <= 0)
31
+ {
32
+ _ = typesToMethods.Remove(entry.Key);
33
+ }
34
+ }
35
+
36
+ TypesToMethods = typesToMethods;
37
+ }
38
+
39
+
40
+ [MenuItem("Tools/Unity Helpers/AnimationEvent Editor")]
41
+ private static void AnimationEventEditorMenu()
42
+ {
43
+ GetWindow(typeof(AnimationEventEditor));
44
+ }
45
+
46
+ public class AnimationEventItem
47
+ {
48
+ public AnimationEventItem(AnimationEvent animationEvent)
49
+ {
50
+ this.animationEvent = animationEvent;
51
+ search = string.Empty;
52
+ }
53
+
54
+ public Type selectedType;
55
+ public MethodInfo selectedMethod;
56
+ public string search;
57
+ public AnimationEvent animationEvent;
58
+ public Texture2D texture;
59
+ public bool isTextureReadable;
60
+ public bool isInvalidTextureRect;
61
+ public Sprite sprite;
62
+ public int? originalIndex;
63
+ public bool overrideEnumValues;
64
+ }
65
+
66
+ private IReadOnlyDictionary<Type, IReadOnlyList<MethodInfo>> Lookup =>
67
+ _explicitMode ? AnimationEventHelpers.TypesToMethods : TypesToMethods;
68
+
69
+ private int MaxFrameIndex =>
70
+ _currentClip == null ? 0 : (int)Math.Round(_currentClip.frameRate * _currentClip.length);
71
+
72
+ private Vector2 _scrollPosition;
73
+ private Animator _sourceAnimator;
74
+ private AnimationClip _currentClip;
75
+ private bool _explicitMode = true;
76
+ private bool _controlFrameTime = false;
77
+ private string _animationSearchString = string.Empty;
78
+ private List<ObjectReferenceKeyframe> _referenceCurve;
79
+
80
+ private readonly List<AnimationEvent> _baseClipEvents = new();
81
+ private readonly List<AnimationEventItem> _state = new();
82
+ private readonly Dictionary<AnimationEventItem, string> _lastSeenSearch = new();
83
+
84
+ private readonly Dictionary<AnimationEventItem, IReadOnlyDictionary<Type, IReadOnlyList<MethodInfo>>> _lookups =
85
+ new();
86
+
87
+ private int _selectedFrameIndex = -1;
88
+
89
+ private void OnGUI()
90
+ {
91
+ Animator tmpAnimator = EditorGUILayout.ObjectField(
92
+ "Animator Object", _sourceAnimator, typeof(Animator), true) as Animator;
93
+ if (tmpAnimator == null)
94
+ {
95
+ _sourceAnimator = null;
96
+ _state.Clear();
97
+ return;
98
+ }
99
+
100
+ if (_sourceAnimator != tmpAnimator)
101
+ {
102
+ _sourceAnimator = tmpAnimator;
103
+ _currentClip = null;
104
+ }
105
+
106
+ _explicitMode = EditorGUILayout.Toggle(
107
+ new GUIContent(
108
+ "Explicit Mode", "If true, restricts results to only those that explicitly with [AnimationEvent]"),
109
+ _explicitMode);
110
+ _controlFrameTime = EditorGUILayout.Toggle(
111
+ new GUIContent(
112
+ "Control Frame Time",
113
+ "Select to edit precise time of animation events instead of snapping to nearest frame"),
114
+ _controlFrameTime);
115
+
116
+ AnimationClip selectedClip = DrawAndFilterAnimationClips();
117
+ if (selectedClip == null)
118
+ {
119
+ return;
120
+ }
121
+
122
+ if (_currentClip != selectedClip)
123
+ {
124
+ _currentClip = selectedClip;
125
+ RefreshAnimationEvents();
126
+ }
127
+
128
+ _selectedFrameIndex = EditorGUILayout.IntField("FrameIndex", _selectedFrameIndex);
129
+
130
+ float frameRate = _currentClip.frameRate;
131
+ float oldFrameRate = frameRate;
132
+ if (GUILayout.Button("Add Event"))
133
+ {
134
+ if (0 <= _selectedFrameIndex)
135
+ {
136
+ _state.Add(new AnimationEventItem(new AnimationEvent { time = _selectedFrameIndex / frameRate }));
137
+ }
138
+ }
139
+
140
+ frameRate = _currentClip.frameRate = EditorGUILayout.FloatField("FrameRate", frameRate);
141
+ _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
142
+
143
+ // Need a copy because we might be mutating it
144
+ foreach (AnimationEventItem item in _state.ToList())
145
+ {
146
+ AnimationEvent animEvent = item.animationEvent;
147
+
148
+ int frame = Mathf.RoundToInt(animEvent.time * oldFrameRate);
149
+ EditorGUILayout.PrefixLabel("Frame " + frame);
150
+
151
+ DrawSpritePreview(item);
152
+
153
+ EditorGUI.indentLevel++;
154
+
155
+ RenderAnimationEventItem(item, frame, frameRate);
156
+
157
+ EditorGUI.indentLevel--;
158
+ EditorGUILayout.Space();
159
+ }
160
+
161
+ EditorGUILayout.EndScrollView();
162
+
163
+ DrawControlButtons();
164
+ }
165
+
166
+ private AnimationClip DrawAndFilterAnimationClips()
167
+ {
168
+ _animationSearchString = EditorGUILayout.TextField("Animation Search", _animationSearchString);
169
+ List<AnimationClip> animationClips = _sourceAnimator.runtimeAnimatorController.animationClips.ToList();
170
+ int selectedIndex;
171
+ if (string.IsNullOrEmpty(_animationSearchString) || _animationSearchString == "*")
172
+ {
173
+ selectedIndex = EditorGUILayout.Popup(
174
+ "Animation", animationClips.IndexOf(_currentClip),
175
+ animationClips.Select(clip => clip.name).ToArray());
176
+ }
177
+ else
178
+ {
179
+ List<string> searchTerms = _animationSearchString
180
+ .Split(" ")
181
+ .Select(searchPart => searchPart.ToLowerInvariant().Trim())
182
+ .Where(trimmed => !string.IsNullOrEmpty(trimmed) && trimmed != "*")
183
+ .ToList();
184
+
185
+ if (0 < searchTerms.Count)
186
+ {
187
+ foreach (AnimationClip animationClip in animationClips.ToList())
188
+ {
189
+ if (_currentClip == animationClip)
190
+ {
191
+ continue;
192
+ }
193
+
194
+ foreach (string searchTerm in searchTerms)
195
+ {
196
+ if (animationClip.name.ToLowerInvariant().Contains(searchTerm))
197
+ {
198
+ continue;
199
+ }
200
+
201
+ animationClips.Remove(animationClip);
202
+ }
203
+ }
204
+ }
205
+
206
+ selectedIndex = EditorGUILayout.Popup(
207
+ "Animation", animationClips.IndexOf(_currentClip),
208
+ animationClips.Select(clip => clip.name).ToArray());
209
+ }
210
+
211
+ if (selectedIndex < 0)
212
+ {
213
+ _currentClip = null;
214
+ RefreshAnimationEvents();
215
+ return null;
216
+ }
217
+
218
+ return animationClips[selectedIndex];
219
+ }
220
+
221
+ private int AnimationEventComparison(AnimationEventItem lhs, AnimationEventItem rhs)
222
+ {
223
+ if (ReferenceEquals(lhs, rhs))
224
+ {
225
+ return 0;
226
+ }
227
+
228
+ if (ReferenceEquals(null, rhs))
229
+ {
230
+ return -1;
231
+ }
232
+
233
+ if (ReferenceEquals(null, lhs))
234
+ {
235
+ return 1;
236
+ }
237
+
238
+ return AnimationEventEqualityComparer.Instance.Compare(lhs.animationEvent, rhs.animationEvent);
239
+ }
240
+
241
+ private void DrawControlButtons()
242
+ {
243
+ if (_baseClipEvents.SequenceEqual(
244
+ _state.Select(item => item.animationEvent), AnimationEventEqualityComparer.Instance))
245
+ {
246
+ GUILayout.Label("No changes detected...");
247
+ return;
248
+ }
249
+
250
+ Color oldColor = GUI.color;
251
+ GUI.color = Color.green;
252
+ if (GUILayout.Button("Save"))
253
+ {
254
+ SaveAnimation();
255
+ AssetDatabase.SaveAssets();
256
+ }
257
+
258
+ GUI.color = oldColor;
259
+ if (GUILayout.Button("Reset"))
260
+ {
261
+ RefreshAnimationEvents();
262
+ }
263
+
264
+ if (!_state.SequenceEqual(
265
+ _state.OrderBy(item => item.animationEvent, AnimationEventEqualityComparer.Instance)))
266
+ {
267
+ if (GUILayout.Button("Re-Order"))
268
+ {
269
+ _state.Sort(AnimationEventComparison);
270
+ }
271
+ }
272
+ }
273
+
274
+ private void RenderAnimationEventItem(AnimationEventItem item, int frame, float frameRate)
275
+ {
276
+ int index = _state.IndexOf(item);
277
+ EditorGUILayout.BeginHorizontal();
278
+ try
279
+ {
280
+ if (1 <= index && Math.Abs(_state[index - 1].animationEvent.time - item.animationEvent.time) < 0.001f &&
281
+ GUILayout.Button("Move Up"))
282
+ {
283
+ _state.RemoveAt(index);
284
+ _state.Insert(index - 1, item);
285
+ }
286
+
287
+ if (index < _state.Count - 1 &&
288
+ Math.Abs(_state[index + 1].animationEvent.time - item.animationEvent.time) < 0.001f &&
289
+ GUILayout.Button("Move Down"))
290
+ {
291
+ _state.RemoveAt(index);
292
+ _state.Insert(index + 1, item);
293
+ }
294
+
295
+ if (0 <= index && index < _baseClipEvents.Count &&
296
+ !AnimationEventEqualityComparer.Instance.Equals(item.animationEvent, _baseClipEvents[index]) &&
297
+ GUILayout.Button("Reset"))
298
+ {
299
+ AnimationEventEqualityComparer.Instance.CopyInto(item.animationEvent, _baseClipEvents[index]);
300
+ item.selectedType = null;
301
+ item.selectedMethod = null;
302
+ }
303
+
304
+ if (GUILayout.Button($"Remove Event at frame {frame}"))
305
+ {
306
+ _state.Remove(item);
307
+ return;
308
+ }
309
+ }
310
+ finally
311
+ {
312
+ EditorGUILayout.EndHorizontal();
313
+ }
314
+
315
+ IReadOnlyDictionary<Type, IReadOnlyList<MethodInfo>> lookup = FilterLookup(item);
316
+
317
+ TryPopulateTypeAndMethod(item, lookup);
318
+
319
+ List<Type> orderedTypes = lookup.Keys.OrderBy(type => type.FullName).Take(20).ToList();
320
+ if (item.selectedType != null && !orderedTypes.Contains(item.selectedType))
321
+ {
322
+ orderedTypes.Add(item.selectedType);
323
+ }
324
+
325
+ string[] orderedTypeNames = orderedTypes.Select(type => type.FullName).ToArray();
326
+
327
+ SelectFrameTime(item, frame, frameRate);
328
+
329
+ SelectFunctionName(item);
330
+
331
+ if (!SelectTypes(item, orderedTypes, orderedTypeNames))
332
+ {
333
+ return;
334
+ }
335
+
336
+ if (!SelectMethods(item, lookup))
337
+ {
338
+ return;
339
+ }
340
+
341
+ RenderEventParameters(item);
342
+ }
343
+
344
+ private void SelectFrameTime(AnimationEventItem item, int frame, float frameRate)
345
+ {
346
+ AnimationEvent animEvent = item.animationEvent;
347
+ float previousTime = animEvent.time;
348
+ if (_controlFrameTime)
349
+ {
350
+ float proposedFrameTime = EditorGUILayout.FloatField("FrameTime", animEvent.time);
351
+ animEvent.time = Mathf.Clamp(proposedFrameTime, 0, _currentClip.length);
352
+ }
353
+ else
354
+ {
355
+ int proposedFrame = EditorGUILayout.IntField("FrameIndex", frame);
356
+ animEvent.time = Mathf.Clamp(proposedFrame, 0, MaxFrameIndex) / frameRate;
357
+ }
358
+
359
+ // ReSharper disable once CompareOfFloatsByEqualityOperator
360
+ if (previousTime != animEvent.time)
361
+ {
362
+ item.texture = null;
363
+ }
364
+ }
365
+
366
+ private void SelectFunctionName(AnimationEventItem item)
367
+ {
368
+ AnimationEvent animEvent = item.animationEvent;
369
+ animEvent.functionName = EditorGUILayout.TextField("FunctionName", animEvent.functionName ?? string.Empty);
370
+ if (!_explicitMode)
371
+ {
372
+ item.search = EditorGUILayout.TextField("Search", item.search);
373
+ }
374
+ }
375
+
376
+ private void TryPopulateTypeAndMethod(
377
+ AnimationEventItem item, IReadOnlyDictionary<Type, IReadOnlyList<MethodInfo>> lookup)
378
+ {
379
+ if (item.selectedType != null)
380
+ {
381
+ return;
382
+ }
383
+
384
+ AnimationEvent animEvent = item.animationEvent;
385
+ foreach (KeyValuePair<Type, IReadOnlyList<MethodInfo>> entry in lookup.OrderBy(kvp => kvp.Key.FullName))
386
+ {
387
+ foreach (MethodInfo method in entry.Value)
388
+ {
389
+ if (string.Equals(method.Name, animEvent.functionName, StringComparison.Ordinal))
390
+ {
391
+ item.selectedType = entry.Key;
392
+ item.selectedMethod = method;
393
+ return;
394
+ }
395
+ }
396
+ }
397
+ }
398
+
399
+ private bool SelectTypes(AnimationEventItem item, IList<Type> orderedTypes, string[] orderedTypeNames)
400
+ {
401
+ int existingIndex = orderedTypes.IndexOf(item.selectedType);
402
+ int selectedTypeIndex = EditorGUILayout.Popup("TypeName", existingIndex, orderedTypeNames);
403
+ item.selectedType = selectedTypeIndex < 0 ? null : orderedTypes[selectedTypeIndex];
404
+ if (existingIndex != selectedTypeIndex)
405
+ {
406
+ item.selectedMethod = null;
407
+ }
408
+
409
+ return item.selectedType != null;
410
+ }
411
+
412
+ private bool SelectMethods(AnimationEventItem item, IReadOnlyDictionary<Type, IReadOnlyList<MethodInfo>> lookup)
413
+ {
414
+ AnimationEvent animEvent = item.animationEvent;
415
+ if (!lookup.TryGetValue(item.selectedType, out IReadOnlyList<MethodInfo> methods))
416
+ {
417
+ methods = new List<MethodInfo>(0);
418
+ }
419
+
420
+ if (item.selectedMethod == null || !methods.Contains(item.selectedMethod))
421
+ {
422
+ foreach (MethodInfo method in methods)
423
+ {
424
+ if (string.Equals(method.Name, animEvent.functionName, StringComparison.Ordinal))
425
+ {
426
+ item.selectedMethod = method;
427
+ break;
428
+ }
429
+ }
430
+
431
+ if (item.selectedMethod != null && !methods.Contains(item.selectedMethod))
432
+ {
433
+ methods = methods.Concat(Enumerables.Of(item.selectedMethod)).ToList();
434
+ }
435
+ }
436
+
437
+ int selectedMethodIndex = EditorGUILayout.Popup(
438
+ "MethodName", methods.ToList().IndexOf(item.selectedMethod),
439
+ methods.Select(method => method.Name).ToArray());
440
+ if (0 <= selectedMethodIndex)
441
+ {
442
+ item.selectedMethod = methods[selectedMethodIndex];
443
+ animEvent.functionName = item.selectedMethod.Name;
444
+ return true;
445
+ }
446
+
447
+ return false;
448
+ }
449
+
450
+ private void RenderEventParameters(AnimationEventItem item)
451
+ {
452
+ AnimationEvent animEvent = item.animationEvent;
453
+ ParameterInfo[] arrayParameterInfo = item.selectedMethod.GetParameters();
454
+ if (arrayParameterInfo.Length == 1)
455
+ {
456
+ EditorGUI.indentLevel++;
457
+
458
+ Type paramType = arrayParameterInfo[0].ParameterType;
459
+ if (paramType == typeof(int))
460
+ {
461
+ animEvent.intParameter = EditorGUILayout.IntField("IntParameter", animEvent.intParameter);
462
+ }
463
+ else if (paramType.BaseType == typeof(Enum))
464
+ {
465
+ string[] enumNamesArray = Enum.GetNames(paramType);
466
+ List<string> enumNames = enumNamesArray.ToList();
467
+ string enumName = Enum.GetName(paramType, animEvent.intParameter);
468
+
469
+ int index = EditorGUILayout.Popup($"{paramType.Name}", enumNames.IndexOf(enumName), enumNamesArray);
470
+ if (0 <= index)
471
+ {
472
+ animEvent.intParameter = (int)Enum.Parse(paramType, enumNames[index]);
473
+ }
474
+
475
+ item.overrideEnumValues = EditorGUILayout.Toggle("Override", item.overrideEnumValues);
476
+ if (item.overrideEnumValues)
477
+ {
478
+ animEvent.intParameter = EditorGUILayout.IntField("IntParameter", animEvent.intParameter);
479
+ }
480
+ }
481
+ else if (paramType == typeof(float))
482
+ {
483
+ animEvent.floatParameter = EditorGUILayout.FloatField(
484
+ "FloatParameter", animEvent.floatParameter);
485
+ }
486
+ else if (paramType == typeof(string))
487
+ {
488
+ animEvent.stringParameter = EditorGUILayout.TextField(
489
+ "StringParameter", animEvent.stringParameter);
490
+ }
491
+ else if (paramType == typeof(UnityEngine.Object))
492
+ {
493
+ animEvent.objectReferenceParameter = EditorGUILayout.ObjectField(
494
+ "ObjectReferenceParameter", animEvent.objectReferenceParameter, typeof(UnityEngine.Object),
495
+ true);
496
+ }
497
+
498
+ EditorGUI.indentLevel--;
499
+ }
500
+ }
501
+
502
+ private IReadOnlyDictionary<Type, IReadOnlyList<MethodInfo>> FilterLookup(AnimationEventItem item)
503
+ {
504
+ IReadOnlyDictionary<Type, IReadOnlyList<MethodInfo>> lookup;
505
+ if (!_explicitMode)
506
+ {
507
+ if (!_lastSeenSearch.TryGetValue(item, out string lastSearch) || !string.Equals(
508
+ lastSearch, item.search, StringComparison.InvariantCultureIgnoreCase) ||
509
+ !_lookups.TryGetValue(item, out lookup))
510
+ {
511
+ Dictionary<Type, List<MethodInfo>> filtered = Lookup.ToDictionary(
512
+ kvp => kvp.Key, kvp => kvp.Value.ToList());
513
+ List<string> searchTerms = item.search
514
+ .Split(" ")
515
+ .Select(searchTerm => searchTerm.Trim().ToLowerInvariant())
516
+ .Where(trimmed => !string.IsNullOrEmpty(trimmed) && trimmed != "*")
517
+ .ToList();
518
+
519
+ if (0 < searchTerms.Count)
520
+ {
521
+ foreach (KeyValuePair<Type, List<MethodInfo>> entry in filtered.ToList())
522
+ {
523
+ foreach (string searchTerm in searchTerms)
524
+ {
525
+ if (entry.Key.FullName.ToLowerInvariant().Contains(searchTerm))
526
+ {
527
+ continue;
528
+ }
529
+
530
+ if (entry.Value.Any(
531
+ methodInfo => methodInfo.Name.ToLowerInvariant().Contains(searchTerm)))
532
+ {
533
+ continue;
534
+ }
535
+
536
+ _ = filtered.Remove(entry.Key);
537
+ break;
538
+ }
539
+
540
+ }
541
+ }
542
+
543
+ _lookups[item] = lookup = filtered.ToDictionary(
544
+ kvp => kvp.Key, kvp => (IReadOnlyList<MethodInfo>)kvp.Value);
545
+ _lastSeenSearch[item] = item.search;
546
+ }
547
+ }
548
+ else
549
+ {
550
+ lookup = Lookup;
551
+ }
552
+
553
+ return lookup;
554
+ }
555
+
556
+ private void DrawSpritePreview(AnimationEventItem item)
557
+ {
558
+ SetupPreviewData(item);
559
+
560
+ string spriteName = item.sprite == null ? string.Empty : item.sprite.name;
561
+ if (item.texture != null)
562
+ {
563
+ GUILayout.Label(item.texture);
564
+ }
565
+ else if (!item.isTextureReadable && !string.IsNullOrEmpty(spriteName))
566
+ {
567
+ EditorGUILayout.BeginHorizontal();
568
+ try
569
+ {
570
+ GUILayout.Label($"Sprite '{spriteName}' required \"Read/Write\" enabled");
571
+ if (item.sprite != null && GUILayout.Button("Fix"))
572
+ {
573
+ string assetPath = AssetDatabase.GetAssetPath(item.sprite.texture);
574
+ if (string.IsNullOrEmpty(assetPath))
575
+ {
576
+ return;
577
+ }
578
+
579
+ TextureImporter tImporter = AssetImporter.GetAtPath(assetPath) as TextureImporter;
580
+ if (tImporter == null)
581
+ {
582
+ return;
583
+ }
584
+
585
+ tImporter.isReadable = true;
586
+ EditorUtility.SetDirty(tImporter);
587
+ tImporter.SaveAndReimport();
588
+ EditorUtility.SetDirty(item.sprite);
589
+ }
590
+ }
591
+ finally
592
+ {
593
+ EditorGUILayout.EndHorizontal();
594
+ }
595
+ }
596
+ else if (item.isInvalidTextureRect && !string.IsNullOrEmpty(spriteName))
597
+ {
598
+ GUILayout.Label($"Sprite '{spriteName}' is packed too tightly inside its texture");
599
+ }
600
+ }
601
+
602
+ private void SetupPreviewData(AnimationEventItem item)
603
+ {
604
+ if (item.texture != null)
605
+ {
606
+ return;
607
+ }
608
+
609
+ if (TryFindSpriteForEvent(item, out Sprite currentSprite))
610
+ {
611
+ item.sprite = currentSprite;
612
+ item.isTextureReadable = currentSprite.texture.isReadable;
613
+ item.isInvalidTextureRect = false;
614
+ if (item.isTextureReadable)
615
+ {
616
+ Rect? maybeTextureRect = null;
617
+ try
618
+ {
619
+ maybeTextureRect = currentSprite.textureRect;
620
+ }
621
+ catch
622
+ {
623
+ item.isInvalidTextureRect = true;
624
+ }
625
+
626
+ if (maybeTextureRect != null)
627
+ {
628
+ Rect textureRect = maybeTextureRect.Value;
629
+ item.texture = CopyTexture(textureRect, currentSprite.texture);
630
+ }
631
+ }
632
+ }
633
+ else
634
+ {
635
+ item.sprite = null;
636
+ item.isTextureReadable = false;
637
+ }
638
+ }
639
+
640
+ private bool TryFindSpriteForEvent(AnimationEventItem item, out Sprite sprite)
641
+ {
642
+ sprite = null;
643
+ foreach (ObjectReferenceKeyframe keyFrame in _referenceCurve)
644
+ {
645
+ if (keyFrame.time <= item.animationEvent.time)
646
+ {
647
+ Sprite frameSprite = keyFrame.value as Sprite;
648
+ if (frameSprite == null)
649
+ {
650
+ continue;
651
+ }
652
+
653
+ sprite = frameSprite;
654
+ continue;
655
+ }
656
+
657
+ return sprite != null;
658
+ }
659
+
660
+ return sprite != null;
661
+ }
662
+
663
+ private Texture2D CopyTexture(Rect textureRect, Texture2D sourceTexture)
664
+ {
665
+ int width = (int)Math.Ceiling(textureRect.width);
666
+ int height = (int)Math.Ceiling(textureRect.height);
667
+ Texture2D texture = new(width, height)
668
+ {
669
+ wrapMode = TextureWrapMode.Clamp,
670
+ filterMode = FilterMode.Point,
671
+ };
672
+ Vector2 offset = textureRect.position;
673
+ int offsetX = (int)Math.Ceiling(offset.x);
674
+ int offsetY = (int)Math.Ceiling(offset.y);
675
+ for (int x = 0; x < width; ++x)
676
+ {
677
+ for (int y = 0; y < height; ++y)
678
+ {
679
+ Color sourcePixel = sourceTexture.GetPixel(offsetX + x, offsetY + y);
680
+ texture.SetPixel(x, y, sourcePixel);
681
+ }
682
+ }
683
+
684
+ texture.Apply();
685
+ return texture;
686
+ }
687
+
688
+ private void RefreshAnimationEvents()
689
+ {
690
+ _state.Clear();
691
+ _baseClipEvents.Clear();
692
+ _lookups.Clear();
693
+ _lastSeenSearch.Clear();
694
+ if (_currentClip == null)
695
+ {
696
+ return;
697
+ }
698
+
699
+ for (int i = 0; i < _currentClip.events.Length; i++)
700
+ {
701
+ AnimationEvent animEvent = _currentClip.events[i];
702
+ _state.Add(
703
+ new AnimationEventItem(animEvent)
704
+ {
705
+ originalIndex = i
706
+ });
707
+ _baseClipEvents.Add(AnimationEventEqualityComparer.Instance.Copy(animEvent));
708
+ }
709
+
710
+ _selectedFrameIndex = MaxFrameIndex;
711
+ _referenceCurve = AnimationUtility.GetObjectReferenceCurve(
712
+ _currentClip, EditorCurveBinding.PPtrCurve("", typeof(SpriteRenderer), "m_Sprite")).ToList();
713
+ _referenceCurve.Sort(
714
+ (lhs, rhs) =>
715
+ {
716
+ int comparison = lhs.time.CompareTo(rhs.time);
717
+ if (comparison != 0)
718
+ {
719
+ return comparison;
720
+ }
721
+
722
+ string lhsName = lhs.value == null ? string.Empty : lhs.value.name ?? string.Empty;
723
+ string rhsName = rhs.value == null ? string.Empty : rhs.value.name ?? string.Empty;
724
+ return string.Compare(lhsName, rhsName, StringComparison.OrdinalIgnoreCase);
725
+ });
726
+ }
727
+
728
+ private void SaveAnimation()
729
+ {
730
+ if (_currentClip != null)
731
+ {
732
+ AnimationUtility.SetAnimationEvents(_currentClip, _state.Select(item => item.animationEvent).ToArray());
733
+ EditorUtility.SetDirty(_currentClip);
734
+ _baseClipEvents.Clear();
735
+ foreach (AnimationEventItem item in _state)
736
+ {
737
+ _baseClipEvents.Add(AnimationEventEqualityComparer.Instance.Copy(item.animationEvent));
738
+ }
739
+ }
740
+ }
741
+ }
742
+ }