com.wallstop-studios.unity-helpers 2.0.0-rc26 → 2.0.0-rc27
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/README.md +19 -1
- package/Runtime/Core/Attributes/ChildComponentAttribute.cs +24 -18
- package/Runtime/Core/Attributes/ParentComponent.cs +36 -30
- package/Runtime/Core/Attributes/SiblingComponentAttribute.cs +20 -12
- package/Runtime/Core/Helper/ReflectionHelpers.cs +152 -0
- package/Runtime/Core/Helper/ReflectionHelpers.cs.meta +3 -0
- package/Tests/Runtime/Components/RelationalComponentTester.cs +34 -0
- package/Tests/Runtime/Components/RelationalComponentTester.cs.meta +3 -0
- package/Tests/Runtime/Components.meta +3 -0
- package/Tests/Runtime/Performance/RelationComponentPerformanceTests.cs +37 -0
- package/Tests/Runtime/Performance/RelationComponentPerformanceTests.cs.meta +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
# A Grab-Bag
|
|
2
2
|
Various Unity Helpers. Includes many deterministic, seedable random number generators.
|
|
3
3
|
|
|
4
|
-
#
|
|
4
|
+
# Compatibility
|
|
5
|
+
| Platform | Compatible |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| Unity 2021 | Likely, but untested |
|
|
8
|
+
| Unity 2022 | ✓ |
|
|
9
|
+
| Unity 2023 | ✓ |
|
|
10
|
+
| Unity 6 | ✓ |
|
|
11
|
+
| URP | ✓ |
|
|
12
|
+
| HDRP | ✓ |
|
|
13
|
+
|
|
14
|
+
# Installation
|
|
15
|
+
|
|
16
|
+
## To Install as Unity Package
|
|
5
17
|
1. Open Unity Package Manager
|
|
6
18
|
2. (Optional) Enable Pre-release packages to get the latest, cutting-edge builds
|
|
7
19
|
3. Open the Advanced Package Settings
|
|
@@ -11,6 +23,12 @@ Various Unity Helpers. Includes many deterministic, seedable random number gener
|
|
|
11
23
|
- Scope(s): `com.wallstop-studios.unity-helpers`
|
|
12
24
|
5. Resolve the latest `com.wallstop-studios.unity-helpers`
|
|
13
25
|
|
|
26
|
+
## From Source
|
|
27
|
+
Grab a copy of this repo (either `git clone` or [download a zip of the source](https://github.com/wallstop/unity-helpers/archive/refs/heads/main.zip)) and copy the contents to your project's `Assets` folder.
|
|
28
|
+
|
|
29
|
+
## From Releases
|
|
30
|
+
Check out the latest [Releases](https://github.com/wallstop/unity-helpers/releases) to grab the Unity Package and import to your project.
|
|
31
|
+
|
|
14
32
|
# Package Contents
|
|
15
33
|
- Random Number Generators
|
|
16
34
|
- Spatial Trees
|
|
@@ -20,12 +20,15 @@
|
|
|
20
20
|
|
|
21
21
|
public static class ChildComponentExtensions
|
|
22
22
|
{
|
|
23
|
-
private static readonly Dictionary<
|
|
23
|
+
private static readonly Dictionary<
|
|
24
|
+
Type,
|
|
25
|
+
(FieldInfo field, Action<object, object> setter)[]
|
|
26
|
+
> FieldsByType = new();
|
|
24
27
|
|
|
25
28
|
public static void AssignChildComponents(this Component component)
|
|
26
29
|
{
|
|
27
30
|
Type componentType = component.GetType();
|
|
28
|
-
FieldInfo[] fields = FieldsByType.GetOrAdd(
|
|
31
|
+
(FieldInfo field, Action<object, object> setter)[] fields = FieldsByType.GetOrAdd(
|
|
29
32
|
componentType,
|
|
30
33
|
type =>
|
|
31
34
|
{
|
|
@@ -34,11 +37,12 @@
|
|
|
34
37
|
);
|
|
35
38
|
return fields
|
|
36
39
|
.Where(field => Attribute.IsDefined(field, typeof(ChildComponentAttribute)))
|
|
40
|
+
.Select(field => (field, ReflectionHelpers.CreateFieldSetter(type, field)))
|
|
37
41
|
.ToArray();
|
|
38
42
|
}
|
|
39
43
|
);
|
|
40
44
|
|
|
41
|
-
foreach (FieldInfo field in fields)
|
|
45
|
+
foreach ((FieldInfo field, Action<object, object> setter) in fields)
|
|
42
46
|
{
|
|
43
47
|
Type fieldType = field.FieldType;
|
|
44
48
|
bool isArray = fieldType.IsArray;
|
|
@@ -59,12 +63,12 @@
|
|
|
59
63
|
|
|
60
64
|
foundChild = 0 < children.Count;
|
|
61
65
|
|
|
62
|
-
Array correctTypedArray =
|
|
66
|
+
Array correctTypedArray = ReflectionHelpers.CreateArray(
|
|
63
67
|
childComponentType,
|
|
64
68
|
children.Count
|
|
65
69
|
);
|
|
66
70
|
Array.Copy(children.ToArray(), correctTypedArray, children.Count);
|
|
67
|
-
|
|
71
|
+
setter(component, correctTypedArray);
|
|
68
72
|
}
|
|
69
73
|
else if (
|
|
70
74
|
fieldType.IsGenericType
|
|
@@ -72,11 +76,8 @@
|
|
|
72
76
|
)
|
|
73
77
|
{
|
|
74
78
|
childComponentType = fieldType.GenericTypeArguments[0];
|
|
75
|
-
Type constructedListType = typeof(List<>).MakeGenericType(
|
|
76
|
-
childComponentType
|
|
77
|
-
);
|
|
78
|
-
IList instance = (IList)Activator.CreateInstance(constructedListType);
|
|
79
79
|
|
|
80
|
+
IList instance = ReflectionHelpers.CreateList(childComponentType);
|
|
80
81
|
foundChild = false;
|
|
81
82
|
foreach (
|
|
82
83
|
Component childComponent in component
|
|
@@ -90,7 +91,7 @@
|
|
|
90
91
|
foundChild = true;
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
|
|
94
|
+
setter(component, instance);
|
|
94
95
|
}
|
|
95
96
|
else
|
|
96
97
|
{
|
|
@@ -107,7 +108,7 @@
|
|
|
107
108
|
}
|
|
108
109
|
if (foundChild)
|
|
109
110
|
{
|
|
110
|
-
|
|
111
|
+
setter(component, childComponent);
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
}
|
|
@@ -121,12 +122,12 @@
|
|
|
121
122
|
);
|
|
122
123
|
foundChild = 0 < childComponents.Length;
|
|
123
124
|
|
|
124
|
-
Array correctTypedArray =
|
|
125
|
+
Array correctTypedArray = ReflectionHelpers.CreateArray(
|
|
125
126
|
childComponentType,
|
|
126
127
|
childComponents.Length
|
|
127
128
|
);
|
|
128
129
|
Array.Copy(childComponents, correctTypedArray, childComponents.Length);
|
|
129
|
-
|
|
130
|
+
setter(component, correctTypedArray);
|
|
130
131
|
}
|
|
131
132
|
else if (
|
|
132
133
|
fieldType.IsGenericType
|
|
@@ -134,11 +135,16 @@
|
|
|
134
135
|
)
|
|
135
136
|
{
|
|
136
137
|
childComponentType = fieldType.GenericTypeArguments[0];
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
|
|
139
|
+
Component[] children = component.GetComponentsInChildren(
|
|
140
|
+
childComponentType,
|
|
141
|
+
true
|
|
139
142
|
);
|
|
140
|
-
IList instance = (IList)Activator.CreateInstance(constructedListType);
|
|
141
143
|
|
|
144
|
+
IList instance = ReflectionHelpers.CreateList(
|
|
145
|
+
childComponentType,
|
|
146
|
+
children.Length
|
|
147
|
+
);
|
|
142
148
|
foundChild = false;
|
|
143
149
|
foreach (
|
|
144
150
|
Component childComponent in component.GetComponentsInChildren(
|
|
@@ -151,7 +157,7 @@
|
|
|
151
157
|
foundChild = true;
|
|
152
158
|
}
|
|
153
159
|
|
|
154
|
-
|
|
160
|
+
setter(component, instance);
|
|
155
161
|
}
|
|
156
162
|
else
|
|
157
163
|
{
|
|
@@ -162,7 +168,7 @@
|
|
|
162
168
|
foundChild = childComponent != null;
|
|
163
169
|
if (foundChild)
|
|
164
170
|
{
|
|
165
|
-
|
|
171
|
+
setter(component, childComponent);
|
|
166
172
|
}
|
|
167
173
|
}
|
|
168
174
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
using System.Linq;
|
|
7
7
|
using System.Reflection;
|
|
8
8
|
using Extension;
|
|
9
|
+
using Helper;
|
|
9
10
|
using JetBrains.Annotations;
|
|
10
11
|
using UnityEngine;
|
|
11
12
|
|
|
@@ -19,12 +20,15 @@
|
|
|
19
20
|
|
|
20
21
|
public static class ParentComponentExtensions
|
|
21
22
|
{
|
|
22
|
-
private static readonly Dictionary<
|
|
23
|
+
private static readonly Dictionary<
|
|
24
|
+
Type,
|
|
25
|
+
(FieldInfo field, Action<object, object> setter)[]
|
|
26
|
+
> FieldsByType = new();
|
|
23
27
|
|
|
24
28
|
public static void AssignParentComponents(this Component component)
|
|
25
29
|
{
|
|
26
30
|
Type componentType = component.GetType();
|
|
27
|
-
FieldInfo[] fields = FieldsByType.GetOrAdd(
|
|
31
|
+
(FieldInfo field, Action<object, object> setter)[] fields = FieldsByType.GetOrAdd(
|
|
28
32
|
componentType,
|
|
29
33
|
type =>
|
|
30
34
|
{
|
|
@@ -35,11 +39,12 @@
|
|
|
35
39
|
.Where(field =>
|
|
36
40
|
Attribute.IsDefined(field, typeof(ParentComponentAttribute))
|
|
37
41
|
)
|
|
42
|
+
.Select(field => (field, ReflectionHelpers.CreateFieldSetter(type, field)))
|
|
38
43
|
.ToArray();
|
|
39
44
|
}
|
|
40
45
|
);
|
|
41
46
|
|
|
42
|
-
foreach (FieldInfo field in fields)
|
|
47
|
+
foreach ((FieldInfo field, Action<object, object> setter) in fields)
|
|
43
48
|
{
|
|
44
49
|
Type fieldType = field.FieldType;
|
|
45
50
|
bool isArray = fieldType.IsArray;
|
|
@@ -61,12 +66,12 @@
|
|
|
61
66
|
);
|
|
62
67
|
foundParent = 0 < parentComponents.Length;
|
|
63
68
|
|
|
64
|
-
Array correctTypedArray =
|
|
69
|
+
Array correctTypedArray = ReflectionHelpers.CreateArray(
|
|
65
70
|
parentComponentType,
|
|
66
71
|
parentComponents.Length
|
|
67
72
|
);
|
|
68
73
|
Array.Copy(parentComponents, correctTypedArray, parentComponents.Length);
|
|
69
|
-
|
|
74
|
+
setter(component, correctTypedArray);
|
|
70
75
|
}
|
|
71
76
|
else if (
|
|
72
77
|
fieldType.IsGenericType
|
|
@@ -74,24 +79,25 @@
|
|
|
74
79
|
)
|
|
75
80
|
{
|
|
76
81
|
parentComponentType = fieldType.GenericTypeArguments[0];
|
|
77
|
-
|
|
78
|
-
|
|
82
|
+
|
|
83
|
+
Component[] parents = parent.GetComponentsInParent(
|
|
84
|
+
parentComponentType,
|
|
85
|
+
true
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
IList instance = ReflectionHelpers.CreateList(
|
|
89
|
+
parentComponentType,
|
|
90
|
+
parents.Length
|
|
79
91
|
);
|
|
80
|
-
IList instance = (IList)Activator.CreateInstance(constructedListType);
|
|
81
92
|
|
|
82
93
|
foundParent = false;
|
|
83
|
-
foreach (
|
|
84
|
-
Component parentComponent in parent.GetComponentsInParent(
|
|
85
|
-
parentComponentType,
|
|
86
|
-
true
|
|
87
|
-
)
|
|
88
|
-
)
|
|
94
|
+
foreach (Component parentComponent in parents)
|
|
89
95
|
{
|
|
90
96
|
instance.Add(parentComponent);
|
|
91
97
|
foundParent = true;
|
|
92
98
|
}
|
|
93
99
|
|
|
94
|
-
|
|
100
|
+
setter(component, instance);
|
|
95
101
|
}
|
|
96
102
|
else
|
|
97
103
|
{
|
|
@@ -102,7 +108,7 @@
|
|
|
102
108
|
foundParent = childComponent != null;
|
|
103
109
|
if (foundParent)
|
|
104
110
|
{
|
|
105
|
-
|
|
111
|
+
setter(component, childComponent);
|
|
106
112
|
}
|
|
107
113
|
}
|
|
108
114
|
}
|
|
@@ -116,12 +122,12 @@
|
|
|
116
122
|
);
|
|
117
123
|
foundParent = 0 < parentComponents.Length;
|
|
118
124
|
|
|
119
|
-
Array correctTypedArray =
|
|
125
|
+
Array correctTypedArray = ReflectionHelpers.CreateArray(
|
|
120
126
|
parentComponentType,
|
|
121
127
|
parentComponents.Length
|
|
122
128
|
);
|
|
123
129
|
Array.Copy(parentComponents, correctTypedArray, parentComponents.Length);
|
|
124
|
-
|
|
130
|
+
setter(component, correctTypedArray);
|
|
125
131
|
}
|
|
126
132
|
else if (
|
|
127
133
|
fieldType.IsGenericType
|
|
@@ -129,24 +135,24 @@
|
|
|
129
135
|
)
|
|
130
136
|
{
|
|
131
137
|
parentComponentType = fieldType.GenericTypeArguments[0];
|
|
132
|
-
|
|
133
|
-
|
|
138
|
+
|
|
139
|
+
Component[] parents = component.GetComponentsInParent(
|
|
140
|
+
parentComponentType,
|
|
141
|
+
true
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
IList instance = ReflectionHelpers.CreateList(
|
|
145
|
+
parentComponentType,
|
|
146
|
+
parents.Length
|
|
134
147
|
);
|
|
135
|
-
IList instance = (IList)Activator.CreateInstance(constructedListType);
|
|
136
148
|
|
|
137
149
|
foundParent = false;
|
|
138
|
-
foreach (
|
|
139
|
-
Component parentComponent in component.GetComponentsInParent(
|
|
140
|
-
parentComponentType,
|
|
141
|
-
true
|
|
142
|
-
)
|
|
143
|
-
)
|
|
150
|
+
foreach (Component parentComponent in parents)
|
|
144
151
|
{
|
|
145
152
|
instance.Add(parentComponent);
|
|
146
153
|
foundParent = true;
|
|
147
154
|
}
|
|
148
|
-
|
|
149
|
-
field.SetValue(component, instance);
|
|
155
|
+
setter(component, instance);
|
|
150
156
|
}
|
|
151
157
|
else
|
|
152
158
|
{
|
|
@@ -157,7 +163,7 @@
|
|
|
157
163
|
foundParent = childComponent != null;
|
|
158
164
|
if (foundParent)
|
|
159
165
|
{
|
|
160
|
-
|
|
166
|
+
setter(component, childComponent);
|
|
161
167
|
}
|
|
162
168
|
}
|
|
163
169
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
using System.Linq;
|
|
7
7
|
using System.Reflection;
|
|
8
8
|
using Extension;
|
|
9
|
+
using Helper;
|
|
9
10
|
using JetBrains.Annotations;
|
|
10
11
|
using UnityEngine;
|
|
11
12
|
|
|
@@ -18,12 +19,15 @@
|
|
|
18
19
|
|
|
19
20
|
public static class SiblingComponentExtensions
|
|
20
21
|
{
|
|
21
|
-
private static readonly Dictionary<
|
|
22
|
+
private static readonly Dictionary<
|
|
23
|
+
Type,
|
|
24
|
+
(FieldInfo field, Action<object, object> setter)[]
|
|
25
|
+
> FieldsByType = new();
|
|
22
26
|
|
|
23
27
|
public static void AssignSiblingComponents(this Component component)
|
|
24
28
|
{
|
|
25
29
|
Type componentType = component.GetType();
|
|
26
|
-
FieldInfo[] fields = FieldsByType.GetOrAdd(
|
|
30
|
+
(FieldInfo field, Action<object, object> setter)[] fields = FieldsByType.GetOrAdd(
|
|
27
31
|
componentType,
|
|
28
32
|
type =>
|
|
29
33
|
{
|
|
@@ -34,11 +38,12 @@
|
|
|
34
38
|
.Where(field =>
|
|
35
39
|
Attribute.IsDefined(field, typeof(SiblingComponentAttribute))
|
|
36
40
|
)
|
|
41
|
+
.Select(field => (field, ReflectionHelpers.CreateFieldSetter(type, field)))
|
|
37
42
|
.ToArray();
|
|
38
43
|
}
|
|
39
44
|
);
|
|
40
45
|
|
|
41
|
-
foreach (FieldInfo field in fields)
|
|
46
|
+
foreach ((FieldInfo field, Action<object, object> setter) in fields)
|
|
42
47
|
{
|
|
43
48
|
Type fieldType = field.FieldType;
|
|
44
49
|
bool isArray = fieldType.IsArray;
|
|
@@ -50,12 +55,12 @@
|
|
|
50
55
|
Component[] siblingComponents = component.GetComponents(siblingComponentType);
|
|
51
56
|
foundSibling = 0 < siblingComponents.Length;
|
|
52
57
|
|
|
53
|
-
Array correctTypedArray =
|
|
58
|
+
Array correctTypedArray = ReflectionHelpers.CreateArray(
|
|
54
59
|
siblingComponentType,
|
|
55
60
|
siblingComponents.Length
|
|
56
61
|
);
|
|
57
62
|
Array.Copy(siblingComponents, correctTypedArray, siblingComponents.Length);
|
|
58
|
-
|
|
63
|
+
setter(component, correctTypedArray);
|
|
59
64
|
}
|
|
60
65
|
else if (
|
|
61
66
|
fieldType.IsGenericType
|
|
@@ -63,19 +68,22 @@
|
|
|
63
68
|
)
|
|
64
69
|
{
|
|
65
70
|
siblingComponentType = fieldType.GenericTypeArguments[0];
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
|
|
72
|
+
Component[] siblings = component.GetComponents(siblingComponentType);
|
|
73
|
+
|
|
74
|
+
IList instance = ReflectionHelpers.CreateList(
|
|
75
|
+
siblingComponentType,
|
|
76
|
+
siblings.Length
|
|
77
|
+
);
|
|
68
78
|
|
|
69
79
|
foundSibling = false;
|
|
70
|
-
foreach (
|
|
71
|
-
Component siblingComponent in component.GetComponents(siblingComponentType)
|
|
72
|
-
)
|
|
80
|
+
foreach (Component siblingComponent in siblings)
|
|
73
81
|
{
|
|
74
82
|
instance.Add(siblingComponent);
|
|
75
83
|
foundSibling = true;
|
|
76
84
|
}
|
|
77
85
|
|
|
78
|
-
|
|
86
|
+
setter(component, instance);
|
|
79
87
|
}
|
|
80
88
|
else
|
|
81
89
|
{
|
|
@@ -87,7 +95,7 @@
|
|
|
87
95
|
)
|
|
88
96
|
{
|
|
89
97
|
foundSibling = true;
|
|
90
|
-
|
|
98
|
+
setter(component, siblingComponent);
|
|
91
99
|
}
|
|
92
100
|
else
|
|
93
101
|
{
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
namespace UnityHelpers.Core.Helper
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Collections;
|
|
5
|
+
using System.Collections.Generic;
|
|
6
|
+
using System.Reflection;
|
|
7
|
+
using System.Reflection.Emit;
|
|
8
|
+
using System.Runtime.CompilerServices;
|
|
9
|
+
using Extension;
|
|
10
|
+
|
|
11
|
+
public static class ReflectionHelpers
|
|
12
|
+
{
|
|
13
|
+
private static readonly Dictionary<Type, Func<int, Array>> ArrayCreators = new();
|
|
14
|
+
private static readonly Dictionary<Type, Func<IList>> ListCreators = new();
|
|
15
|
+
private static readonly Dictionary<Type, Func<int, IList>> ListWithCapacityCreators = new();
|
|
16
|
+
|
|
17
|
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
18
|
+
public static Func<int, Array> GetOrCreateArrayCreator(Type type)
|
|
19
|
+
{
|
|
20
|
+
return ArrayCreators.GetOrAdd(type, elementType => GetArrayCreator(elementType));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
24
|
+
public static Array CreateArray(Type type, int length)
|
|
25
|
+
{
|
|
26
|
+
return GetOrCreateArrayCreator(type).Invoke(length);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
30
|
+
public static IList CreateList(Type elementType, int length)
|
|
31
|
+
{
|
|
32
|
+
return ListWithCapacityCreators
|
|
33
|
+
.GetOrAdd(elementType, type => GetListWithCapacityCreator(type))
|
|
34
|
+
.Invoke(length);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
38
|
+
public static IList CreateList(Type elementType)
|
|
39
|
+
{
|
|
40
|
+
return ListCreators.GetOrAdd(elementType, type => GetListCreator(type)).Invoke();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public static Action<object, object> CreateFieldSetter(Type type, FieldInfo field)
|
|
44
|
+
{
|
|
45
|
+
#if WEB_GL
|
|
46
|
+
return field.SetValue;
|
|
47
|
+
#else
|
|
48
|
+
DynamicMethod dynamicMethod = new(
|
|
49
|
+
$"SetField{field.Name}",
|
|
50
|
+
null,
|
|
51
|
+
new[] { typeof(object), typeof(object) },
|
|
52
|
+
type.Module,
|
|
53
|
+
true
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
ILGenerator il = dynamicMethod.GetILGenerator();
|
|
57
|
+
|
|
58
|
+
il.Emit(OpCodes.Ldarg_0); // Load the object (arg0)
|
|
59
|
+
il.Emit(OpCodes.Castclass, type); // Cast to the actual type
|
|
60
|
+
|
|
61
|
+
il.Emit(OpCodes.Ldarg_1); // Load the value (arg1)
|
|
62
|
+
il.Emit(
|
|
63
|
+
field.FieldType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass,
|
|
64
|
+
field.FieldType
|
|
65
|
+
); // Cast for reference types
|
|
66
|
+
// Unbox if it's a value type
|
|
67
|
+
il.Emit(OpCodes.Stfld, field); // Set the field
|
|
68
|
+
il.Emit(OpCodes.Ret); // Return
|
|
69
|
+
return (Action<object, object>)
|
|
70
|
+
dynamicMethod.CreateDelegate(typeof(Action<object, object>));
|
|
71
|
+
#endif
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public static Func<int, Array> GetArrayCreator(Type elementType)
|
|
75
|
+
{
|
|
76
|
+
#if WEB_GL
|
|
77
|
+
return size => Array.CreateInstance(elementType, size);
|
|
78
|
+
#else
|
|
79
|
+
|
|
80
|
+
DynamicMethod dynamicMethod = new DynamicMethod(
|
|
81
|
+
$"CreateArray{elementType.Namespace}",
|
|
82
|
+
typeof(Array), // Return type: Array
|
|
83
|
+
new[] { typeof(int) }, // Parameter: int (size)
|
|
84
|
+
true
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
ILGenerator il = dynamicMethod.GetILGenerator();
|
|
88
|
+
il.Emit(OpCodes.Ldarg_0); // Load the array size
|
|
89
|
+
il.Emit(OpCodes.Newarr, elementType); // Create a new array of 'type'
|
|
90
|
+
il.Emit(OpCodes.Ret); // Return the array
|
|
91
|
+
return (Func<int, Array>)dynamicMethod.CreateDelegate(typeof(Func<int, Array>));
|
|
92
|
+
#endif
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public static Func<IList> GetListCreator(Type elementType)
|
|
96
|
+
{
|
|
97
|
+
Type listType = typeof(List<>).MakeGenericType(elementType);
|
|
98
|
+
#if WEB_GL
|
|
99
|
+
return () => (IList)Activator.CreateInstance(listType);
|
|
100
|
+
#else
|
|
101
|
+
DynamicMethod dynamicMethod = new DynamicMethod(
|
|
102
|
+
$"CreateList{listType.Name}",
|
|
103
|
+
typeof(IList), // Return type: IList
|
|
104
|
+
Type.EmptyTypes, // No parameters
|
|
105
|
+
true
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
ILGenerator il = dynamicMethod.GetILGenerator();
|
|
109
|
+
ConstructorInfo constructor = listType.GetConstructor(Type.EmptyTypes);
|
|
110
|
+
if (constructor == null)
|
|
111
|
+
{
|
|
112
|
+
throw new ArgumentException(
|
|
113
|
+
$"Type {listType} does not have a parameterless constructor."
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
il.Emit(OpCodes.Newobj, constructor); // Call List<T> constructor
|
|
118
|
+
il.Emit(OpCodes.Ret); // Return the instance
|
|
119
|
+
return (Func<IList>)dynamicMethod.CreateDelegate(typeof(Func<IList>));
|
|
120
|
+
#endif
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public static Func<int, IList> GetListWithCapacityCreator(Type elementType)
|
|
124
|
+
{
|
|
125
|
+
Type listType = typeof(List<>).MakeGenericType(elementType);
|
|
126
|
+
#if WEB_GL
|
|
127
|
+
return _ => (IList)Activator.CreateInstance(listType);
|
|
128
|
+
#else
|
|
129
|
+
DynamicMethod dynamicMethod = new DynamicMethod(
|
|
130
|
+
$"CreateListWithCapacity{listType.Name}",
|
|
131
|
+
typeof(IList), // Return type: IList
|
|
132
|
+
new[] { typeof(int) }, // Parameter: int (size)
|
|
133
|
+
true
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
ILGenerator il = dynamicMethod.GetILGenerator();
|
|
137
|
+
ConstructorInfo constructor = listType.GetConstructor(new[] { typeof(int) });
|
|
138
|
+
if (constructor == null)
|
|
139
|
+
{
|
|
140
|
+
throw new ArgumentException(
|
|
141
|
+
$"Type {listType} does not have a constructor accepting an int."
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
il.Emit(OpCodes.Ldarg_0); // Load capacity argument
|
|
146
|
+
il.Emit(OpCodes.Newobj, constructor); // Call List<T>(int capacity) constructor
|
|
147
|
+
il.Emit(OpCodes.Ret); // Return the instance
|
|
148
|
+
return (Func<int, IList>)dynamicMethod.CreateDelegate(typeof(Func<int, IList>));
|
|
149
|
+
#endif
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
namespace UnityHelpers.Tests.Components
|
|
2
|
+
{
|
|
3
|
+
using Core.Attributes;
|
|
4
|
+
using UnityEngine;
|
|
5
|
+
|
|
6
|
+
[DisallowMultipleComponent]
|
|
7
|
+
[RequireComponent(typeof(SpriteRenderer))]
|
|
8
|
+
[RequireComponent(typeof(BoxCollider2D))]
|
|
9
|
+
[RequireComponent(typeof(BoxCollider2D))]
|
|
10
|
+
[RequireComponent(typeof(PolygonCollider2D))]
|
|
11
|
+
public sealed class RelationalComponentTester : MonoBehaviour
|
|
12
|
+
{
|
|
13
|
+
[SiblingComponent]
|
|
14
|
+
internal SpriteRenderer _spriteRenderer;
|
|
15
|
+
|
|
16
|
+
[SiblingComponent]
|
|
17
|
+
internal Transform _transform;
|
|
18
|
+
|
|
19
|
+
[SiblingComponent]
|
|
20
|
+
internal PolygonCollider2D _polygonCollider;
|
|
21
|
+
|
|
22
|
+
[SiblingComponent]
|
|
23
|
+
internal BoxCollider2D _boxCollider;
|
|
24
|
+
|
|
25
|
+
[ChildComponent]
|
|
26
|
+
internal Collider2D[] _childColliders;
|
|
27
|
+
|
|
28
|
+
[ParentComponent]
|
|
29
|
+
internal Collider2D[] _parentColliders;
|
|
30
|
+
|
|
31
|
+
[SiblingComponent]
|
|
32
|
+
internal Collider2D[] _siblingColliders;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
namespace UnityHelpers.Tests.Performance
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Diagnostics;
|
|
5
|
+
using Components;
|
|
6
|
+
using Core.Attributes;
|
|
7
|
+
using NUnit.Framework;
|
|
8
|
+
using UnityEngine;
|
|
9
|
+
|
|
10
|
+
public sealed class RelationComponentPerformanceTests
|
|
11
|
+
{
|
|
12
|
+
[Test]
|
|
13
|
+
public void RelationalPerformanceTest()
|
|
14
|
+
{
|
|
15
|
+
int count = 0;
|
|
16
|
+
|
|
17
|
+
GameObject go = new("Test", typeof(RelationalComponentTester));
|
|
18
|
+
RelationalComponentTester tester = go.GetComponent<RelationalComponentTester>();
|
|
19
|
+
// Pre-warm
|
|
20
|
+
tester.AssignRelationalComponents();
|
|
21
|
+
|
|
22
|
+
TimeSpan timeout = TimeSpan.FromSeconds(10);
|
|
23
|
+
Stopwatch timer = Stopwatch.StartNew();
|
|
24
|
+
do
|
|
25
|
+
{
|
|
26
|
+
tester.AssignRelationalComponents();
|
|
27
|
+
++count;
|
|
28
|
+
} while (timer.Elapsed < timeout);
|
|
29
|
+
|
|
30
|
+
UnityEngine.Debug.Log($"Averaged {count / timeout.TotalSeconds} operations / second.");
|
|
31
|
+
|
|
32
|
+
Assert.AreNotEqual(0, tester._childColliders.Length);
|
|
33
|
+
Assert.AreNotEqual(0, tester._parentColliders.Length);
|
|
34
|
+
Assert.AreNotEqual(0, tester._siblingColliders.Length);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|