com.wallstop-studios.unity-helpers 2.1.0 → 2.1.2
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.
- package/AGENTS.md +1 -0
- package/Docs/ILIST_SORTING_PERFORMANCE.md +92 -0
- package/{package-lock.json.meta → Docs/ILIST_SORTING_PERFORMANCE.md.meta} +1 -1
- package/Docs/INDEX.md +11 -1
- package/Docs/Images/random_generators.svg +7 -7
- package/Docs/RANDOM_PERFORMANCE.md +17 -14
- package/Docs/REFLECTION_HELPERS.md +84 -1
- package/Docs/REFLECTION_PERFORMANCE.md +169 -0
- package/Docs/REFLECTION_PERFORMANCE.md.meta +7 -0
- package/Docs/RELATIONAL_COMPONENTS.md +6 -0
- package/Docs/RELATIONAL_COMPONENT_PERFORMANCE.md +63 -0
- package/Docs/RELATIONAL_COMPONENT_PERFORMANCE.md.meta +7 -0
- package/Docs/SPATIAL_TREE_2D_PERFORMANCE.md +64 -64
- package/Docs/SPATIAL_TREE_3D_PERFORMANCE.md +64 -64
- package/Editor/Core/Helper/AnimationEventHelpers.cs +1 -1
- package/Editor/Sprites/AnimationCopier.cs +1 -1
- package/Editor/Sprites/AnimationViewerWindow.cs +4 -4
- package/Editor/Sprites/SpriteSettingsApplierAPI.cs +2 -1
- package/Editor/Sprites/TextureResizerWizard.cs +4 -3
- package/Editor/Utils/ScriptableObjectSingletonCreator.cs +3 -3
- package/README.md +33 -18
- package/Runtime/Core/Attributes/BaseRelationalComponentAttribute.cs +147 -20
- package/Runtime/Core/Attributes/ChildComponentAttribute.cs +630 -117
- package/Runtime/Core/Attributes/NotNullAttribute.cs +5 -2
- package/Runtime/Core/Attributes/ParentComponentAttribute.cs +477 -103
- package/Runtime/Core/Attributes/RelationalComponentAssigner.cs +26 -3
- package/Runtime/Core/Attributes/RelationalComponentExtensions.cs +19 -3
- package/Runtime/Core/Attributes/SiblingComponentAttribute.cs +265 -92
- package/Runtime/Core/CodeGen.meta +8 -0
- package/Runtime/Core/DataStructure/ImmutableBitSet.cs +5 -20
- package/Runtime/Core/Extension/IListExtensions.cs +720 -12
- package/Runtime/Core/Helper/Logging/UnityLogTagFormatter.cs +11 -7
- package/Runtime/Core/Helper/Objects.cs +1 -1
- package/Runtime/Core/Helper/ReflectionHelpers.Factory.cs +5142 -0
- package/Runtime/Core/Helper/ReflectionHelpers.Factory.cs.meta +11 -0
- package/Runtime/Core/Helper/ReflectionHelpers.cs +1812 -1518
- package/Runtime/Core/Helper/UnityMainThreadDispatcher.cs +2 -3
- package/Runtime/Core/Math/Line2D.cs +2 -4
- package/Runtime/Core/Math/Line3D.cs +2 -4
- package/Runtime/Core/Random/AbstractRandom.cs +52 -5
- package/Runtime/Core/Random/DotNetRandom.cs +3 -3
- package/Runtime/Core/Random/FlurryBurstRandom.cs +279 -0
- package/Runtime/Core/Random/FlurryBurstRandom.cs.meta +3 -0
- package/Runtime/Core/Random/IllusionFlow.cs +3 -3
- package/Runtime/Core/Random/LinearCongruentialGenerator.cs +3 -3
- package/Runtime/Core/Random/PcgRandom.cs +6 -6
- package/Runtime/Core/Random/PhotonSpinRandom.cs +387 -0
- package/Runtime/Core/Random/PhotonSpinRandom.cs.meta +3 -0
- package/Runtime/Core/Random/RomuDuo.cs +3 -3
- package/Runtime/Core/Random/SplitMix64.cs +3 -3
- package/Runtime/Core/Random/SquirrelRandom.cs +6 -4
- package/Runtime/Core/Random/StormDropRandom.cs +271 -0
- package/Runtime/Core/Random/StormDropRandom.cs.meta +3 -0
- package/Runtime/Core/Random/UnityRandom.cs +3 -3
- package/Runtime/Core/Random/WyRandom.cs +6 -4
- package/Runtime/Core/Random/XorShiftRandom.cs +3 -3
- package/Runtime/Core/Random/XoroShiroRandom.cs +3 -3
- package/Runtime/Tags/AttributeMetadataCache.cs +316 -9
- package/Runtime/Tags/CosmeticEffectData.cs +1 -1
- package/Runtime/Visuals/UIToolkit/MultiFileSelectorElement.cs +3 -3
- package/Tests/Editor/Helper/HelpersTests.cs +2 -2
- package/Tests/Editor/Helper/ReflectionHelpersTypedEditorTests.cs +87 -0
- package/Tests/Editor/Helper/ReflectionHelpersTypedEditorTests.cs.meta +11 -0
- package/Tests/Editor/Helper/SpriteHelpersTests.cs +1 -1
- package/Tests/Editor/PrefabCheckerReportTests.cs +3 -3
- package/Tests/Editor/Sprites/AnimationCopierFilterTests.cs +18 -12
- package/Tests/Editor/Sprites/AnimationCopierWindowTests.cs +8 -7
- package/Tests/Editor/Sprites/AnimationViewerWindowTests.cs +2 -1
- package/Tests/Editor/Sprites/ScriptableSpriteAtlasEditorTests.cs +6 -5
- package/Tests/Editor/Sprites/SpriteCropperAdditionalTests.cs +2 -1
- package/Tests/Editor/Sprites/SpriteCropperTests.cs +7 -6
- package/Tests/Editor/Sprites/SpritePivotAdjusterAdditionalTests.cs +2 -1
- package/Tests/Editor/Sprites/SpritePivotAdjusterTests.cs +4 -3
- package/Tests/Editor/Sprites/TextureResizerWizardTests.cs +10 -9
- package/Tests/Editor/Sprites/TextureSettingsApplierAPITests.cs +2 -1
- package/Tests/Editor/Tags/AttributeMetadataCacheTests.cs +192 -0
- package/Tests/Editor/Tags/AttributeMetadataCacheTests.cs.meta +11 -0
- package/Tests/Editor/Tags.meta +8 -0
- package/Tests/Runtime/Extensions/IListExtensionTests.cs +187 -1
- package/Tests/Runtime/Helper/ObjectsTests.cs +4 -4
- package/Tests/Runtime/Helper/ReflectionHelperCapabilityMatrixTests.cs +2923 -0
- package/Tests/Runtime/Helper/ReflectionHelperCapabilityMatrixTests.cs.meta +11 -0
- package/Tests/Runtime/Helper/ReflectionHelperTests.cs +660 -0
- package/Tests/Runtime/Integrations/Reflex/RelationalComponentsReflexTests.cs +2 -2
- package/Tests/Runtime/Performance/IListSortingPerformanceTests.cs +346 -0
- package/Tests/Runtime/Performance/IListSortingPerformanceTests.cs.meta +11 -0
- package/Tests/Runtime/Performance/RandomPerformanceTests.cs +3 -0
- package/Tests/Runtime/Performance/ReflectionPerformanceTests.cs +1238 -0
- package/Tests/Runtime/Performance/ReflectionPerformanceTests.cs.meta +11 -0
- package/Tests/Runtime/Performance/RelationalComponentBenchmarkTests.cs +832 -0
- package/Tests/Runtime/Performance/RelationalComponentBenchmarkTests.cs.meta +11 -0
- package/Tests/Runtime/Random/FlurryBurstRandomTests.cs +12 -0
- package/Tests/Runtime/Random/FlurryBurstRandomTests.cs.meta +3 -0
- package/Tests/Runtime/Random/PhotonSpinRandomTests.cs +12 -0
- package/Tests/Runtime/Random/PhotonSpinRandomTests.cs.meta +3 -0
- package/Tests/Runtime/Random/RandomProtoSerializationTests.cs +14 -0
- package/Tests/Runtime/Random/RandomTestBase.cs +39 -4
- package/Tests/Runtime/Random/StormDropRandomTests.cs +12 -0
- package/Tests/Runtime/Random/StormDropRandomTests.cs.meta +3 -0
- package/Tests/Runtime/Serialization/ProtoInterfaceResolutionEdgeTests.cs +2 -2
- package/Tests/Runtime/Serialization/ProtoRootRegistrationTests.cs +1 -1
- package/Tests/Runtime/Serialization/ProtoSerializeBehaviorTests.cs +1 -1
- package/Tests/Runtime/Tags/PeriodicEffectDefinitionSerializationTests.cs +2 -2
- package/package.json +1 -1
- package/Tests/Runtime/Performance/RelationComponentPerformanceTests.cs +0 -60
- package/Tests/Runtime/Performance/RelationComponentPerformanceTests.cs.meta +0 -3
|
@@ -3,10 +3,16 @@ namespace WallstopStudios.UnityHelpers.Core.Attributes
|
|
|
3
3
|
using System;
|
|
4
4
|
using System.Collections;
|
|
5
5
|
using System.Collections.Generic;
|
|
6
|
+
using System.Linq;
|
|
7
|
+
using System.Linq.Expressions;
|
|
8
|
+
using System.Reflection;
|
|
6
9
|
using Extension;
|
|
7
10
|
using UnityEngine;
|
|
8
11
|
using WallstopStudios.UnityHelpers.Utils;
|
|
9
12
|
using static RelationalComponentProcessor;
|
|
13
|
+
#if UNITY_EDITOR && UNITY_2020_2_OR_NEWER
|
|
14
|
+
using Unity.Profiling;
|
|
15
|
+
#endif
|
|
10
16
|
|
|
11
17
|
/// <summary>
|
|
12
18
|
/// Automatically assigns parent components (components up the transform hierarchy) to the decorated field.
|
|
@@ -86,6 +92,15 @@ namespace WallstopStudios.UnityHelpers.Core.Attributes
|
|
|
86
92
|
FieldMetadata<ParentComponentAttribute>[]
|
|
87
93
|
> FieldsByType = new();
|
|
88
94
|
|
|
95
|
+
#if UNITY_EDITOR && UNITY_2020_2_OR_NEWER
|
|
96
|
+
private static readonly ProfilerMarker ParentFastPathMarker = new ProfilerMarker(
|
|
97
|
+
"RelationalComponents.Parent.FastPath"
|
|
98
|
+
);
|
|
99
|
+
private static readonly ProfilerMarker ParentFallbackMarker = new ProfilerMarker(
|
|
100
|
+
"RelationalComponents.Parent.Fallback"
|
|
101
|
+
);
|
|
102
|
+
#endif
|
|
103
|
+
|
|
89
104
|
/// <summary>
|
|
90
105
|
/// Assigns fields on <paramref name="component"/> marked with <see cref="ParentComponentAttribute"/>.
|
|
91
106
|
/// </summary>
|
|
@@ -104,11 +119,22 @@ namespace WallstopStudios.UnityHelpers.Core.Attributes
|
|
|
104
119
|
/// </example>
|
|
105
120
|
public static void AssignParentComponents(this Component component)
|
|
106
121
|
{
|
|
107
|
-
Type componentType = component.GetType();
|
|
108
122
|
FieldMetadata<ParentComponentAttribute>[] fields = FieldsByType.GetOrAdd(
|
|
109
|
-
|
|
123
|
+
component.GetType(),
|
|
110
124
|
type => GetFieldMetadata<ParentComponentAttribute>(type)
|
|
111
125
|
);
|
|
126
|
+
AssignParentComponents(component, fields);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
internal static void AssignParentComponents(
|
|
130
|
+
Component component,
|
|
131
|
+
FieldMetadata<ParentComponentAttribute>[] fields
|
|
132
|
+
)
|
|
133
|
+
{
|
|
134
|
+
if (component == null || fields == null || fields.Length == 0)
|
|
135
|
+
{
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
112
138
|
|
|
113
139
|
foreach (FieldMetadata<ParentComponentAttribute> field in fields)
|
|
114
140
|
{
|
|
@@ -117,8 +143,7 @@ namespace WallstopStudios.UnityHelpers.Core.Attributes
|
|
|
117
143
|
continue;
|
|
118
144
|
}
|
|
119
145
|
|
|
120
|
-
|
|
121
|
-
FilterParameters filters = new(field.attribute);
|
|
146
|
+
FilterParameters filters = field.Filters;
|
|
122
147
|
Transform root = component.transform;
|
|
123
148
|
if (field.attribute.OnlyAncestors)
|
|
124
149
|
{
|
|
@@ -128,128 +153,382 @@ namespace WallstopStudios.UnityHelpers.Core.Attributes
|
|
|
128
153
|
if (root == null)
|
|
129
154
|
{
|
|
130
155
|
SetEmptyCollection(component, field);
|
|
131
|
-
|
|
156
|
+
LogMissingComponentError(component, field, "parent");
|
|
157
|
+
continue;
|
|
132
158
|
}
|
|
133
159
|
else
|
|
134
160
|
{
|
|
135
|
-
|
|
161
|
+
bool foundParent;
|
|
162
|
+
if (field.kind == FieldKind.Single)
|
|
136
163
|
{
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
using PooledResource<List<Component>> parentComponentBuffer =
|
|
140
|
-
Buffers<Component>.List.Get(out List<Component> parentComponents);
|
|
141
|
-
GetParentComponents(
|
|
164
|
+
if (
|
|
165
|
+
TryAssignParentSingleFast(
|
|
142
166
|
root,
|
|
167
|
+
field,
|
|
168
|
+
filters,
|
|
169
|
+
out Component parentComponent
|
|
170
|
+
)
|
|
171
|
+
|| TryGetFirstParentComponent(
|
|
172
|
+
root,
|
|
173
|
+
filters,
|
|
143
174
|
field.elementType,
|
|
144
175
|
field.attribute,
|
|
145
176
|
field.isInterface,
|
|
146
|
-
|
|
147
|
-
)
|
|
177
|
+
out parentComponent
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
{
|
|
181
|
+
field.SetValue(component, parentComponent);
|
|
182
|
+
foundParent = true;
|
|
183
|
+
}
|
|
184
|
+
else
|
|
185
|
+
{
|
|
186
|
+
foundParent = false;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
else
|
|
190
|
+
{
|
|
191
|
+
switch (field.kind)
|
|
192
|
+
{
|
|
193
|
+
case FieldKind.Array:
|
|
194
|
+
{
|
|
195
|
+
if (
|
|
196
|
+
TryAssignParentCollectionFast(
|
|
197
|
+
component,
|
|
198
|
+
root,
|
|
199
|
+
field,
|
|
200
|
+
filters,
|
|
201
|
+
out bool assignedAny
|
|
202
|
+
)
|
|
203
|
+
)
|
|
204
|
+
{
|
|
205
|
+
foundParent = assignedAny;
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
148
208
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
209
|
+
using PooledResource<List<Component>> parentComponentBuffer =
|
|
210
|
+
Buffers<Component>.List.Get(
|
|
211
|
+
out List<Component> parentComponents
|
|
212
|
+
);
|
|
213
|
+
GetParentComponents(
|
|
214
|
+
root,
|
|
215
|
+
field.elementType,
|
|
216
|
+
field.attribute,
|
|
217
|
+
field.isInterface,
|
|
218
|
+
parentComponents
|
|
219
|
+
);
|
|
157
220
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
221
|
+
int filteredCount =
|
|
222
|
+
!filters.RequiresPostProcessing && field.attribute.MaxCount <= 0
|
|
223
|
+
? parentComponents.Count
|
|
224
|
+
: FilterComponentsInPlace(
|
|
225
|
+
parentComponents,
|
|
226
|
+
filters,
|
|
227
|
+
field.attribute,
|
|
228
|
+
field.elementType,
|
|
229
|
+
field.isInterface,
|
|
230
|
+
filterDisabledComponents: false
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
Array correctTypedArray = field.arrayCreator(filteredCount);
|
|
234
|
+
for (int i = 0; i < filteredCount; ++i)
|
|
235
|
+
{
|
|
236
|
+
correctTypedArray.SetValue(parentComponents[i], i);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
field.SetValue(component, correctTypedArray);
|
|
240
|
+
foundParent = filteredCount > 0;
|
|
241
|
+
break;
|
|
162
242
|
}
|
|
243
|
+
case FieldKind.List:
|
|
244
|
+
{
|
|
245
|
+
if (
|
|
246
|
+
TryAssignParentCollectionFast(
|
|
247
|
+
component,
|
|
248
|
+
root,
|
|
249
|
+
field,
|
|
250
|
+
filters,
|
|
251
|
+
out bool assignedAny
|
|
252
|
+
)
|
|
253
|
+
)
|
|
254
|
+
{
|
|
255
|
+
foundParent = assignedAny;
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
163
258
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
field.attribute,
|
|
176
|
-
field.isInterface,
|
|
177
|
-
parentComponents
|
|
178
|
-
);
|
|
259
|
+
using PooledResource<List<Component>> parentComponentBuffer =
|
|
260
|
+
Buffers<Component>.List.Get(
|
|
261
|
+
out List<Component> parentComponents
|
|
262
|
+
);
|
|
263
|
+
GetParentComponents(
|
|
264
|
+
root,
|
|
265
|
+
field.elementType,
|
|
266
|
+
field.attribute,
|
|
267
|
+
field.isInterface,
|
|
268
|
+
parentComponents
|
|
269
|
+
);
|
|
179
270
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
271
|
+
int filteredCount =
|
|
272
|
+
!filters.RequiresPostProcessing && field.attribute.MaxCount <= 0
|
|
273
|
+
? parentComponents.Count
|
|
274
|
+
: FilterComponentsInPlace(
|
|
275
|
+
parentComponents,
|
|
276
|
+
filters,
|
|
277
|
+
field.attribute,
|
|
278
|
+
field.elementType,
|
|
279
|
+
field.isInterface,
|
|
280
|
+
filterDisabledComponents: false
|
|
281
|
+
);
|
|
188
282
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
283
|
+
if (field.GetValue(component) is IList instance)
|
|
284
|
+
{
|
|
285
|
+
instance.Clear();
|
|
286
|
+
}
|
|
287
|
+
else
|
|
288
|
+
{
|
|
289
|
+
instance = field.listCreator(filteredCount);
|
|
290
|
+
field.SetValue(component, instance);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
for (int i = 0; i < filteredCount; ++i)
|
|
294
|
+
{
|
|
295
|
+
instance.Add(parentComponents[i]);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
foundParent = filteredCount > 0;
|
|
299
|
+
break;
|
|
193
300
|
}
|
|
301
|
+
case FieldKind.HashSet:
|
|
302
|
+
{
|
|
303
|
+
if (
|
|
304
|
+
TryAssignParentCollectionFast(
|
|
305
|
+
component,
|
|
306
|
+
root,
|
|
307
|
+
field,
|
|
308
|
+
filters,
|
|
309
|
+
out bool assignedAny
|
|
310
|
+
)
|
|
311
|
+
)
|
|
312
|
+
{
|
|
313
|
+
foundParent = assignedAny;
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
194
316
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
field.attribute,
|
|
207
|
-
field.isInterface,
|
|
208
|
-
parentComponents
|
|
209
|
-
);
|
|
317
|
+
using PooledResource<List<Component>> parentComponentBuffer =
|
|
318
|
+
Buffers<Component>.List.Get(
|
|
319
|
+
out List<Component> parentComponents
|
|
320
|
+
);
|
|
321
|
+
GetParentComponents(
|
|
322
|
+
root,
|
|
323
|
+
field.elementType,
|
|
324
|
+
field.attribute,
|
|
325
|
+
field.isInterface,
|
|
326
|
+
parentComponents
|
|
327
|
+
);
|
|
210
328
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
329
|
+
int filteredCount = FilterComponentsInPlace(
|
|
330
|
+
parentComponents,
|
|
331
|
+
filters,
|
|
332
|
+
field.attribute,
|
|
333
|
+
field.elementType,
|
|
334
|
+
field.isInterface,
|
|
335
|
+
filterDisabledComponents: false
|
|
336
|
+
);
|
|
219
337
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
338
|
+
object instance = field.GetValue(component);
|
|
339
|
+
if (instance != null && field.hashSetClearer != null)
|
|
340
|
+
{
|
|
341
|
+
field.hashSetClearer(instance);
|
|
342
|
+
}
|
|
343
|
+
else
|
|
344
|
+
{
|
|
345
|
+
instance = field.hashSetCreator(filteredCount);
|
|
346
|
+
field.SetValue(component, instance);
|
|
347
|
+
}
|
|
225
348
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
default:
|
|
231
|
-
{
|
|
232
|
-
foundParent = TryGetFirstParentComponent(
|
|
233
|
-
root,
|
|
234
|
-
field.elementType,
|
|
235
|
-
field.attribute,
|
|
236
|
-
field.isInterface,
|
|
237
|
-
out Component parentComponent
|
|
238
|
-
);
|
|
349
|
+
for (int i = 0; i < filteredCount; ++i)
|
|
350
|
+
{
|
|
351
|
+
field.hashSetAdder(instance, parentComponents[i]);
|
|
352
|
+
}
|
|
239
353
|
|
|
240
|
-
|
|
354
|
+
foundParent = filteredCount > 0;
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
default:
|
|
241
358
|
{
|
|
242
|
-
|
|
359
|
+
foundParent = false;
|
|
360
|
+
break;
|
|
243
361
|
}
|
|
244
|
-
|
|
245
|
-
break;
|
|
246
362
|
}
|
|
247
363
|
}
|
|
364
|
+
|
|
365
|
+
if (!foundParent)
|
|
366
|
+
{
|
|
367
|
+
LogMissingComponentError(component, field, "parent");
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
internal static FieldMetadata<ParentComponentAttribute>[] GetOrCreateFields(Type type)
|
|
374
|
+
{
|
|
375
|
+
return FieldsByType.GetOrAdd(type, t => GetFieldMetadata<ParentComponentAttribute>(t));
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
private static bool TryAssignParentCollectionFast(
|
|
379
|
+
Component component,
|
|
380
|
+
Transform root,
|
|
381
|
+
FieldMetadata<ParentComponentAttribute> metadata,
|
|
382
|
+
FilterParameters filters,
|
|
383
|
+
out bool assignedAny
|
|
384
|
+
)
|
|
385
|
+
{
|
|
386
|
+
assignedAny = false;
|
|
387
|
+
ParentComponentAttribute attribute = metadata.attribute;
|
|
388
|
+
if (
|
|
389
|
+
metadata.isInterface
|
|
390
|
+
|| filters.RequiresPostProcessing
|
|
391
|
+
|| attribute.MaxDepth > 0
|
|
392
|
+
|| root == null
|
|
393
|
+
)
|
|
394
|
+
{
|
|
395
|
+
#if UNITY_EDITOR && UNITY_2020_2_OR_NEWER
|
|
396
|
+
ParentFallbackMarker.Begin();
|
|
397
|
+
ParentFallbackMarker.End();
|
|
398
|
+
#endif
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
#if UNITY_EDITOR && UNITY_2020_2_OR_NEWER
|
|
403
|
+
using (ParentFastPathMarker.Auto())
|
|
404
|
+
#endif
|
|
405
|
+
{
|
|
406
|
+
Array parents = ParentComponentFastInvoker.GetArray(
|
|
407
|
+
root,
|
|
408
|
+
metadata.elementType,
|
|
409
|
+
attribute.IncludeInactive
|
|
410
|
+
);
|
|
411
|
+
|
|
412
|
+
Array filtered = FilterParentArray(metadata, parents);
|
|
413
|
+
assignedAny = AssignParentComponentsFromArray(component, metadata, filtered);
|
|
414
|
+
return true;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
private static Array FilterParentArray(
|
|
419
|
+
FieldMetadata<ParentComponentAttribute> metadata,
|
|
420
|
+
Array source
|
|
421
|
+
)
|
|
422
|
+
{
|
|
423
|
+
Type elementType = metadata.elementType;
|
|
424
|
+
if (source == null || source.Length == 0)
|
|
425
|
+
{
|
|
426
|
+
return Array.CreateInstance(elementType, 0);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
int maxCount = metadata.attribute.MaxCount;
|
|
430
|
+
if (maxCount <= 0)
|
|
431
|
+
{
|
|
432
|
+
return source;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
int limit = Math.Min(maxCount, source.Length);
|
|
436
|
+
Array staged = Array.CreateInstance(elementType, limit);
|
|
437
|
+
int writeIndex = 0;
|
|
438
|
+
|
|
439
|
+
for (int i = 0; i < source.Length && writeIndex < limit; ++i)
|
|
440
|
+
{
|
|
441
|
+
Component candidate = source.GetValue(i) as Component;
|
|
442
|
+
if (candidate == null)
|
|
443
|
+
{
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
staged.SetValue(candidate, writeIndex++);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (writeIndex == staged.Length)
|
|
451
|
+
{
|
|
452
|
+
return staged;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
Array result = Array.CreateInstance(elementType, writeIndex);
|
|
456
|
+
if (writeIndex > 0)
|
|
457
|
+
{
|
|
458
|
+
Array.Copy(staged, 0, result, 0, writeIndex);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return result;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
private static bool AssignParentComponentsFromArray(
|
|
465
|
+
Component component,
|
|
466
|
+
FieldMetadata<ParentComponentAttribute> metadata,
|
|
467
|
+
Array parents
|
|
468
|
+
)
|
|
469
|
+
{
|
|
470
|
+
if (parents == null)
|
|
471
|
+
{
|
|
472
|
+
parents = Array.CreateInstance(metadata.elementType, 0);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
int count = parents.Length;
|
|
476
|
+
|
|
477
|
+
switch (metadata.kind)
|
|
478
|
+
{
|
|
479
|
+
case FieldKind.Array:
|
|
480
|
+
{
|
|
481
|
+
Array instance = metadata.arrayCreator(count);
|
|
482
|
+
for (int i = 0; i < count; ++i)
|
|
483
|
+
{
|
|
484
|
+
instance.SetValue(parents.GetValue(i), i);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
metadata.SetValue(component, instance);
|
|
488
|
+
return count > 0;
|
|
248
489
|
}
|
|
490
|
+
case FieldKind.List:
|
|
491
|
+
{
|
|
492
|
+
if (metadata.GetValue(component) is IList list)
|
|
493
|
+
{
|
|
494
|
+
list.Clear();
|
|
495
|
+
}
|
|
496
|
+
else
|
|
497
|
+
{
|
|
498
|
+
list = metadata.listCreator(count);
|
|
499
|
+
metadata.SetValue(component, list);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
for (int i = 0; i < count; ++i)
|
|
503
|
+
{
|
|
504
|
+
list.Add(parents.GetValue(i));
|
|
505
|
+
}
|
|
249
506
|
|
|
250
|
-
|
|
507
|
+
return count > 0;
|
|
508
|
+
}
|
|
509
|
+
case FieldKind.HashSet:
|
|
251
510
|
{
|
|
252
|
-
|
|
511
|
+
object hashSet = metadata.GetValue(component);
|
|
512
|
+
if (hashSet != null && metadata.hashSetClearer != null)
|
|
513
|
+
{
|
|
514
|
+
metadata.hashSetClearer(hashSet);
|
|
515
|
+
}
|
|
516
|
+
else
|
|
517
|
+
{
|
|
518
|
+
hashSet = metadata.hashSetCreator(count);
|
|
519
|
+
metadata.SetValue(component, hashSet);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
for (int i = 0; i < count; ++i)
|
|
523
|
+
{
|
|
524
|
+
metadata.hashSetAdder(hashSet, parents.GetValue(i));
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return count > 0;
|
|
528
|
+
}
|
|
529
|
+
default:
|
|
530
|
+
{
|
|
531
|
+
return false;
|
|
253
532
|
}
|
|
254
533
|
}
|
|
255
534
|
}
|
|
@@ -318,22 +597,57 @@ namespace WallstopStudios.UnityHelpers.Core.Attributes
|
|
|
318
597
|
return buffer;
|
|
319
598
|
}
|
|
320
599
|
|
|
600
|
+
private static bool TryAssignParentSingleFast(
|
|
601
|
+
Transform root,
|
|
602
|
+
FieldMetadata<ParentComponentAttribute> metadata,
|
|
603
|
+
FilterParameters filters,
|
|
604
|
+
out Component parentComponent
|
|
605
|
+
)
|
|
606
|
+
{
|
|
607
|
+
parentComponent = null;
|
|
608
|
+
|
|
609
|
+
if (
|
|
610
|
+
root == null
|
|
611
|
+
|| metadata.isInterface
|
|
612
|
+
|| filters.RequiresPostProcessing
|
|
613
|
+
|| metadata.attribute.IncludeInactive
|
|
614
|
+
|| metadata.attribute.MaxDepth > 0
|
|
615
|
+
)
|
|
616
|
+
{
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
Component candidate = root.GetComponentInParent(metadata.elementType);
|
|
621
|
+
if (candidate == null)
|
|
622
|
+
{
|
|
623
|
+
return false;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
parentComponent = candidate;
|
|
627
|
+
return true;
|
|
628
|
+
}
|
|
629
|
+
|
|
321
630
|
private static bool TryGetFirstParentComponent(
|
|
322
631
|
Transform root,
|
|
632
|
+
FilterParameters filters,
|
|
323
633
|
Type elementType,
|
|
324
634
|
ParentComponentAttribute attribute,
|
|
325
635
|
bool isInterface,
|
|
326
636
|
out Component result
|
|
327
637
|
)
|
|
328
638
|
{
|
|
329
|
-
FilterParameters filters = new(attribute);
|
|
330
639
|
Transform current = root;
|
|
331
640
|
int depth = 0;
|
|
332
641
|
int maxDepth = attribute.MaxDepth > 0 ? attribute.MaxDepth : int.MaxValue;
|
|
333
642
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
643
|
+
bool needsScratch = isInterface || filters.RequiresPostProcessing;
|
|
644
|
+
List<Component> components = null;
|
|
645
|
+
PooledResource<List<Component>> scratch = default;
|
|
646
|
+
if (needsScratch)
|
|
647
|
+
{
|
|
648
|
+
scratch = Buffers<Component>.List.Get(out components);
|
|
649
|
+
}
|
|
650
|
+
|
|
337
651
|
while (current != null && depth < maxDepth)
|
|
338
652
|
{
|
|
339
653
|
if (
|
|
@@ -349,6 +663,10 @@ namespace WallstopStudios.UnityHelpers.Core.Attributes
|
|
|
349
663
|
)
|
|
350
664
|
)
|
|
351
665
|
{
|
|
666
|
+
if (needsScratch)
|
|
667
|
+
{
|
|
668
|
+
scratch.Dispose();
|
|
669
|
+
}
|
|
352
670
|
result = resolved;
|
|
353
671
|
return true;
|
|
354
672
|
}
|
|
@@ -357,6 +675,11 @@ namespace WallstopStudios.UnityHelpers.Core.Attributes
|
|
|
357
675
|
depth++;
|
|
358
676
|
}
|
|
359
677
|
|
|
678
|
+
if (needsScratch)
|
|
679
|
+
{
|
|
680
|
+
scratch.Dispose();
|
|
681
|
+
}
|
|
682
|
+
|
|
360
683
|
result = null;
|
|
361
684
|
return false;
|
|
362
685
|
}
|
|
@@ -373,4 +696,55 @@ namespace WallstopStudios.UnityHelpers.Core.Attributes
|
|
|
373
696
|
return current == target ? depth : int.MaxValue;
|
|
374
697
|
}
|
|
375
698
|
}
|
|
699
|
+
|
|
700
|
+
internal static class ParentComponentFastInvoker
|
|
701
|
+
{
|
|
702
|
+
private static readonly Dictionary<Type, Func<Component, bool, Array>> ArrayGetters = new();
|
|
703
|
+
|
|
704
|
+
private static readonly MethodInfo GetComponentsInParentGeneric = typeof(Component)
|
|
705
|
+
.GetMethods(BindingFlags.Instance | BindingFlags.Public)
|
|
706
|
+
.First(method =>
|
|
707
|
+
method.Name == nameof(Component.GetComponentsInParent)
|
|
708
|
+
&& method.IsGenericMethodDefinition
|
|
709
|
+
&& method.GetParameters().Length == 1
|
|
710
|
+
&& method.GetParameters()[0].ParameterType == typeof(bool)
|
|
711
|
+
);
|
|
712
|
+
|
|
713
|
+
internal static Array GetArray(Component component, Type elementType, bool includeInactive)
|
|
714
|
+
{
|
|
715
|
+
if (!ArrayGetters.TryGetValue(elementType, out Func<Component, bool, Array> getter))
|
|
716
|
+
{
|
|
717
|
+
getter = CreateArrayGetter(elementType);
|
|
718
|
+
ArrayGetters[elementType] = getter;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
return getter(component, includeInactive);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
private static Func<Component, bool, Array> CreateArrayGetter(Type elementType)
|
|
725
|
+
{
|
|
726
|
+
MethodInfo closedMethod = GetComponentsInParentGeneric.MakeGenericMethod(elementType);
|
|
727
|
+
ParameterExpression componentParameter = Expression.Parameter(
|
|
728
|
+
typeof(Component),
|
|
729
|
+
"component"
|
|
730
|
+
);
|
|
731
|
+
ParameterExpression includeInactiveParameter = Expression.Parameter(
|
|
732
|
+
typeof(bool),
|
|
733
|
+
"includeInactive"
|
|
734
|
+
);
|
|
735
|
+
MethodCallExpression invoke = Expression.Call(
|
|
736
|
+
componentParameter,
|
|
737
|
+
closedMethod,
|
|
738
|
+
includeInactiveParameter
|
|
739
|
+
);
|
|
740
|
+
UnaryExpression convert = Expression.Convert(invoke, typeof(Array));
|
|
741
|
+
return Expression
|
|
742
|
+
.Lambda<Func<Component, bool, Array>>(
|
|
743
|
+
convert,
|
|
744
|
+
componentParameter,
|
|
745
|
+
includeInactiveParameter
|
|
746
|
+
)
|
|
747
|
+
.Compile();
|
|
748
|
+
}
|
|
749
|
+
}
|
|
376
750
|
}
|