com.wallstop-studios.unity-helpers 2.0.0-rc81.9 → 2.0.0

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 (168) hide show
  1. package/.editorconfig +1 -1
  2. package/.gitattributes +1 -1
  3. package/.githooks/pre-commit +31 -5
  4. package/.githooks/pre-push +50 -0
  5. package/.github/dependabot.yml +24 -2
  6. package/.github/scripts/check-markdown-links.ps1 +77 -0
  7. package/.github/scripts/check_markdown_links.py +89 -0
  8. package/.github/scripts/check_markdown_url_encoding.py +74 -0
  9. package/.github/scripts/validate_markdown_links.py +194 -0
  10. package/.github/workflows/csharpier-autofix.yml +152 -0
  11. package/.github/workflows/format-on-demand.yml +305 -0
  12. package/.github/workflows/lint-doc-links.yml +8 -5
  13. package/.github/workflows/markdown-json.yml +6 -2
  14. package/.github/workflows/prettier-autofix.yml +195 -0
  15. package/.github/workflows/update-dotnet-tools.yml +80 -0
  16. package/.github/workflows/yaml-format-lint.yml +41 -0
  17. package/.lychee.toml +4 -4
  18. package/.markdownlint.jsonc +21 -0
  19. package/.pre-commit-config.yaml +11 -3
  20. package/.yamllint.yaml +31 -0
  21. package/AGENTS.md +5 -1
  22. package/CHANGELOG.md +11 -0
  23. package/CONTRIBUTING.md +49 -0
  24. package/CONTRIBUTING.md.meta +7 -0
  25. package/EDITOR_TOOLS_GUIDE.md +4 -0
  26. package/Editor/AnimationEventEditor.cs +337 -160
  27. package/Editor/Core/Helper/AnimationEventHelpers.cs +178 -152
  28. package/Editor/CustomEditors/PersistentDirectoryGUI.cs +20 -11
  29. package/Editor/CustomEditors/TexturePlatformOverrideEntryDrawer.cs +11 -2
  30. package/Editor/FitTextureSizeWindow.cs +43 -19
  31. package/Editor/PersistentDirectorySettings.cs +64 -12
  32. package/Editor/PrefabChecker.cs +72 -5
  33. package/Editor/Sprites/AnimationCopier.cs +132 -56
  34. package/Editor/Sprites/AnimationCreator.cs +63 -22
  35. package/Editor/Sprites/AnimationViewerWindow.cs +42 -6
  36. package/Editor/Sprites/TexturePlatformNameHelper.cs +50 -39
  37. package/Editor/Sprites/TextureResizerWizard.cs +23 -1
  38. package/Editor/Sprites/TextureSettingsApplierWindow.cs +148 -85
  39. package/Editor/Tools/ImageBlurTool.cs +81 -10
  40. package/Editor/Utils/EditorUi.cs +1 -1
  41. package/Editor/Utils/ScriptableObjectSingletonCreator.cs +1 -1
  42. package/GETTING_STARTED.md +40 -56
  43. package/RANDOM_PERFORMANCE.md +12 -12
  44. package/README.md +395 -2407
  45. package/RELATIONAL_COMPONENTS.md +92 -83
  46. package/Runtime/AssemblyInfo.cs +2 -0
  47. package/Runtime/Core/Attributes/NotNullAttribute.cs +1 -3
  48. package/Runtime/Core/Attributes/RelationalComponentAssigner.cs +50 -5
  49. package/Runtime/Core/DataStructure/CyclicBuffer.cs +0 -1
  50. package/Runtime/Core/Extension/RandomExtensions.cs +68 -0
  51. package/Runtime/Core/Extension/WallstopStudiosLogger.cs +16 -0
  52. package/Runtime/Core/Helper/Partials/ObjectHelpers.cs +4 -1
  53. package/Runtime/Core/Helper/ReflectionHelpers.cs +21 -10
  54. package/Runtime/Core/Helper/SpriteHelpers.cs +3 -1
  55. package/Runtime/Core/Helper/UnityMainThreadDispatcher.cs +45 -1
  56. package/Runtime/Core/Serialization/JsonConverters/GameObjectConverter.cs +13 -5
  57. package/Runtime/Core/Serialization/JsonConverters/ResolutionConverter.cs +1 -1
  58. package/Runtime/Core/Serialization/JsonConverters/TypeConverter.cs +1 -1
  59. package/Runtime/Core/Serialization/Serializer.cs +101 -0
  60. package/Runtime/Integrations/VContainer/AssemblyInfo.cs +9 -0
  61. package/Runtime/Integrations/VContainer/AssemblyInfo.cs.meta +3 -0
  62. package/Runtime/Integrations/VContainer/ObjectResolverRelationalExtensions.cs +96 -0
  63. package/Runtime/Integrations/VContainer/RelationalComponentEntryPoint.cs +90 -10
  64. package/Runtime/Integrations/VContainer/RelationalComponentsBuilderExtensions.cs +13 -1
  65. package/Runtime/Integrations/VContainer/RelationalObjectPools.cs +114 -0
  66. package/Runtime/Integrations/VContainer/RelationalObjectPools.cs.meta +11 -0
  67. package/Runtime/Integrations/VContainer/RelationalSceneAssignmentOptions.cs +16 -4
  68. package/Runtime/Integrations/VContainer/RelationalSceneLoadListener.cs +241 -0
  69. package/Runtime/Integrations/VContainer/RelationalSceneLoadListener.cs.meta +11 -0
  70. package/Runtime/Integrations/Zenject/AssemblyInfo.cs +9 -0
  71. package/Runtime/Integrations/Zenject/AssemblyInfo.cs.meta +3 -0
  72. package/Runtime/Integrations/Zenject/DiContainerRelationalExtensions.cs +69 -2
  73. package/Runtime/Integrations/Zenject/RelationalComponentSceneInitializer.cs +89 -12
  74. package/Runtime/Integrations/Zenject/RelationalComponentsInstaller.cs +23 -1
  75. package/Runtime/Integrations/Zenject/RelationalMemoryPools.cs +44 -0
  76. package/Runtime/Integrations/Zenject/RelationalMemoryPools.cs.meta +11 -0
  77. package/Runtime/Integrations/Zenject/RelationalSceneAssignmentOptions.cs +16 -10
  78. package/Runtime/Integrations/Zenject/RelationalSceneLoadListener.cs +243 -0
  79. package/Runtime/Integrations/Zenject/RelationalSceneLoadListener.cs.meta +11 -0
  80. package/Runtime/Tags/AttributeMetadataCache.cs +1 -4
  81. package/Runtime/Utils/Buffers.cs +4 -4
  82. package/Runtime/Utils/ScriptableObjectSingleton.cs +0 -1
  83. package/Runtime/Utils/SetTextureImportData.cs +3 -1
  84. package/Runtime/Utils/TextureScale.cs +10 -2
  85. package/Runtime/Visuals/UGUI/EnhancedImage.cs +6 -0
  86. package/Runtime/Visuals/UIToolkit/LayeredImage.cs +4 -1
  87. package/SERIALIZATION.md +15 -0
  88. package/SPATIAL_TREE_2D_PERFORMANCE.md +85 -82
  89. package/SPATIAL_TREE_3D_PERFORMANCE.md +94 -91
  90. package/Samples~/DI - VContainer/README.md +232 -51
  91. package/Samples~/DI - VContainer/Scripts/GameLifetimeScope.cs +22 -4
  92. package/Samples~/DI - VContainer/Scripts/RelationalConsumer.cs +5 -2
  93. package/Samples~/DI - VContainer/Scripts/Spawner.cs +113 -4
  94. package/Samples~/DI - Zenject/README.md +217 -53
  95. package/Samples~/DI - Zenject/Scripts/RelationalConsumer.cs +3 -0
  96. package/Samples~/DI - Zenject/Scripts/RelationalConsumerPool.cs +37 -0
  97. package/Samples~/DI - Zenject/Scripts/RelationalConsumerPool.cs.meta +12 -0
  98. package/Samples~/DI - Zenject/Scripts/SpawnerZenject.cs +74 -3
  99. package/Samples~/Random - PRNG/README.md +2 -1
  100. package/Samples~/Relational Components - Basic/README.md +3 -1
  101. package/Samples~/Serialization - JSON/README.md +2 -1
  102. package/Samples~/Spatial Structures - 2D and 3D/README.md +2 -1
  103. package/Samples~/UGUI - EnhancedImage/README.md +2 -1
  104. package/Samples~/UI Toolkit - MultiFile Selector (Editor)/README.md +2 -1
  105. package/THIRD_PARTY_NOTICES.md +1 -1
  106. package/Tests/Editor/Attributes/AnimationEventHelpersTests.cs +16 -0
  107. package/Tests/Editor/Core/Attributes/RelationalComponentAssignerTests.cs +3 -3
  108. package/Tests/Editor/Integrations/VContainer/VContainerRelationalEntryPointTests.cs +6 -2
  109. package/Tests/Editor/Integrations/VContainer/VContainerRelationalHelpersTests.cs +170 -0
  110. package/Tests/Editor/Integrations/VContainer/VContainerRelationalHelpersTests.cs.meta +11 -0
  111. package/Tests/Editor/Integrations/VContainer/WallstopStudios.UnityHelpers.Tests.Editor.VContainer.asmdef +2 -1
  112. package/Tests/Editor/Integrations/Zenject/WallstopStudios.UnityHelpers.Tests.Editor.Zenject.asmdef +3 -2
  113. package/Tests/Editor/Integrations/Zenject/ZenjectRelationalHelpersTests.cs +131 -0
  114. package/Tests/Editor/Integrations/Zenject/ZenjectRelationalHelpersTests.cs.meta +11 -0
  115. package/Tests/Editor/Integrations/Zenject/ZenjectRelationalInitializerTests.cs +6 -2
  116. package/Tests/Editor/PersistentDirectorySettingsTests.cs +59 -0
  117. package/Tests/Editor/PersistentDirectorySettingsTests.cs.meta +11 -0
  118. package/Tests/Editor/PrefabCheckerReportTests.cs +32 -0
  119. package/Tests/Editor/PrefabCheckerReportTests.cs.meta +11 -0
  120. package/Tests/Editor/Sprites/AnimationCopierFilterTests.cs +64 -0
  121. package/Tests/Editor/Sprites/AnimationCopierFilterTests.cs.meta +11 -0
  122. package/Tests/Editor/Sprites/AnimationCopierWindowTests.cs +1 -1
  123. package/Tests/Editor/Sprites/AnimationViewerWindowTests.cs +38 -0
  124. package/Tests/Editor/Sprites/AnimationViewerWindowTests.cs.meta +11 -0
  125. package/Tests/Editor/Sprites/ScriptableSpriteAtlasEditorTests.cs +1 -1
  126. package/Tests/Editor/Sprites/SpriteCropperAdditionalTests.cs +12 -12
  127. package/Tests/Editor/Sprites/SpriteCropperTests.cs +9 -9
  128. package/Tests/Editor/Sprites/SpritePivotAdjusterTests.cs +3 -3
  129. package/Tests/Editor/Sprites/TexturePlatformNameHelperTests.cs +18 -0
  130. package/Tests/Editor/Sprites/TextureResizerWizardTests.cs +5 -5
  131. package/Tests/Editor/Sprites/TextureSettingsApplierAPITests.cs +3 -3
  132. package/Tests/Editor/Sprites/TextureSettingsApplierWizardAdditionalTests.cs +4 -4
  133. package/Tests/Editor/Sprites/TextureSettingsApplierWizardTests.cs +4 -4
  134. package/Tests/Editor/Tools/ImageBlurToolTests.cs +22 -110
  135. package/Tests/Editor/Utils/CommonTestBase.cs +43 -1
  136. package/Tests/Editor/Utils/ScriptableObjectSingletonCreatorTests.cs +5 -5
  137. package/Tests/Editor/Windows/FitTextureSizeWindowTests.cs +66 -74
  138. package/Tests/Runtime/Attributes/RelationalComponentInitializerTests.cs +4 -15
  139. package/Tests/Runtime/DataStructures/SpatialTree3DBoundsConsistencyTests.cs +29 -29
  140. package/Tests/Runtime/Integrations/VContainer/RelationalComponentsVContainerTests.cs +259 -218
  141. package/Tests/Runtime/Integrations/VContainer/RelationalObjectPoolsVContainerTests.cs +86 -0
  142. package/Tests/Runtime/Integrations/VContainer/RelationalObjectPoolsVContainerTests.cs.meta +11 -0
  143. package/Tests/Runtime/Integrations/Zenject/RelationalComponentsZenjectTests.cs +255 -227
  144. package/Tests/Runtime/Performance/SpatialTree2DPerformanceTests.cs +5 -0
  145. package/Tests/Runtime/Performance/SpatialTree3DPerformanceTests.cs +3 -0
  146. package/Tests/Runtime/Serialization/JsonConverterAdditionalTests.cs +30 -0
  147. package/Tests/Runtime/Serialization/JsonConverterAdditionalTests.cs.meta +11 -0
  148. package/Tests/Runtime/Serialization/JsonConverterTests.cs +8 -12
  149. package/Tests/Runtime/Serialization/JsonSerializationTest.cs +16 -5
  150. package/Tests/Runtime/Serialization/SerializerAdditionalTests.cs +12 -0
  151. package/Tests/Runtime/Serialization/SerializerFileIoTests.cs +105 -0
  152. package/Tests/Runtime/Serialization/SerializerFileIoTests.cs.meta +11 -0
  153. package/Tests/Runtime/Serialization/UnityEngineObjectJsonTests.cs +247 -0
  154. package/Tests/Runtime/Serialization/UnityEngineObjectJsonTests.cs.meta +11 -0
  155. package/Tests/Runtime/TestUtils/CommonTestBase.cs +88 -0
  156. package/Tests/Runtime/Utils/CoroutineHandlerTests.cs +1 -1
  157. package/Tests/Runtime/Utils/LZMAComprehensiveTests.cs +1 -1
  158. package/Tests/Runtime/Utils/LZMATests.cs +1 -1
  159. package/Tests/Runtime/Utils/MatchColliderToSpriteTests.cs +1 -1
  160. package/Tests/Runtime/Visuals/EnhancedImageTests.cs +25 -56
  161. package/Tests/Runtime/Visuals/VisualsTestHelpers.cs +1 -8
  162. package/package-lock.json.meta +7 -0
  163. package/package.json +8 -4
  164. package/scripts/check-eol.ps1 +4 -5
  165. package/scripts/lint-tests.ps1 +156 -0
  166. package/scripts/lint-tests.ps1.meta +7 -0
  167. package/scripts/normalize-eol.ps1 +6 -9
  168. package/.github/workflows/csharpier.yml +0 -135
