com.wallstop-studios.unity-helpers 2.0.0-rc39 → 2.0.0-rc41
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/.github/workflows/npm-publish.yml +22 -26
- package/Editor/AnimationCopier.cs +25 -2
- package/Editor/AnimationCreator.cs +18 -27
- package/Editor/AnimatorControllerCopier.cs +7 -7
- package/Editor/EnsureTextureSizeWizard.cs +14 -9
- package/Editor/PrefabCheckWizard.cs +1 -1
- package/Editor/Utils/{ReadOnlyPropertyDrawer.cs → DxReadOnlyPropertyDrawer.cs} +2 -2
- package/README.md +37 -1
- package/Runtime/Core/Attributes/ChildComponentAttribute.cs +39 -19
- package/Runtime/Core/Attributes/DxReadOnlyAttribute.cs +6 -0
- package/Runtime/Core/Attributes/ParentComponent.cs +16 -15
- package/Runtime/Core/Attributes/SiblingComponentAttribute.cs +7 -9
- package/Runtime/Core/Helper/Partials/TransformHelpers.cs +26 -0
- package/Runtime/Core/Helper/ReflectionHelpers.cs +167 -22
- package/Tests/Runtime/Components/{RelationalComponentTester.cs → RelationalComponentTesterComplex.cs} +1 -1
- package/Tests/Runtime/Components/RelationalComponentsTesterSimple.cs +40 -0
- package/Tests/Runtime/Components/RelationalComponentsTesterSimple.cs.meta +3 -0
- package/Tests/Runtime/Helper/ReflectionHelperTests.cs +215 -0
- package/Tests/Runtime/Helper/ReflectionHelperTests.cs.meta +3 -0
- package/Tests/Runtime/Performance/RelationComponentPerformanceTests.cs +27 -3
- package/package.json +1 -1
- package/.github/workflows/unity-package.yml +0 -105
- package/Editor/BuildScript.cs +0 -33
- package/Editor/BuildScript.cs.meta +0 -3
- package/Editor/Scenes/SampleScene.unity +0 -221
- package/Editor/Scenes/SampleScene.unity.meta +0 -7
- package/Editor/Scenes.meta +0 -3
- package/Runtime/Core/Attributes/ReadOnlyAttribute.cs +0 -6
- /package/Editor/Utils/{ReadOnlyPropertyDrawer.cs.meta → DxReadOnlyPropertyDrawer.cs.meta} +0 -0
- /package/Runtime/Core/Attributes/{ReadOnlyAttribute.cs.meta → DxReadOnlyAttribute.cs.meta} +0 -0
- /package/Tests/Runtime/Components/{RelationalComponentTester.cs.meta → RelationalComponentTesterComplex.cs.meta} +0 -0
|
@@ -8,22 +8,20 @@
|
|
|
8
8
|
using System.Runtime.CompilerServices;
|
|
9
9
|
using Extension;
|
|
10
10
|
|
|
11
|
+
public delegate void FieldSetter<TInstance, in TValue>(ref TInstance instance, TValue value);
|
|
12
|
+
|
|
11
13
|
public static class ReflectionHelpers
|
|
12
14
|
{
|
|
13
15
|
private static readonly Dictionary<Type, Func<int, Array>> ArrayCreators = new();
|
|
14
16
|
private static readonly Dictionary<Type, Func<IList>> ListCreators = new();
|
|
15
17
|
private static readonly Dictionary<Type, Func<int, IList>> ListWithCapacityCreators = new();
|
|
16
18
|
|
|
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
19
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
24
20
|
public static Array CreateArray(Type type, int length)
|
|
25
21
|
{
|
|
26
|
-
return
|
|
22
|
+
return ArrayCreators
|
|
23
|
+
.GetOrAdd(type, elementType => GetArrayCreator(elementType))
|
|
24
|
+
.Invoke(length);
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
@@ -40,32 +38,180 @@
|
|
|
40
38
|
return ListCreators.GetOrAdd(elementType, type => GetListCreator(type)).Invoke();
|
|
41
39
|
}
|
|
42
40
|
|
|
43
|
-
public static
|
|
41
|
+
public static Func<object, object> GetFieldGetter(FieldInfo field)
|
|
42
|
+
{
|
|
43
|
+
#if WEB_GL
|
|
44
|
+
return field.GetValue;
|
|
45
|
+
#else
|
|
46
|
+
DynamicMethod dynamicMethod = new(
|
|
47
|
+
$"Get{(field.DeclaringType?.Name ?? string.Empty)}{field.Name}",
|
|
48
|
+
typeof(object),
|
|
49
|
+
new[] { typeof(object) },
|
|
50
|
+
field.DeclaringType,
|
|
51
|
+
true
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
ILGenerator il = dynamicMethod.GetILGenerator();
|
|
55
|
+
il.Emit(OpCodes.Ldarg_0);
|
|
56
|
+
il.Emit(
|
|
57
|
+
field.DeclaringType.IsValueType ? OpCodes.Unbox : OpCodes.Castclass,
|
|
58
|
+
field.DeclaringType
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
il.Emit(OpCodes.Ldfld, field);
|
|
62
|
+
|
|
63
|
+
// If the field's type is a value type, box it.
|
|
64
|
+
if (field.FieldType.IsValueType)
|
|
65
|
+
{
|
|
66
|
+
il.Emit(OpCodes.Box, field.FieldType);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
il.Emit(OpCodes.Ret);
|
|
70
|
+
|
|
71
|
+
return (Func<object, object>)dynamicMethod.CreateDelegate(typeof(Func<object, object>));
|
|
72
|
+
#endif
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public static Func<TInstance, TValue> GetFieldGetter<TInstance, TValue>(FieldInfo field)
|
|
76
|
+
{
|
|
77
|
+
#if WEB_GL
|
|
78
|
+
return Getter;
|
|
79
|
+
TValue Getter(TInstance instance)
|
|
80
|
+
{
|
|
81
|
+
return (TValue)field.GetValue(instance);
|
|
82
|
+
}
|
|
83
|
+
#else
|
|
84
|
+
DynamicMethod dynamicMethod = new(
|
|
85
|
+
$"GetGeneric{field.DeclaringType.Name}{field.Name}",
|
|
86
|
+
typeof(TValue),
|
|
87
|
+
new[] { typeof(TInstance) },
|
|
88
|
+
field.DeclaringType,
|
|
89
|
+
true
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
ILGenerator il = dynamicMethod.GetILGenerator();
|
|
93
|
+
|
|
94
|
+
if (!field.IsStatic)
|
|
95
|
+
{
|
|
96
|
+
if (typeof(TInstance).IsValueType)
|
|
97
|
+
{
|
|
98
|
+
il.Emit(OpCodes.Ldarga_S, 0);
|
|
99
|
+
}
|
|
100
|
+
else
|
|
101
|
+
{
|
|
102
|
+
il.Emit(OpCodes.Ldarg_0);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (field.DeclaringType != typeof(TInstance))
|
|
106
|
+
{
|
|
107
|
+
il.Emit(
|
|
108
|
+
field.DeclaringType.IsValueType ? OpCodes.Unbox : OpCodes.Castclass,
|
|
109
|
+
field.DeclaringType
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
il.Emit(OpCodes.Ldfld, field);
|
|
114
|
+
}
|
|
115
|
+
else
|
|
116
|
+
{
|
|
117
|
+
il.Emit(OpCodes.Ldsfld, field);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (field.FieldType.IsValueType)
|
|
121
|
+
{
|
|
122
|
+
if (!typeof(TValue).IsValueType)
|
|
123
|
+
{
|
|
124
|
+
il.Emit(OpCodes.Box, field.FieldType);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else
|
|
128
|
+
{
|
|
129
|
+
if (typeof(TValue).IsValueType)
|
|
130
|
+
{
|
|
131
|
+
il.Emit(OpCodes.Unbox_Any, typeof(TValue));
|
|
132
|
+
}
|
|
133
|
+
else if (typeof(TValue) != field.FieldType)
|
|
134
|
+
{
|
|
135
|
+
il.Emit(OpCodes.Castclass, typeof(TValue));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
il.Emit(OpCodes.Ret);
|
|
140
|
+
return (Func<TInstance, TValue>)
|
|
141
|
+
dynamicMethod.CreateDelegate(typeof(Func<TInstance, TValue>));
|
|
142
|
+
#endif
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public static FieldSetter<TInstance, TValue> GetFieldSetter<TInstance, TValue>(
|
|
146
|
+
FieldInfo field
|
|
147
|
+
)
|
|
148
|
+
{
|
|
149
|
+
#if WEB_GL
|
|
150
|
+
return Setter;
|
|
151
|
+
void Setter(ref TInstance instance, TValue newValue)
|
|
152
|
+
{
|
|
153
|
+
object value = instance;
|
|
154
|
+
field.SetValue(value, newValue);
|
|
155
|
+
instance = (TInstance)value;
|
|
156
|
+
}
|
|
157
|
+
#else
|
|
158
|
+
Type instanceType = field.DeclaringType;
|
|
159
|
+
Type valueType = field.FieldType;
|
|
160
|
+
|
|
161
|
+
DynamicMethod dynamicMethod = new(
|
|
162
|
+
$"SetFieldGeneric{field.DeclaringType.Name}{field.Name}",
|
|
163
|
+
MethodAttributes.Public | MethodAttributes.Static,
|
|
164
|
+
CallingConventions.Standard,
|
|
165
|
+
typeof(void),
|
|
166
|
+
new[] { instanceType.MakeByRefType(), valueType },
|
|
167
|
+
field.Module,
|
|
168
|
+
true
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
ILGenerator il = dynamicMethod.GetILGenerator();
|
|
172
|
+
il.Emit(OpCodes.Ldarg_0);
|
|
173
|
+
if (!instanceType.IsValueType)
|
|
174
|
+
{
|
|
175
|
+
il.Emit(OpCodes.Ldind_Ref);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
il.Emit(OpCodes.Ldarg_1);
|
|
179
|
+
il.Emit(OpCodes.Stfld, field);
|
|
180
|
+
il.Emit(OpCodes.Ret);
|
|
181
|
+
|
|
182
|
+
Type delegateType = typeof(FieldSetter<,>).MakeGenericType(instanceType, valueType);
|
|
183
|
+
return (FieldSetter<TInstance, TValue>)dynamicMethod.CreateDelegate(delegateType);
|
|
184
|
+
#endif
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
public static Action<object, object> GetFieldSetter(FieldInfo field)
|
|
44
188
|
{
|
|
45
189
|
#if WEB_GL
|
|
46
190
|
return field.SetValue;
|
|
47
191
|
#else
|
|
48
192
|
DynamicMethod dynamicMethod = new(
|
|
49
|
-
$"SetField{field.Name}",
|
|
193
|
+
$"SetField{field.DeclaringType.Name}{field.Name}",
|
|
50
194
|
null,
|
|
51
195
|
new[] { typeof(object), typeof(object) },
|
|
52
|
-
|
|
196
|
+
field.DeclaringType.Module,
|
|
53
197
|
true
|
|
54
198
|
);
|
|
55
199
|
|
|
56
200
|
ILGenerator il = dynamicMethod.GetILGenerator();
|
|
57
201
|
|
|
58
|
-
il.Emit(OpCodes.Ldarg_0);
|
|
59
|
-
il.Emit(
|
|
202
|
+
il.Emit(OpCodes.Ldarg_0);
|
|
203
|
+
il.Emit(
|
|
204
|
+
field.DeclaringType.IsValueType ? OpCodes.Unbox : OpCodes.Castclass,
|
|
205
|
+
field.DeclaringType
|
|
206
|
+
);
|
|
60
207
|
|
|
61
|
-
il.Emit(OpCodes.Ldarg_1);
|
|
208
|
+
il.Emit(OpCodes.Ldarg_1);
|
|
62
209
|
il.Emit(
|
|
63
210
|
field.FieldType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass,
|
|
64
211
|
field.FieldType
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
il.Emit(OpCodes.
|
|
68
|
-
il.Emit(OpCodes.Ret); // Return
|
|
212
|
+
);
|
|
213
|
+
il.Emit(OpCodes.Stfld, field);
|
|
214
|
+
il.Emit(OpCodes.Ret);
|
|
69
215
|
return (Action<object, object>)
|
|
70
216
|
dynamicMethod.CreateDelegate(typeof(Action<object, object>));
|
|
71
217
|
#endif
|
|
@@ -76,9 +222,8 @@
|
|
|
76
222
|
#if WEB_GL
|
|
77
223
|
return size => Array.CreateInstance(elementType, size);
|
|
78
224
|
#else
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
$"CreateArray{elementType.Namespace}",
|
|
225
|
+
DynamicMethod dynamicMethod = new(
|
|
226
|
+
$"CreateArray{elementType.Name}",
|
|
82
227
|
typeof(Array), // Return type: Array
|
|
83
228
|
new[] { typeof(int) }, // Parameter: int (size)
|
|
84
229
|
true
|
|
@@ -98,7 +243,7 @@
|
|
|
98
243
|
#if WEB_GL
|
|
99
244
|
return () => (IList)Activator.CreateInstance(listType);
|
|
100
245
|
#else
|
|
101
|
-
DynamicMethod dynamicMethod = new
|
|
246
|
+
DynamicMethod dynamicMethod = new(
|
|
102
247
|
$"CreateList{listType.Name}",
|
|
103
248
|
typeof(IList), // Return type: IList
|
|
104
249
|
Type.EmptyTypes, // No parameters
|
|
@@ -126,7 +271,7 @@
|
|
|
126
271
|
#if WEB_GL
|
|
127
272
|
return _ => (IList)Activator.CreateInstance(listType);
|
|
128
273
|
#else
|
|
129
|
-
DynamicMethod dynamicMethod = new
|
|
274
|
+
DynamicMethod dynamicMethod = new(
|
|
130
275
|
$"CreateListWithCapacity{listType.Name}",
|
|
131
276
|
typeof(IList), // Return type: IList
|
|
132
277
|
new[] { typeof(int) }, // Parameter: int (size)
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
[RequireComponent(typeof(BoxCollider2D))]
|
|
9
9
|
[RequireComponent(typeof(BoxCollider2D))]
|
|
10
10
|
[RequireComponent(typeof(PolygonCollider2D))]
|
|
11
|
-
public sealed class
|
|
11
|
+
public sealed class RelationalComponentTesterComplex : MonoBehaviour
|
|
12
12
|
{
|
|
13
13
|
[SiblingComponent]
|
|
14
14
|
internal SpriteRenderer _spriteRenderer;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
namespace UnityHelpers.Tests.Components
|
|
2
|
+
{
|
|
3
|
+
namespace UnityHelpers.Tests.Components
|
|
4
|
+
{
|
|
5
|
+
using Core.Attributes;
|
|
6
|
+
using UnityEngine;
|
|
7
|
+
|
|
8
|
+
[DisallowMultipleComponent]
|
|
9
|
+
[RequireComponent(typeof(SpriteRenderer))]
|
|
10
|
+
[RequireComponent(typeof(BoxCollider2D))]
|
|
11
|
+
[RequireComponent(typeof(BoxCollider2D))]
|
|
12
|
+
[RequireComponent(typeof(PolygonCollider2D))]
|
|
13
|
+
public sealed class RelationalComponentTesterSimple : MonoBehaviour
|
|
14
|
+
{
|
|
15
|
+
[SiblingComponent]
|
|
16
|
+
internal SpriteRenderer _spriteRenderer;
|
|
17
|
+
|
|
18
|
+
[SiblingComponent]
|
|
19
|
+
internal Transform _transform;
|
|
20
|
+
|
|
21
|
+
[SiblingComponent]
|
|
22
|
+
internal PolygonCollider2D _polygonCollider;
|
|
23
|
+
|
|
24
|
+
// [ParentComponent]
|
|
25
|
+
// internal PolygonCollider2D _polygonColliderParent;
|
|
26
|
+
|
|
27
|
+
[SiblingComponent]
|
|
28
|
+
internal BoxCollider2D _boxCollider;
|
|
29
|
+
|
|
30
|
+
// [ParentComponent]
|
|
31
|
+
// internal BoxCollider2D _boxColliderParent;
|
|
32
|
+
//
|
|
33
|
+
// [ChildComponent]
|
|
34
|
+
// internal BoxCollider2D _boxColliderChild;
|
|
35
|
+
//
|
|
36
|
+
// [ChildComponent]
|
|
37
|
+
// internal BoxCollider2D _boxColliderParentChild;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
namespace UnityHelpers.Tests.Tests.Runtime.Helper
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Collections;
|
|
5
|
+
using System.Collections.Generic;
|
|
6
|
+
using Core.Helper;
|
|
7
|
+
using NUnit.Framework;
|
|
8
|
+
|
|
9
|
+
public struct TestStruct
|
|
10
|
+
{
|
|
11
|
+
public int intValue;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public sealed class TestClass
|
|
15
|
+
{
|
|
16
|
+
public int intValue;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public sealed class ReflectionHelperTests
|
|
20
|
+
{
|
|
21
|
+
internal const int NumTries = 1_000;
|
|
22
|
+
|
|
23
|
+
private readonly Random _random = new();
|
|
24
|
+
|
|
25
|
+
// TODO: Test on static fields
|
|
26
|
+
[Test]
|
|
27
|
+
public void GetFieldGetterClass()
|
|
28
|
+
{
|
|
29
|
+
TestClass testClass = new();
|
|
30
|
+
Func<object, object> classGetter = ReflectionHelpers.GetFieldGetter(
|
|
31
|
+
typeof(TestClass).GetField(nameof(TestClass.intValue))
|
|
32
|
+
);
|
|
33
|
+
Assert.AreEqual(testClass.intValue, classGetter(testClass));
|
|
34
|
+
for (int i = 0; i < NumTries; ++i)
|
|
35
|
+
{
|
|
36
|
+
testClass.intValue = _random.Next(int.MinValue, int.MaxValue);
|
|
37
|
+
Assert.AreEqual(testClass.intValue, classGetter(testClass));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// TODO: Test on static fields
|
|
42
|
+
[Test]
|
|
43
|
+
public void GetFieldGetterStruct()
|
|
44
|
+
{
|
|
45
|
+
TestStruct testStruct = new();
|
|
46
|
+
Func<object, object> structGetter = ReflectionHelpers.GetFieldGetter(
|
|
47
|
+
typeof(TestStruct).GetField(nameof(TestStruct.intValue))
|
|
48
|
+
);
|
|
49
|
+
Assert.AreEqual(testStruct.intValue, structGetter(testStruct));
|
|
50
|
+
for (int i = 0; i < NumTries; ++i)
|
|
51
|
+
{
|
|
52
|
+
testStruct.intValue = _random.Next(int.MinValue, int.MaxValue);
|
|
53
|
+
Assert.AreEqual(testStruct.intValue, structGetter(testStruct));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// TODO: Test on static fields
|
|
58
|
+
[Test]
|
|
59
|
+
public void GetFieldSetterClass()
|
|
60
|
+
{
|
|
61
|
+
TestClass testClass = new();
|
|
62
|
+
Action<object, object> structSetter = ReflectionHelpers.GetFieldSetter(
|
|
63
|
+
typeof(TestClass).GetField(nameof(TestClass.intValue))
|
|
64
|
+
);
|
|
65
|
+
for (int i = 0; i < NumTries; ++i)
|
|
66
|
+
{
|
|
67
|
+
int expected = _random.Next(int.MinValue, int.MaxValue);
|
|
68
|
+
structSetter(testClass, expected);
|
|
69
|
+
Assert.AreEqual(expected, testClass.intValue);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// TODO: Test on static fields
|
|
74
|
+
[Test]
|
|
75
|
+
public void GetFieldSetterStruct()
|
|
76
|
+
{
|
|
77
|
+
// Need boxing
|
|
78
|
+
object testStruct = new TestStruct();
|
|
79
|
+
Action<object, object> structSetter = ReflectionHelpers.GetFieldSetter(
|
|
80
|
+
typeof(TestStruct).GetField(nameof(TestStruct.intValue))
|
|
81
|
+
);
|
|
82
|
+
for (int i = 0; i < NumTries; ++i)
|
|
83
|
+
{
|
|
84
|
+
int expected = _random.Next(int.MinValue, int.MaxValue);
|
|
85
|
+
structSetter(testStruct, expected);
|
|
86
|
+
Assert.AreEqual(expected, ((TestStruct)testStruct).intValue);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// TODO: Test on static fields
|
|
91
|
+
[Test]
|
|
92
|
+
public void GetFieldSetterClassGeneric()
|
|
93
|
+
{
|
|
94
|
+
TestClass testClass = new();
|
|
95
|
+
FieldSetter<TestClass, int> classSetter = ReflectionHelpers.GetFieldSetter<
|
|
96
|
+
TestClass,
|
|
97
|
+
int
|
|
98
|
+
>(typeof(TestClass).GetField(nameof(TestClass.intValue)));
|
|
99
|
+
for (int i = 0; i < NumTries; ++i)
|
|
100
|
+
{
|
|
101
|
+
int expected = _random.Next(int.MinValue, int.MaxValue);
|
|
102
|
+
classSetter(ref testClass, expected);
|
|
103
|
+
Assert.AreEqual(expected, testClass.intValue);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// TODO: Test on static fields
|
|
108
|
+
[Test]
|
|
109
|
+
public void GetFieldSetterStructGeneric()
|
|
110
|
+
{
|
|
111
|
+
TestStruct testStruct = new();
|
|
112
|
+
FieldSetter<TestStruct, int> structSetter = ReflectionHelpers.GetFieldSetter<
|
|
113
|
+
TestStruct,
|
|
114
|
+
int
|
|
115
|
+
>(typeof(TestStruct).GetField(nameof(TestStruct.intValue)));
|
|
116
|
+
for (int i = 0; i < NumTries; ++i)
|
|
117
|
+
{
|
|
118
|
+
int expected = _random.Next(int.MinValue, int.MaxValue);
|
|
119
|
+
structSetter(ref testStruct, expected);
|
|
120
|
+
Assert.AreEqual(expected, testStruct.intValue);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// TODO: Test on static fields
|
|
125
|
+
[Test]
|
|
126
|
+
public void GetFieldGetterClassGeneric()
|
|
127
|
+
{
|
|
128
|
+
TestClass testClass = new();
|
|
129
|
+
Func<TestClass, int> classGetter = ReflectionHelpers.GetFieldGetter<TestClass, int>(
|
|
130
|
+
typeof(TestClass).GetField(nameof(TestClass.intValue))
|
|
131
|
+
);
|
|
132
|
+
for (int i = 0; i < NumTries; ++i)
|
|
133
|
+
{
|
|
134
|
+
testClass.intValue = _random.Next(int.MinValue, int.MaxValue);
|
|
135
|
+
Assert.AreEqual(testClass.intValue, classGetter(testClass));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// TODO: Test on static fields
|
|
140
|
+
[Test]
|
|
141
|
+
public void GetFieldGetterStructGeneric()
|
|
142
|
+
{
|
|
143
|
+
TestStruct testStruct = new();
|
|
144
|
+
Func<TestStruct, int> structSetter = ReflectionHelpers.GetFieldGetter<TestStruct, int>(
|
|
145
|
+
typeof(TestStruct).GetField(nameof(TestStruct.intValue))
|
|
146
|
+
);
|
|
147
|
+
for (int i = 0; i < NumTries; ++i)
|
|
148
|
+
{
|
|
149
|
+
testStruct.intValue = _random.Next(int.MinValue, int.MaxValue);
|
|
150
|
+
Assert.AreEqual(testStruct.intValue, structSetter(testStruct));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
[Test]
|
|
155
|
+
public void ArrayCreator()
|
|
156
|
+
{
|
|
157
|
+
for (int i = 0; i < NumTries; ++i)
|
|
158
|
+
{
|
|
159
|
+
int count = _random.Next(1_000);
|
|
160
|
+
Array created = ReflectionHelpers.CreateArray(typeof(int), count);
|
|
161
|
+
Assert.AreEqual(count, created.Length);
|
|
162
|
+
Assert.IsTrue(created is int[]);
|
|
163
|
+
int[] typed = (int[])created;
|
|
164
|
+
Assert.AreEqual(count, typed.Length);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
[Test]
|
|
169
|
+
public void ListCreator()
|
|
170
|
+
{
|
|
171
|
+
for (int i = 0; i < NumTries; ++i)
|
|
172
|
+
{
|
|
173
|
+
IList created = ReflectionHelpers.CreateList(typeof(int));
|
|
174
|
+
Assert.AreEqual(0, created.Count);
|
|
175
|
+
Assert.IsTrue(created is List<int>);
|
|
176
|
+
List<int> typedCreated = (List<int>)created;
|
|
177
|
+
int count = _random.Next(50);
|
|
178
|
+
List<int> expected = new();
|
|
179
|
+
for (int j = 0; j < count; ++j)
|
|
180
|
+
{
|
|
181
|
+
int element = _random.Next();
|
|
182
|
+
created.Add(element);
|
|
183
|
+
expected.Add(element);
|
|
184
|
+
Assert.AreEqual(j + 1, created.Count);
|
|
185
|
+
Assert.That(expected, Is.EqualTo(typedCreated));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
[Test]
|
|
191
|
+
public void ListWithSizeCreator()
|
|
192
|
+
{
|
|
193
|
+
for (int i = 0; i < NumTries; ++i)
|
|
194
|
+
{
|
|
195
|
+
int capacity = _random.Next(1_000);
|
|
196
|
+
IList created = ReflectionHelpers.CreateList(typeof(int), capacity);
|
|
197
|
+
Assert.AreEqual(0, created.Count);
|
|
198
|
+
Assert.IsTrue(created is List<int>);
|
|
199
|
+
List<int> typedCreated = (List<int>)created;
|
|
200
|
+
Assert.AreEqual(capacity, typedCreated.Capacity);
|
|
201
|
+
|
|
202
|
+
int count = _random.Next(50);
|
|
203
|
+
List<int> expected = new();
|
|
204
|
+
for (int j = 0; j < count; ++j)
|
|
205
|
+
{
|
|
206
|
+
int element = _random.Next();
|
|
207
|
+
created.Add(element);
|
|
208
|
+
expected.Add(element);
|
|
209
|
+
Assert.AreEqual(j + 1, created.Count);
|
|
210
|
+
Assert.That(expected, Is.EqualTo(typedCreated));
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
using System;
|
|
4
4
|
using System.Diagnostics;
|
|
5
5
|
using Components;
|
|
6
|
+
using Components.UnityHelpers.Tests.Components;
|
|
6
7
|
using Core.Attributes;
|
|
7
8
|
using NUnit.Framework;
|
|
8
9
|
using UnityEngine;
|
|
@@ -10,12 +11,13 @@
|
|
|
10
11
|
public sealed class RelationComponentPerformanceTests
|
|
11
12
|
{
|
|
12
13
|
[Test]
|
|
13
|
-
public void
|
|
14
|
+
public void RelationalPerformanceComplexTest()
|
|
14
15
|
{
|
|
15
16
|
int count = 0;
|
|
16
17
|
|
|
17
|
-
GameObject go = new("Test", typeof(
|
|
18
|
-
|
|
18
|
+
GameObject go = new("Test", typeof(RelationalComponentTesterComplex));
|
|
19
|
+
RelationalComponentTesterComplex tester =
|
|
20
|
+
go.GetComponent<RelationalComponentTesterComplex>();
|
|
19
21
|
// Pre-warm
|
|
20
22
|
tester.AssignRelationalComponents();
|
|
21
23
|
|
|
@@ -33,5 +35,27 @@
|
|
|
33
35
|
Assert.AreNotEqual(0, tester._parentColliders.Length);
|
|
34
36
|
Assert.AreNotEqual(0, tester._siblingColliders.Length);
|
|
35
37
|
}
|
|
38
|
+
|
|
39
|
+
[Test]
|
|
40
|
+
public void RelationalPerformanceSimpleTest()
|
|
41
|
+
{
|
|
42
|
+
int count = 0;
|
|
43
|
+
|
|
44
|
+
GameObject go = new("Test", typeof(RelationalComponentTesterSimple));
|
|
45
|
+
RelationalComponentTesterSimple tester =
|
|
46
|
+
go.GetComponent<RelationalComponentTesterSimple>();
|
|
47
|
+
// Pre-warm
|
|
48
|
+
tester.AssignRelationalComponents();
|
|
49
|
+
|
|
50
|
+
TimeSpan timeout = TimeSpan.FromSeconds(10);
|
|
51
|
+
Stopwatch timer = Stopwatch.StartNew();
|
|
52
|
+
do
|
|
53
|
+
{
|
|
54
|
+
tester.AssignRelationalComponents();
|
|
55
|
+
++count;
|
|
56
|
+
} while (timer.Elapsed < timeout);
|
|
57
|
+
|
|
58
|
+
UnityEngine.Debug.Log($"Averaged {count / timeout.TotalSeconds} operations / second.");
|
|
59
|
+
}
|
|
36
60
|
}
|
|
37
61
|
}
|
package/package.json
CHANGED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
name: Export and Release Unity Package
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
workflow_run:
|
|
5
|
-
workflows: ["Unity Tests"]
|
|
6
|
-
types:
|
|
7
|
-
- completed
|
|
8
|
-
workflow_dispatch:
|
|
9
|
-
inputs:
|
|
10
|
-
logLevel:
|
|
11
|
-
description: 'Log level'
|
|
12
|
-
required: true
|
|
13
|
-
default: 'warning'
|
|
14
|
-
environment:
|
|
15
|
-
description: 'Environment to deploy'
|
|
16
|
-
required: false
|
|
17
|
-
default: 'staging'
|
|
18
|
-
|
|
19
|
-
env:
|
|
20
|
-
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
21
|
-
|
|
22
|
-
jobs:
|
|
23
|
-
package_unity:
|
|
24
|
-
runs-on: ubuntu-latest
|
|
25
|
-
|
|
26
|
-
steps:
|
|
27
|
-
- name: Checkout Repository
|
|
28
|
-
uses: actions/checkout@v4
|
|
29
|
-
with:
|
|
30
|
-
fetch-depth: 0 # Ensure full commit history for version comparison
|
|
31
|
-
|
|
32
|
-
- name: Set up Node.js
|
|
33
|
-
uses: actions/setup-node@v4
|
|
34
|
-
with:
|
|
35
|
-
node-version: 18
|
|
36
|
-
|
|
37
|
-
- name: Check if version changed
|
|
38
|
-
id: version_check
|
|
39
|
-
run: |
|
|
40
|
-
PREV_VERSION=$(git show HEAD~1:package.json | jq -r '.version' || echo "0.0.0")
|
|
41
|
-
NEW_VERSION=$(jq -r '.version' package.json)
|
|
42
|
-
echo "Previous version: $PREV_VERSION"
|
|
43
|
-
echo "New version: $NEW_VERSION"
|
|
44
|
-
|
|
45
|
-
if [ "$PREV_VERSION" != "$NEW_VERSION" ]; then
|
|
46
|
-
echo "Version changed, proceeding..."
|
|
47
|
-
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
|
|
48
|
-
echo "should_build=true" >> $GITHUB_ENV
|
|
49
|
-
|
|
50
|
-
# Check for pre-release versions
|
|
51
|
-
if [[ "$NEW_VERSION" == *"rc"* ]]; then
|
|
52
|
-
echo "This is a pre-release (next tag)."
|
|
53
|
-
echo "IS_PRERELEASE=true" >> $GITHUB_ENV
|
|
54
|
-
else
|
|
55
|
-
echo "This is a stable release."
|
|
56
|
-
echo "IS_PRERELEASE=false" >> $GITHUB_ENV
|
|
57
|
-
fi
|
|
58
|
-
else
|
|
59
|
-
echo "Version did not change, skipping..."
|
|
60
|
-
echo "should_build=false" >> $GITHUB_ENV
|
|
61
|
-
fi
|
|
62
|
-
|
|
63
|
-
- name: Set up Unity
|
|
64
|
-
if: env.should_build == 'true'
|
|
65
|
-
uses: game-ci/unity-builder@v4
|
|
66
|
-
env:
|
|
67
|
-
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
68
|
-
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
|
69
|
-
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
|
70
|
-
with:
|
|
71
|
-
unityVersion: 2022.3.5f1
|
|
72
|
-
targetPlatform: StandaloneLinux64
|
|
73
|
-
buildMethod: BuildScript.BuildLinux
|
|
74
|
-
projectPath: .
|
|
75
|
-
|
|
76
|
-
- name: Export Unity Package
|
|
77
|
-
if: env.should_build == 'true'
|
|
78
|
-
run: |
|
|
79
|
-
EXPORT_DIR="UnityHelpers"
|
|
80
|
-
PACKAGE_NAME="WallstopStudios.UnityHelpers.unitypackage"
|
|
81
|
-
|
|
82
|
-
mkdir -p $EXPORT_DIR
|
|
83
|
-
|
|
84
|
-
echo "Exporting package: $EXPORT_DIR/$PACKAGE_NAME"
|
|
85
|
-
|
|
86
|
-
/opt/unity/Editor/Unity \
|
|
87
|
-
-batchmode -quit \
|
|
88
|
-
-projectPath "$(pwd)" \
|
|
89
|
-
-exportPackage "Assets" "$EXPORT_DIR/$PACKAGE_NAME"
|
|
90
|
-
|
|
91
|
-
echo "PACKAGE_PATH=$EXPORT_DIR/$PACKAGE_NAME" >> $GITHUB_ENV
|
|
92
|
-
|
|
93
|
-
- name: Create GitHub Release
|
|
94
|
-
if: env.should_build == 'true'
|
|
95
|
-
id: create_release
|
|
96
|
-
uses: softprops/action-gh-release@v2
|
|
97
|
-
with:
|
|
98
|
-
tag_name: v${{ env.NEW_VERSION }}
|
|
99
|
-
release_name: "Unity Helpers v${{ env.NEW_VERSION }}"
|
|
100
|
-
body: "Automatically generated release for version ${{ env.NEW_VERSION }}."
|
|
101
|
-
draft: false
|
|
102
|
-
prerelease: ${{ env.IS_PRERELEASE == 'true' }}
|
|
103
|
-
files: ${{ env.PACKAGE_PATH }}
|
|
104
|
-
env:
|
|
105
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|