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
|
@@ -7,15 +7,6 @@ on:
|
|
|
7
7
|
paths:
|
|
8
8
|
- 'package.json'
|
|
9
9
|
workflow_dispatch:
|
|
10
|
-
inputs:
|
|
11
|
-
logLevel:
|
|
12
|
-
description: 'Log level'
|
|
13
|
-
required: true
|
|
14
|
-
default: 'warning'
|
|
15
|
-
environment:
|
|
16
|
-
description: 'Environment to deploy'
|
|
17
|
-
required: false
|
|
18
|
-
default: 'staging'
|
|
19
10
|
|
|
20
11
|
jobs:
|
|
21
12
|
publish_npm:
|
|
@@ -36,27 +27,32 @@ jobs:
|
|
|
36
27
|
- name: Check if version changed
|
|
37
28
|
id: version_check
|
|
38
29
|
run: |
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
echo "Previous version: $PREV_VERSION"
|
|
42
|
-
echo "New version: $NEW_VERSION"
|
|
43
|
-
|
|
44
|
-
if [ "$PREV_VERSION" != "$NEW_VERSION" ]; then
|
|
45
|
-
echo "Version changed, proceeding..."
|
|
46
|
-
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
|
|
30
|
+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
31
|
+
echo "Manual trigger detected. Skipping version check."
|
|
47
32
|
echo "should_publish=true" >> $GITHUB_ENV
|
|
33
|
+
else
|
|
34
|
+
PREV_VERSION=$(git show HEAD~1:package.json | jq -r '.version' || echo "0.0.0")
|
|
35
|
+
NEW_VERSION=$(jq -r '.version' package.json)
|
|
36
|
+
echo "Previous version: $PREV_VERSION"
|
|
37
|
+
echo "New version: $NEW_VERSION"
|
|
48
38
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
echo "
|
|
52
|
-
echo "
|
|
39
|
+
if [ "$PREV_VERSION" != "$NEW_VERSION" ]; then
|
|
40
|
+
echo "Version changed, proceeding..."
|
|
41
|
+
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
|
|
42
|
+
echo "should_publish=true" >> $GITHUB_ENV
|
|
43
|
+
|
|
44
|
+
# Detect pre-releases (versions with "rc" or similar tags)
|
|
45
|
+
if [[ "$NEW_VERSION" == *"rc"* ]]; then
|
|
46
|
+
echo "This is a pre-release (next tag)."
|
|
47
|
+
echo "NPM_TAG=next" >> $GITHUB_ENV
|
|
48
|
+
else
|
|
49
|
+
echo "This is a stable release (latest tag)."
|
|
50
|
+
echo "NPM_TAG=latest" >> $GITHUB_ENV
|
|
51
|
+
fi
|
|
53
52
|
else
|
|
54
|
-
echo "
|
|
55
|
-
echo "
|
|
53
|
+
echo "Version did not change, skipping..."
|
|
54
|
+
echo "should_publish=false" >> $GITHUB_ENV
|
|
56
55
|
fi
|
|
57
|
-
else
|
|
58
|
-
echo "Version did not change, skipping..."
|
|
59
|
-
echo "should_publish=false" >> $GITHUB_ENV
|
|
60
56
|
fi
|
|
61
57
|
|
|
62
58
|
- name: Install Dependencies
|
|
@@ -14,12 +14,35 @@
|
|
|
14
14
|
private string _fullSourcePath;
|
|
15
15
|
private string _fullDestinationPath;
|
|
16
16
|
|
|
17
|
-
[
|
|
17
|
+
[DxReadOnly]
|
|
18
18
|
public string animationSourcePath;
|
|
19
19
|
|
|
20
|
-
[
|
|
20
|
+
[DxReadOnly]
|
|
21
21
|
public string animationDestinationPath;
|
|
22
22
|
|
|
23
|
+
private void OnEnable()
|
|
24
|
+
{
|
|
25
|
+
if (string.IsNullOrWhiteSpace(_fullSourcePath))
|
|
26
|
+
{
|
|
27
|
+
_fullSourcePath = $"{Application.dataPath}/Sprites";
|
|
28
|
+
int assetIndex = _fullSourcePath.IndexOf("Assets", StringComparison.Ordinal);
|
|
29
|
+
if (0 <= assetIndex)
|
|
30
|
+
{
|
|
31
|
+
animationSourcePath = _fullSourcePath.Substring(assetIndex);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (string.IsNullOrWhiteSpace(_fullDestinationPath))
|
|
36
|
+
{
|
|
37
|
+
_fullDestinationPath = $"{Application.dataPath}/Animations";
|
|
38
|
+
int assetIndex = _fullDestinationPath.IndexOf("Assets", StringComparison.Ordinal);
|
|
39
|
+
if (0 <= assetIndex)
|
|
40
|
+
{
|
|
41
|
+
animationDestinationPath = _fullDestinationPath.Substring(assetIndex);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
23
46
|
[MenuItem("Tools/Unity Helpers/Animation Copier")]
|
|
24
47
|
public static void CopyAnimations()
|
|
25
48
|
{
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
{
|
|
15
15
|
public const int DefaultFramesPerSecond = 12;
|
|
16
16
|
|
|
17
|
-
public List<Texture2D> frames;
|
|
17
|
+
public List<Texture2D> frames = new();
|
|
18
18
|
public int framesPerSecond = DefaultFramesPerSecond;
|
|
19
|
-
public string animationName;
|
|
19
|
+
public string animationName = string.Empty;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
public sealed class AnimationCreator : ScriptableWizard
|
|
@@ -90,11 +90,13 @@
|
|
|
90
90
|
int lastNumericIndex = frameName.Length - 1;
|
|
91
91
|
for (int i = frameName.Length - 1; 0 <= i; --i)
|
|
92
92
|
{
|
|
93
|
-
if (
|
|
93
|
+
if (char.IsNumber(frameName[i]))
|
|
94
94
|
{
|
|
95
|
-
|
|
96
|
-
break;
|
|
95
|
+
continue;
|
|
97
96
|
}
|
|
97
|
+
|
|
98
|
+
lastNumericIndex = i + 1;
|
|
99
|
+
break;
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
int lastUnderscoreIndex = frameName.LastIndexOf('_');
|
|
@@ -118,29 +120,18 @@
|
|
|
118
120
|
if (0 < texturesByPrefixAndAssetPath.Count)
|
|
119
121
|
{
|
|
120
122
|
animationData.Clear();
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
List<Texture2D>
|
|
132
|
-
> textureAndPrefix in assetPathAndTextures.Value
|
|
123
|
+
animationData.AddRange(
|
|
124
|
+
texturesByPrefixAndAssetPath.SelectMany(assetPathAndTextures =>
|
|
125
|
+
assetPathAndTextures.Value.Select(
|
|
126
|
+
textureAndPrefix => new AnimationData
|
|
127
|
+
{
|
|
128
|
+
frames = textureAndPrefix.Value,
|
|
129
|
+
framesPerSecond = data.framesPerSecond,
|
|
130
|
+
animationName = $"Anim_{textureAndPrefix.Key}",
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
133
|
)
|
|
134
|
-
|
|
135
|
-
AnimationData newData = new()
|
|
136
|
-
{
|
|
137
|
-
frames = textureAndPrefix.Value,
|
|
138
|
-
framesPerSecond = data.framesPerSecond,
|
|
139
|
-
animationName = $"Anim_{textureAndPrefix.Key}",
|
|
140
|
-
};
|
|
141
|
-
animationData.Add(newData);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
134
|
+
);
|
|
144
135
|
}
|
|
145
136
|
}
|
|
146
137
|
}
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
private string _fullSourcePath;
|
|
15
15
|
private string _fullDestinationPath;
|
|
16
16
|
|
|
17
|
-
[
|
|
17
|
+
[DxReadOnly]
|
|
18
18
|
public string controllerSourcePath;
|
|
19
19
|
|
|
20
|
-
[
|
|
21
|
-
public string
|
|
20
|
+
[DxReadOnly]
|
|
21
|
+
public string controllerDestinationPath;
|
|
22
22
|
|
|
23
23
|
[MenuItem("Tools/Unity Helpers/Animator Controller Copier")]
|
|
24
24
|
public static void CopyAnimations()
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
return false;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
_fullDestinationPath =
|
|
65
|
-
|
|
64
|
+
_fullDestinationPath = controllerDestinationPath = sourcePath ?? string.Empty;
|
|
65
|
+
controllerDestinationPath = controllerDestinationPath.Substring(assetIndex);
|
|
66
66
|
return true;
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
|
|
79
79
|
if (
|
|
80
80
|
string.IsNullOrEmpty(controllerSourcePath)
|
|
81
|
-
|| string.IsNullOrEmpty(
|
|
81
|
+
|| string.IsNullOrEmpty(controllerDestinationPath)
|
|
82
82
|
)
|
|
83
83
|
{
|
|
84
84
|
return;
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
string destination =
|
|
133
|
-
|
|
133
|
+
controllerDestinationPath + partialPath + relativePath.Substring(prefixIndex);
|
|
134
134
|
bool copySuccessful = AssetDatabase.CopyAsset(path, destination);
|
|
135
135
|
if (copySuccessful)
|
|
136
136
|
{
|
|
@@ -22,22 +22,27 @@
|
|
|
22
22
|
{
|
|
23
23
|
textures ??= new List<Texture2D>();
|
|
24
24
|
textureSourcePaths ??= new List<Object>();
|
|
25
|
-
HashSet<string>
|
|
26
|
-
foreach (
|
|
25
|
+
HashSet<string> texturePaths = new();
|
|
26
|
+
foreach (
|
|
27
|
+
string assetPath in textureSourcePaths
|
|
28
|
+
.Select(AssetDatabase.GetAssetPath)
|
|
29
|
+
.Where(assetPath => !string.IsNullOrWhiteSpace(assetPath))
|
|
30
|
+
)
|
|
27
31
|
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
_ = texturePaths.Add(assetPath);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!textures.Any() && !texturePaths.Any())
|
|
36
|
+
{
|
|
37
|
+
texturePaths.Add("Assets");
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
if (
|
|
40
|
+
if (texturePaths.Any())
|
|
36
41
|
{
|
|
37
42
|
foreach (
|
|
38
43
|
string assetGuid in AssetDatabase.FindAssets(
|
|
39
44
|
"t:texture2D",
|
|
40
|
-
|
|
45
|
+
texturePaths.ToArray()
|
|
41
46
|
)
|
|
42
47
|
)
|
|
43
48
|
{
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
[Tooltip(
|
|
22
22
|
"Drag a folder from Unity here to validate all prefabs under it. Defaults to Assets/Prefabs and Assets/Resources if none specified."
|
|
23
23
|
)]
|
|
24
|
-
public List<Object> assetPaths;
|
|
24
|
+
public List<Object> assetPaths = new();
|
|
25
25
|
|
|
26
26
|
[MenuItem("Tools/Unity Helpers/Prefab Check Wizard")]
|
|
27
27
|
public static void CreatePrefabCheckWizard()
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
using UnityEngine;
|
|
7
7
|
|
|
8
8
|
// https://www.patrykgalach.com/2020/01/20/readonly-attribute-in-unity-editor/
|
|
9
|
-
[CustomPropertyDrawer(typeof(
|
|
10
|
-
public sealed class
|
|
9
|
+
[CustomPropertyDrawer(typeof(DxReadOnlyAttribute))]
|
|
10
|
+
public sealed class DxReadOnlyPropertyDrawer : PropertyDrawer
|
|
11
11
|
{
|
|
12
12
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
|
13
13
|
{
|
package/README.md
CHANGED
|
@@ -3,7 +3,6 @@ Various Unity Helpers. Includes many deterministic, seedable random number gener
|
|
|
3
3
|
|
|
4
4
|
# CI/CD Status
|
|
5
5
|

|
|
6
|
-

|
|
7
6
|
|
|
8
7
|
# Compatibility
|
|
9
8
|
| Platform | Compatible |
|
|
@@ -51,6 +50,43 @@ Check out the latest [Releases](https://github.com/wallstop/unity-helpers/releas
|
|
|
51
50
|
- A randomizable PerlinNoise implementation
|
|
52
51
|
- And more!
|
|
53
52
|
|
|
53
|
+
# Auto Get(Parent/Sibling/Child)Component
|
|
54
|
+
Are you tired of constantly writing GetComponent<T>() all over the place? Waste time no more!
|
|
55
|
+
|
|
56
|
+
```csharp
|
|
57
|
+
public sealed class MyCoolScript : MonoBehaviour
|
|
58
|
+
{
|
|
59
|
+
[SiblingComponent] // If it doesn't exist, will log an error
|
|
60
|
+
private SpriteRenderer _spriteRenderer;
|
|
61
|
+
|
|
62
|
+
[SiblingComponent(optional = true)] // Ok if it doesn't exist, no errors logged
|
|
63
|
+
private BoxCollider2D _boxCollider;
|
|
64
|
+
|
|
65
|
+
[ParentComponent] // Similar to GetComponentInParent<AIController>(includeInactive: true)
|
|
66
|
+
private AIController _parentAIController;
|
|
67
|
+
|
|
68
|
+
// Only include components in parents, Unity by default includes sibling components in the GetComponentsInParent call
|
|
69
|
+
[ParentComponent(onlyAncestors = true)]
|
|
70
|
+
private Transform [] _allParentTransforms; // Works with arrays!
|
|
71
|
+
|
|
72
|
+
[ParentComponent(includeInactive = false)] // Don't include inactive components
|
|
73
|
+
private List<PolygonCollider2> _parentColliders; // Works with lists!
|
|
74
|
+
|
|
75
|
+
[ChildComponent(onlyDescendents = true)] // Similar to GetComponentInChildren<EdgeCollider2D>(includeInactive: true)
|
|
76
|
+
private EdgeCollider2D _childEdgeCollider;
|
|
77
|
+
|
|
78
|
+
private void Awake()
|
|
79
|
+
{
|
|
80
|
+
/*
|
|
81
|
+
Make sure this is called somewhere, usually in Awake, OnEnable, or Start - wherever this is called,
|
|
82
|
+
values will be injected into the annotated fields and errors will be logged
|
|
83
|
+
*/
|
|
84
|
+
this.AssignRelationalComponents();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
|
|
54
90
|
# Random Number Generators
|
|
55
91
|
This package implements several high quality, seedable, and serializable random number generators. The best one (currently) is the PCG Random. This has been hidden behind the `PRNG.Instance` class, which is thread-safe. As the package evolves, the exact implementation of this may change.
|
|
56
92
|
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
public sealed class ChildComponentAttribute : Attribute
|
|
16
16
|
{
|
|
17
17
|
public bool optional = false;
|
|
18
|
+
public bool includeInactive = true;
|
|
18
19
|
public bool onlyDescendents = false;
|
|
19
20
|
}
|
|
20
21
|
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
);
|
|
38
39
|
return fields
|
|
39
40
|
.Where(field => Attribute.IsDefined(field, typeof(ChildComponentAttribute)))
|
|
40
|
-
.Select(field => (field, ReflectionHelpers.
|
|
41
|
+
.Select(field => (field, ReflectionHelpers.GetFieldSetter(field)))
|
|
41
42
|
.ToArray();
|
|
42
43
|
}
|
|
43
44
|
);
|
|
@@ -49,7 +50,9 @@
|
|
|
49
50
|
Type childComponentType = isArray ? fieldType.GetElementType() : fieldType;
|
|
50
51
|
|
|
51
52
|
bool foundChild;
|
|
52
|
-
|
|
53
|
+
ChildComponentAttribute customAttribute =
|
|
54
|
+
field.GetCustomAttribute<ChildComponentAttribute>();
|
|
55
|
+
if (customAttribute.onlyDescendents)
|
|
53
56
|
{
|
|
54
57
|
if (isArray)
|
|
55
58
|
{
|
|
@@ -57,7 +60,10 @@
|
|
|
57
60
|
foreach (Transform child in component.IterateOverAllChildren())
|
|
58
61
|
{
|
|
59
62
|
children.AddRange(
|
|
60
|
-
child.GetComponentsInChildren(
|
|
63
|
+
child.GetComponentsInChildren(
|
|
64
|
+
childComponentType,
|
|
65
|
+
customAttribute.includeInactive
|
|
66
|
+
)
|
|
61
67
|
);
|
|
62
68
|
}
|
|
63
69
|
|
|
@@ -83,7 +89,10 @@
|
|
|
83
89
|
Component childComponent in component
|
|
84
90
|
.IterateOverAllChildren()
|
|
85
91
|
.SelectMany(child =>
|
|
86
|
-
child.GetComponentsInChildren(
|
|
92
|
+
child.GetComponentsInChildren(
|
|
93
|
+
childComponentType,
|
|
94
|
+
customAttribute.includeInactive
|
|
95
|
+
)
|
|
87
96
|
)
|
|
88
97
|
)
|
|
89
98
|
{
|
|
@@ -97,14 +106,27 @@
|
|
|
97
106
|
{
|
|
98
107
|
foundChild = false;
|
|
99
108
|
Component childComponent = null;
|
|
100
|
-
foreach (
|
|
109
|
+
foreach (
|
|
110
|
+
Transform child in component.IterateOverAllChildrenRecursivelyBreadthFirst()
|
|
111
|
+
)
|
|
101
112
|
{
|
|
102
113
|
childComponent = child.GetComponent(childComponentType);
|
|
103
|
-
if (
|
|
114
|
+
if (
|
|
115
|
+
childComponent == null
|
|
116
|
+
|| (
|
|
117
|
+
!customAttribute.includeInactive
|
|
118
|
+
&& (
|
|
119
|
+
!childComponent.gameObject.activeInHierarchy
|
|
120
|
+
|| childComponent is Behaviour { enabled: false }
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
)
|
|
104
124
|
{
|
|
105
|
-
|
|
106
|
-
break;
|
|
125
|
+
continue;
|
|
107
126
|
}
|
|
127
|
+
|
|
128
|
+
foundChild = true;
|
|
129
|
+
break;
|
|
108
130
|
}
|
|
109
131
|
if (foundChild)
|
|
110
132
|
{
|
|
@@ -118,7 +140,7 @@
|
|
|
118
140
|
{
|
|
119
141
|
Component[] childComponents = component.GetComponentsInChildren(
|
|
120
142
|
childComponentType,
|
|
121
|
-
|
|
143
|
+
customAttribute.includeInactive
|
|
122
144
|
);
|
|
123
145
|
foundChild = 0 < childComponents.Length;
|
|
124
146
|
|
|
@@ -149,7 +171,7 @@
|
|
|
149
171
|
foreach (
|
|
150
172
|
Component childComponent in component.GetComponentsInChildren(
|
|
151
173
|
childComponentType,
|
|
152
|
-
|
|
174
|
+
customAttribute.includeInactive
|
|
153
175
|
)
|
|
154
176
|
)
|
|
155
177
|
{
|
|
@@ -163,7 +185,7 @@
|
|
|
163
185
|
{
|
|
164
186
|
Component childComponent = component.GetComponentInChildren(
|
|
165
187
|
childComponentType,
|
|
166
|
-
|
|
188
|
+
customAttribute.includeInactive
|
|
167
189
|
);
|
|
168
190
|
foundChild = childComponent != null;
|
|
169
191
|
if (foundChild)
|
|
@@ -173,15 +195,13 @@
|
|
|
173
195
|
}
|
|
174
196
|
}
|
|
175
197
|
|
|
176
|
-
if (
|
|
198
|
+
if (
|
|
199
|
+
!foundChild
|
|
200
|
+
&& field.GetCustomAttributes(typeof(ChildComponentAttribute), false)[0]
|
|
201
|
+
is ChildComponentAttribute { optional: false }
|
|
202
|
+
)
|
|
177
203
|
{
|
|
178
|
-
|
|
179
|
-
field.GetCustomAttributes(typeof(ChildComponentAttribute), false)[0]
|
|
180
|
-
is ChildComponentAttribute { optional: false } _
|
|
181
|
-
)
|
|
182
|
-
{
|
|
183
|
-
component.LogError($"Unable to find child component of type {fieldType}");
|
|
184
|
-
}
|
|
204
|
+
component.LogError($"Unable to find child component of type {fieldType}");
|
|
185
205
|
}
|
|
186
206
|
}
|
|
187
207
|
}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
public sealed class ParentComponentAttribute : Attribute
|
|
16
16
|
{
|
|
17
17
|
public bool optional = false;
|
|
18
|
+
public bool includeInactive = true;
|
|
18
19
|
public bool onlyAncestors = false;
|
|
19
20
|
}
|
|
20
21
|
|
|
@@ -39,7 +40,7 @@
|
|
|
39
40
|
.Where(field =>
|
|
40
41
|
Attribute.IsDefined(field, typeof(ParentComponentAttribute))
|
|
41
42
|
)
|
|
42
|
-
.Select(field => (field, ReflectionHelpers.
|
|
43
|
+
.Select(field => (field, ReflectionHelpers.GetFieldSetter(field)))
|
|
43
44
|
.ToArray();
|
|
44
45
|
}
|
|
45
46
|
);
|
|
@@ -51,6 +52,8 @@
|
|
|
51
52
|
Type parentComponentType = isArray ? fieldType.GetElementType() : fieldType;
|
|
52
53
|
|
|
53
54
|
bool foundParent;
|
|
55
|
+
ParentComponentAttribute customAttribute =
|
|
56
|
+
field.GetCustomAttribute<ParentComponentAttribute>();
|
|
54
57
|
if (field.GetCustomAttribute<ParentComponentAttribute>().onlyAncestors)
|
|
55
58
|
{
|
|
56
59
|
Transform parent = component.transform.parent;
|
|
@@ -62,7 +65,7 @@
|
|
|
62
65
|
{
|
|
63
66
|
Component[] parentComponents = parent.GetComponentsInParent(
|
|
64
67
|
parentComponentType,
|
|
65
|
-
|
|
68
|
+
customAttribute.includeInactive
|
|
66
69
|
);
|
|
67
70
|
foundParent = 0 < parentComponents.Length;
|
|
68
71
|
|
|
@@ -82,7 +85,7 @@
|
|
|
82
85
|
|
|
83
86
|
Component[] parents = parent.GetComponentsInParent(
|
|
84
87
|
parentComponentType,
|
|
85
|
-
|
|
88
|
+
customAttribute.includeInactive
|
|
86
89
|
);
|
|
87
90
|
|
|
88
91
|
IList instance = ReflectionHelpers.CreateList(
|
|
@@ -103,7 +106,7 @@
|
|
|
103
106
|
{
|
|
104
107
|
Component childComponent = parent.GetComponentInParent(
|
|
105
108
|
parentComponentType,
|
|
106
|
-
|
|
109
|
+
customAttribute.includeInactive
|
|
107
110
|
);
|
|
108
111
|
foundParent = childComponent != null;
|
|
109
112
|
if (foundParent)
|
|
@@ -118,7 +121,7 @@
|
|
|
118
121
|
{
|
|
119
122
|
Component[] parentComponents = component.GetComponentsInParent(
|
|
120
123
|
parentComponentType,
|
|
121
|
-
|
|
124
|
+
customAttribute.includeInactive
|
|
122
125
|
);
|
|
123
126
|
foundParent = 0 < parentComponents.Length;
|
|
124
127
|
|
|
@@ -138,7 +141,7 @@
|
|
|
138
141
|
|
|
139
142
|
Component[] parents = component.GetComponentsInParent(
|
|
140
143
|
parentComponentType,
|
|
141
|
-
|
|
144
|
+
customAttribute.includeInactive
|
|
142
145
|
);
|
|
143
146
|
|
|
144
147
|
IList instance = ReflectionHelpers.CreateList(
|
|
@@ -158,7 +161,7 @@
|
|
|
158
161
|
{
|
|
159
162
|
Component childComponent = component.GetComponentInParent(
|
|
160
163
|
parentComponentType,
|
|
161
|
-
|
|
164
|
+
customAttribute.includeInactive
|
|
162
165
|
);
|
|
163
166
|
foundParent = childComponent != null;
|
|
164
167
|
if (foundParent)
|
|
@@ -168,15 +171,13 @@
|
|
|
168
171
|
}
|
|
169
172
|
}
|
|
170
173
|
|
|
171
|
-
if (
|
|
174
|
+
if (
|
|
175
|
+
!foundParent
|
|
176
|
+
&& field.GetCustomAttributes(typeof(ParentComponentAttribute), false)[0]
|
|
177
|
+
is ParentComponentAttribute { optional: false }
|
|
178
|
+
)
|
|
172
179
|
{
|
|
173
|
-
|
|
174
|
-
field.GetCustomAttributes(typeof(ParentComponentAttribute), false)[0]
|
|
175
|
-
is ParentComponentAttribute { optional: false } _
|
|
176
|
-
)
|
|
177
|
-
{
|
|
178
|
-
component.LogError($"Unable to find parent component of type {fieldType}");
|
|
179
|
-
}
|
|
180
|
+
component.LogError($"Unable to find parent component of type {fieldType}");
|
|
180
181
|
}
|
|
181
182
|
}
|
|
182
183
|
}
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
.Where(field =>
|
|
39
39
|
Attribute.IsDefined(field, typeof(SiblingComponentAttribute))
|
|
40
40
|
)
|
|
41
|
-
.Select(field => (field, ReflectionHelpers.
|
|
41
|
+
.Select(field => (field, ReflectionHelpers.GetFieldSetter(field)))
|
|
42
42
|
.ToArray();
|
|
43
43
|
}
|
|
44
44
|
);
|
|
@@ -103,15 +103,13 @@
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
if (
|
|
106
|
+
if (
|
|
107
|
+
!foundSibling
|
|
108
|
+
&& field.GetCustomAttributes(typeof(SiblingComponentAttribute), false)[0]
|
|
109
|
+
is SiblingComponentAttribute { optional: false }
|
|
110
|
+
)
|
|
107
111
|
{
|
|
108
|
-
|
|
109
|
-
field.GetCustomAttributes(typeof(SiblingComponentAttribute), false)[0]
|
|
110
|
-
is SiblingComponentAttribute { optional: false } _
|
|
111
|
-
)
|
|
112
|
-
{
|
|
113
|
-
component.LogError($"Unable to find sibling component of type {fieldType}");
|
|
114
|
-
}
|
|
112
|
+
component.LogError($"Unable to find sibling component of type {fieldType}");
|
|
115
113
|
}
|
|
116
114
|
}
|
|
117
115
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
namespace UnityHelpers.Core.Helper
|
|
2
2
|
{
|
|
3
3
|
using System.Collections.Generic;
|
|
4
|
+
using System.Linq;
|
|
4
5
|
using UnityEngine;
|
|
5
6
|
|
|
6
7
|
public static partial class Helpers
|
|
@@ -163,5 +164,30 @@
|
|
|
163
164
|
}
|
|
164
165
|
}
|
|
165
166
|
}
|
|
167
|
+
|
|
168
|
+
public static IEnumerable<Transform> IterateOverAllChildrenRecursivelyBreadthFirst(
|
|
169
|
+
this Component component
|
|
170
|
+
)
|
|
171
|
+
{
|
|
172
|
+
if (component == null)
|
|
173
|
+
{
|
|
174
|
+
return Enumerable.Empty<Transform>();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
Queue<Transform> results = new();
|
|
178
|
+
Queue<Transform> iteration = new();
|
|
179
|
+
iteration.Enqueue(component.transform);
|
|
180
|
+
while (iteration.TryDequeue(out Transform current))
|
|
181
|
+
{
|
|
182
|
+
for (int i = 0; i < current.childCount; ++i)
|
|
183
|
+
{
|
|
184
|
+
Transform childTransform = current.GetChild(i);
|
|
185
|
+
results.Enqueue(childTransform);
|
|
186
|
+
iteration.Enqueue(childTransform);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return results;
|
|
191
|
+
}
|
|
166
192
|
}
|
|
167
193
|
}
|