@@ -2,7 +2,6 @@ namespace WallstopStudios.UnityHelpers.Editor.Core.Helper
2
2
  {
3
3
  using System;
4
4
  using System.Collections.Generic;
5
- using System.Linq;
6
5
  using System.Reflection;
7
6
  using UnityEditor;
8
7
  using UnityEngine;
@@ -17,188 +16,215 @@ namespace WallstopStudios.UnityHelpers.Editor.Core.Helper
17
16
  static AnimationEventHelpers()
18
17
  {
19
18
  List<(Type, string)> ignoreDerived = new();
20
- Dictionary<Type, List<MethodInfo>> typesToMethods = TypeCache
21
- .GetTypesDerivedFrom<MonoBehaviour>()
22
- .Where(type => type.IsClass && !type.IsAbstract)
23
- .ToDictionary(
24
- type => type,
25
- type =>
19
+ Dictionary<Type, List<MethodInfo>> typesToMethods = new();
20
+
21
+ TypeCache.TypeCollection monoTypes = TypeCache.GetTypesDerivedFrom<MonoBehaviour>();
22
+ for (int i = 0; i < monoTypes.Count; i++)
23
+ {
24
+ Type type = monoTypes[i];
25
+ if (type == null || !type.IsClass || type.IsAbstract)
26
+ {
27
+ continue;
28
+ }
29
+
30
+ List<MethodInfo> definedMethods = GetPossibleAnimatorEventsForType(type);
31
+ // Filter: only methods directly declared on this type and attributed
32
+ for (int m = definedMethods.Count - 1; m >= 0; m--)
33
+ {
34
+ MethodInfo method = definedMethods[m];
35
+ if (method.DeclaringType != type)
26
36
  {
27
- List<MethodInfo> definedMethods = GetPossibleAnimatorEventsForType(type)
28
- .Where(method =>
29
- {
30
- // Only include methods where the attribute is directly defined
31
- if (
32
- !method.IsAttributeDefined<AnimationEventAttribute>(
33
- out _,
34
- inherit: false
35
- )
36
- )
37
- {
38
- return false;
39
- }
40
-
41
- // Only include methods that are declared on this type
42
- return method.DeclaringType == type;
43
- })
44
- .ToList();
45
-
46
- // Only include inherited methods if this type has its own handlers
47
- if (definedMethods.Count > 0)
37
+ definedMethods.RemoveAt(m);
38
+ continue;
39
+ }
40
+ if (!method.IsAttributeDefined<AnimationEventAttribute>(out _, inherit: false))
41
+ {
42
+ definedMethods.RemoveAt(m);
43
+ }
44
+ }
45
+
46
+ if (definedMethods.Count > 0)
47
+ {
48
+ // Include inherited methods that explicitly allow derived
49
+ List<MethodInfo> allPossible = GetPossibleAnimatorEventsForType(type);
50
+ for (int m = 0; m < allPossible.Count; m++)
51
+ {
52
+ MethodInfo candidate = allPossible[m];
53
+ if (candidate.DeclaringType == type)
48
54
  {
49
- // Also include inherited methods that explicitly allow derived types
50
- List<MethodInfo> inheritedMethods = GetPossibleAnimatorEventsForType(
51
- type
52
- )
53
- .Where(method =>
54
- {
55
- // Skip if not attributed
56
- if (
57
- !method.IsAttributeDefined<AnimationEventAttribute>(
58
- out _,
59
- inherit: false
60
- )
61
- )
62
- {
63
- return false;
64
- }
65
-
66
- // Skip if declared on this type (already handled)
67
- if (method.DeclaringType == type)
68
- {
69
- return false;
70
- }
71
-
72
- // Include inherited methods that allow derived
73
- if (
74
- method.IsAttributeDefined(
75
- out AnimationEventAttribute attribute,
76
- inherit: false
77
- )
78
- )
79
- {
80
- return !attribute.ignoreDerived;
81
- }
82
-
83
- return false;
84
- })
85
- .Select(method =>
86
- // Get the method from its declaring type to ensure consistent MethodInfo references
87
- method.DeclaringType.GetMethod(
88
- method.Name,
89
- BindingFlags.Instance
90
- | BindingFlags.Public
91
- | BindingFlags.NonPublic,
92
- null,
93
- method
94
- .GetParameters()
95
- .Select(p => p.ParameterType)
96
- .ToArray(),
97
- null
98
- )
99
- )
100
- .ToList();
101
-
102
- definedMethods.AddRange(inheritedMethods);
55
+ continue;
103
56
  }
104
- foreach (MethodInfo definedMethod in definedMethods)
105
- {
106
- // Only consider attributes on our specific method
107
- if (
108
- !definedMethod.IsAttributeDefined<AnimationEventAttribute>(
109
- out _,
110
- inherit: false
111
- )
57
+ if (
58
+ !candidate.IsAttributeDefined<AnimationEventAttribute>(
59
+ out AnimationEventAttribute attribute,
60
+ inherit: false
112
61
  )
113
- {
114
- continue;
115
- }
62
+ )
63
+ {
64
+ continue;
65
+ }
66
+ if (attribute.ignoreDerived)
67
+ {
68
+ continue;
69
+ }
116
70
 
117
- if (
118
- definedMethod.IsAttributeDefined(
119
- out AnimationEventAttribute attribute,
120
- inherit: false
121
- ) && attribute.ignoreDerived
122
- )
71
+ // Re-resolve method on its declaring type with exact parameter types
72
+ ParameterInfo[] parameters = candidate.GetParameters();
73
+ Type[] paramTypes;
74
+ if (parameters is { Length: > 0 })
75
+ {
76
+ paramTypes = new Type[parameters.Length];
77
+ for (int pi = 0; pi < parameters.Length; pi++)
123
78
  {
124
- ignoreDerived.Add((type, definedMethod.Name));
79
+ paramTypes[pi] = parameters[pi].ParameterType;
125
80
  }
126
81
  }
82
+ else
83
+ {
84
+ paramTypes = Array.Empty<Type>();
85
+ }
127
86
 
128
- return definedMethods;
87
+ MethodInfo resolved = candidate.DeclaringType.GetMethod(
88
+ candidate.Name,
89
+ BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
90
+ null,
91
+ paramTypes,
92
+ null
93
+ );
94
+ if (resolved != null)
95
+ {
96
+ definedMethods.Add(resolved);
97
+ }
129
98
  }
130
- );
99
+ }
131
100
 
132
- using PooledResource<List<KeyValuePair<Type, List<MethodInfo>>>> methodBufferResource =
133
- Buffers<KeyValuePair<Type, List<MethodInfo>>>.List.Get();
134
- List<KeyValuePair<Type, List<MethodInfo>>> methodBuffer = methodBufferResource.resource;
135
- foreach (KeyValuePair<Type, List<MethodInfo>> entry in typesToMethods)
136
- {
137
- methodBuffer.Add(entry);
101
+ for (int m = 0; m < definedMethods.Count; m++)
102
+ {
103
+ MethodInfo definedMethod = definedMethods[m];
104
+ if (
105
+ definedMethod.IsAttributeDefined(
106
+ out AnimationEventAttribute attr,
107
+ inherit: false
108
+ ) && attr.ignoreDerived
109
+ )
110
+ {
111
+ ignoreDerived.Add((type, definedMethod.Name));
112
+ }
113
+ }
114
+
115
+ if (definedMethods.Count > 0)
116
+ {
117
+ typesToMethods[type] = definedMethods;
118
+ }
138
119
  }
139
- foreach (KeyValuePair<Type, List<MethodInfo>> entry in methodBuffer)
120
+
121
+ using (
122
+ PooledResource<List<KeyValuePair<Type, List<MethodInfo>>>> methodBufferResource =
123
+ Buffers<KeyValuePair<Type, List<MethodInfo>>>.List.Get()
124
+ )
140
125
  {
141
- if (entry.Value.Count <= 0)
126
+ List<KeyValuePair<Type, List<MethodInfo>>> methodBuffer =
127
+ methodBufferResource.resource;
128
+ foreach (KeyValuePair<Type, List<MethodInfo>> entry in typesToMethods)
142
129
  {
143
- _ = typesToMethods.Remove(entry.Key);
130
+ methodBuffer.Add(entry);
144
131
  }
145
132
 
146
- Type key = entry.Key;
147
- foreach ((Type type, string methodName) in ignoreDerived)
133
+ foreach (KeyValuePair<Type, List<MethodInfo>> entry in methodBuffer)
148
134
  {
149
- if (key == type)
135
+ if (entry.Value.Count <= 0)
150
136
  {
137
+ _ = typesToMethods.Remove(entry.Key);
151
138
  continue;
152
139
  }
153
140
 
154
- if (!key.IsSubclassOf(type))
141
+ Type key = entry.Key;
142
+ for (int i = 0; i < ignoreDerived.Count; i++)
155
143
  {
156
- continue;
157
- }
144
+ (Type baseType, string methodName) = ignoreDerived[i];
145
+ if (key == baseType)
146
+ {
147
+ continue;
148
+ }
149
+ if (!key.IsSubclassOf(baseType))
150
+ {
151
+ continue;
152
+ }
158
153
 
159
- entry.Value.RemoveAll(method => method.Name == methodName);
160
- if (entry.Value.Count <= 0)
161
- {
162
- _ = typesToMethods.Remove(entry.Key);
163
- break;
154
+ // Remove inherited methods with this name
155
+ for (int midx = entry.Value.Count - 1; midx >= 0; midx--)
156
+ {
157
+ if (entry.Value[midx].Name == methodName)
158
+ {
159
+ entry.Value.RemoveAt(midx);
160
+ }
161
+ }
162
+ if (entry.Value.Count <= 0)
163
+ {
164
+ _ = typesToMethods.Remove(entry.Key);
165
+ break;
166
+ }
164
167
  }
165
168
  }
166
169
  }
167
170
 
168
- TypesToMethods = typesToMethods.ToDictionary(
169
- kvp => kvp.Key,
170
- kvp => (IReadOnlyList<MethodInfo>)kvp.Value
171
- );
171
+ // Project to IReadOnlyList without LINQ
172
+ Dictionary<Type, IReadOnlyList<MethodInfo>> ro = new();
173
+ foreach (KeyValuePair<Type, List<MethodInfo>> kvp in typesToMethods)
174
+ {
175
+ ro[kvp.Key] = kvp.Value;
176
+ }
177
+ TypesToMethods = ro;
172
178
  }
173
179
 
174
180
  public static List<MethodInfo> GetPossibleAnimatorEventsForType(Type type)
175
181
  {
176
- return type.GetMethods(
177
- BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
178
- )
179
- .Where(p =>
180
- p.ReturnType == typeof(void)
181
- && (
182
- p.GetParameters().Select(q => q.ParameterType).SequenceEqual(new Type[] { })
183
- || p.GetParameters()
184
- .Select(q => q.ParameterType)
185
- .SequenceEqual(new Type[] { typeof(int) })
186
- || p.GetParameters()
187
- .Select(q => q.ParameterType.BaseType)
188
- .SequenceEqual(new Type[] { typeof(Enum) })
189
- || p.GetParameters()
190
- .Select(q => q.ParameterType)
191
- .SequenceEqual(new Type[] { typeof(float) })
192
- || p.GetParameters()
193
- .Select(q => q.ParameterType)
194
- .SequenceEqual(new Type[] { typeof(string) })
195
- || p.GetParameters()
196
- .Select(q => q.ParameterType)
197
- .SequenceEqual(new Type[] { typeof(UnityEngine.Object) })
198
- )
199
- )
200
- .OrderBy(method => method.Name)
201
- .ToList();
182
+ MethodInfo[] methods = type.GetMethods(
183
+ BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
184
+ );
185
+ using (Buffers<MethodInfo>.List.Get(out List<MethodInfo> result))
186
+ {
187
+ for (int i = 0; i < methods.Length; i++)
188
+ {
189
+ MethodInfo m = methods[i];
190
+ if (m.ReturnType != typeof(void))
191
+ {
192
+ continue;
193
+ }
194
+
195
+ ParameterInfo[] ps = m.GetParameters();
196
+ bool ok;
197
+ if (ps == null || ps.Length == 0)
198
+ {
199
+ ok = true;
200
+ }
201
+ else if (ps.Length == 1)
202
+ {
203
+ Type pt = ps[0].ParameterType;
204
+ ok =
205
+ pt == typeof(int)
206
+ || pt == typeof(float)
207
+ || pt == typeof(string)
208
+ || pt == typeof(UnityEngine.Object)
209
+ || (pt.BaseType == typeof(Enum));
210
+ }
211
+ else
212
+ {
213
+ ok = false;
214
+ }
215
+
216
+ if (ok)
217
+ {
218
+ result.Add(m);
219
+ }
220
+ }
221
+
222
+ result.Sort(
223
+ static (a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal)
224
+ );
225
+ // Return a new list to avoid exposing pooled instance
226
+ return new List<MethodInfo>(result);
227
+ }
202
228
  }
203
229
  }
204
230
  }
@@ -5,7 +5,6 @@ namespace WallstopStudios.UnityHelpers.Editor.CustomEditors
5
5
  using UnityEngine;
6
6
  using UnityEditor;
7
7
  using System.Collections.Generic;
8
- using System.Linq;
9
8
  using System.IO;
10
9
  using WallstopStudios.UnityHelpers.Core.Helper;
11
10
  using Object = UnityEngine.Object;
@@ -115,13 +114,12 @@ namespace WallstopStudios.UnityHelpers.Editor.CustomEditors
115
114
 
116
115
  if (ContextFoldoutStates[foldoutKey])
117
116
  {
118
- List<DirectoryUsageData> pathsNotAlreadyInTop = allPaths
119
- .Skip(topN)
120
- .ToList();
121
- if (pathsNotAlreadyInTop.Any())
117
+ int remaining = allPaths.Length - topN;
118
+ if (remaining > 0)
122
119
  {
123
- foreach (DirectoryUsageData dirData in pathsNotAlreadyInTop)
120
+ for (int idx = topN; idx < allPaths.Length; idx++)
124
121
  {
122
+ DirectoryUsageData dirData = allPaths[idx];
125
123
  Rect moreHistoryButtonRect = new(
126
124
  startX + 30f,
127
125
  currentY,
@@ -213,8 +211,13 @@ namespace WallstopStudios.UnityHelpers.Editor.CustomEditors
213
211
  bool isExpanded = ContextFoldoutStates.GetValueOrDefault(foldoutKey, false);
214
212
  if (isExpanded)
215
213
  {
214
+ int remaining = allPaths.Length - topN;
215
+ if (remaining < 1)
216
+ {
217
+ remaining = 1;
218
+ }
216
219
  height +=
217
- Mathf.Max(1, allPaths.Skip(topN).Count())
220
+ remaining
218
221
  * (
219
222
  EditorGUIUtility.singleLineHeight
220
223
  + EditorGUIUtility.standardVerticalSpacing
@@ -271,8 +274,13 @@ namespace WallstopStudios.UnityHelpers.Editor.CustomEditors
271
274
  bool isExpanded = ContextFoldoutStates.GetValueOrDefault(foldoutKey, false);
272
275
  if (isExpanded)
273
276
  {
277
+ int remaining = allPaths.Length - topN;
278
+ if (remaining < 1)
279
+ {
280
+ remaining = 1;
281
+ }
274
282
  height +=
275
- Mathf.Max(1, allPaths.Skip(topN).Count())
283
+ remaining
276
284
  * (
277
285
  EditorGUIUtility.singleLineHeight
278
286
  + EditorGUIUtility.standardVerticalSpacing
@@ -765,11 +773,12 @@ namespace WallstopStudios.UnityHelpers.Editor.CustomEditors
765
773
  return;
766
774
  }
767
775
 
768
- DirectoryUsageData[] pathsNotAlreadyInTop = allPaths.Skip(topN).ToArray();
769
- if (0 < pathsNotAlreadyInTop.Length)
776
+ int remaining = allPaths.Length - topN;
777
+ if (remaining > 0)
770
778
  {
771
- foreach (DirectoryUsageData dirData in pathsNotAlreadyInTop)
779
+ for (int idx = topN; idx < allPaths.Length; idx++)
772
780
  {
781
+ DirectoryUsageData dirData = allPaths[idx];
773
782
  if (
774
783
  GUILayout.Button(
775
784
  new GUIContent(
@@ -8,17 +8,26 @@ namespace WallstopStudios.UnityHelpers.Editor.CustomEditors
8
8
  [CustomPropertyDrawer(typeof(TextureSettingsApplierWindow.PlatformOverrideEntry))]
9
9
  public sealed class TexturePlatformOverrideEntryDrawer : PropertyDrawer
10
10
  {
11
+ private static string[] _cachedChoices;
12
+ private static string[] _lastKnownRef;
13
+
11
14
  private static string[] GetChoices()
12
15
  {
13
16
  string[] known = TexturePlatformNameHelper.GetKnownPlatformNames();
17
+ if (ReferenceEquals(known, _lastKnownRef) && _cachedChoices != null)
18
+ {
19
+ return _cachedChoices;
20
+ }
21
+
14
22
  string[] arr = new string[known.Length + 1];
15
23
  for (int i = 0; i < known.Length; i++)
16
24
  {
17
25
  arr[i] = known[i];
18
26
  }
19
-
20
27
  arr[arr.Length - 1] = "Custom";
21
- return arr;
28
+ _lastKnownRef = known;
29
+ _cachedChoices = arr;
30
+ return _cachedChoices;
22
31
  }
23
32
 
24
33
  public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
@@ -4,7 +4,6 @@ namespace WallstopStudios.UnityHelpers.Editor
4
4
  using System;
5
5
  using System.Collections.Generic;
6
6
  using System.IO;
7
- using System.Linq;
8
7
  using System.Text.RegularExpressions;
9
8
  using UnityEditor;
10
9
  using UnityEngine;
@@ -410,20 +409,32 @@ namespace WallstopStudios.UnityHelpers.Editor
410
409
  // Reset the label-query GUIDs set for a fresh collection
411
410
  _labelQueryGuids.Clear();
412
411
 
413
- if (!uniqueAssetPaths.Any())
412
+ if (uniqueAssetPaths.Count == 0)
414
413
  {
415
414
  if (_useSelectionOnly)
416
415
  {
417
416
  // Selection-only mode with no folders selected: rely on direct GUIDs only.
418
417
  }
419
- else if (_textureSourcePaths.Any(o => o != null))
420
- {
421
- this.LogWarn($"No valid source folders found in the list.");
422
- }
423
418
  else
424
419
  {
425
- this.Log($"No source folders specified. Searching entire 'Assets' folder.");
426
- searchPaths.Add("Assets");
420
+ bool anyNonNull = false;
421
+ for (int i = 0; i < _textureSourcePaths.Count; i++)
422
+ {
423
+ if (_textureSourcePaths[i] != null)
424
+ {
425
+ anyNonNull = true;
426
+ break;
427
+ }
428
+ }
429
+ if (anyNonNull)
430
+ {
431
+ this.LogWarn($"No valid source folders found in the list.");
432
+ }
433
+ else
434
+ {
435
+ this.Log($"No source folders specified. Searching entire 'Assets' folder.");
436
+ searchPaths.Add("Assets");
437
+ }
427
438
  }
428
439
  }
429
440
  else
@@ -490,21 +501,34 @@ namespace WallstopStudios.UnityHelpers.Editor
490
501
  bool hasLabelFilterCsv = !string.IsNullOrWhiteSpace(_labelFilterCsv);
491
502
  if (hasLabelFilterCsv)
492
503
  {
493
- parsedLabels = _labelFilterCsv
494
- .Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
495
- .Select(s => s.Trim())
496
- .Where(s => s.Length > 0)
497
- .ToArray();
498
- if (parsedLabels.Length > 0)
504
+ string raw = _labelFilterCsv;
505
+ char[] seps = { ',', ';' };
506
+ string[] parts = raw.Split(seps, StringSplitOptions.RemoveEmptyEntries);
507
+ // Trim and filter empties without LINQ
508
+ int count = 0;
509
+ for (int i = 0; i < parts.Length; i++)
510
+ {
511
+ string item = parts[i] != null ? parts[i].Trim() : string.Empty;
512
+ if (!string.IsNullOrEmpty(item))
513
+ {
514
+ parts[count++] = item;
515
+ }
516
+ }
517
+ if (count > 0)
499
518
  {
519
+ parsedLabels = new string[count];
520
+ for (int i = 0; i < count; i++)
521
+ {
522
+ parsedLabels[i] = parts[i];
523
+ }
524
+
500
525
  labelSetRes = Buffers<string>.HashSet.Get(out labelSet);
501
526
  for (int i = 0; i < parsedLabels.Length; i++)
502
527
  {
503
- _ = labelSet.Add(
504
- _caseSensitiveNameFilter
505
- ? parsedLabels[i]
506
- : parsedLabels[i].ToLowerInvariant()
507
- );
528
+ string norm = _caseSensitiveNameFilter
529
+ ? parsedLabels[i]
530
+ : parsedLabels[i].ToLowerInvariant();
531
+ _ = labelSet.Add(norm);
508
532
  }
509
533
  }
510
534
  }