com.wallstop-studios.unity-helpers 2.0.0-rc68 → 2.0.0-rc70
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/Editor/AnimationCopier.cs +875 -93
- package/Editor/AnimationCreator.cs +840 -137
- package/Editor/AnimationEventEditor.cs +4 -4
- package/Editor/AnimatorControllerCopier.cs +3 -3
- package/Editor/Extensions/UnityExtensions.cs +26 -0
- package/Editor/Extensions/UnityExtensions.cs.meta +3 -0
- package/Editor/Extensions.meta +3 -0
- package/Editor/FitTextureSizeWindow.cs +371 -0
- package/Editor/PrefabChecker.cs +716 -0
- package/Editor/SpriteAtlasGenerator.cs +598 -0
- package/Editor/SpriteAtlasGenerator.cs.meta +3 -0
- package/Editor/SpriteCropper.cs +407 -0
- package/Editor/SpriteCropper.cs.meta +3 -0
- package/Editor/SpriteSettingsApplier.cs +756 -92
- package/Editor/TextureResizerWizard.cs +3 -3
- package/Editor/TextureSettingsApplier.cs +9 -9
- package/Editor/WShowIfPropertyDrawer.cs +2 -2
- package/Runtime/Core/Attributes/EnumDisplayNameAttribute.cs +15 -0
- package/Runtime/Core/Attributes/EnumDisplayNameAttribute.cs.meta +3 -0
- package/Runtime/Core/Attributes/ValidateAssignmentAttribute.cs +1 -1
- package/Runtime/Core/Extension/EnumExtensions.cs +176 -1
- package/Runtime/Core/Extension/UnityExtensions.cs +1 -1
- package/Runtime/Core/Helper/Partials/LogHelpers.cs +1 -1
- package/Runtime/Core/Helper/Partials/MathHelpers.cs +1 -1
- package/Runtime/Core/Helper/Partials/ObjectHelpers.cs +3 -4
- package/Runtime/Tags/Attribute.cs +205 -0
- package/Runtime/Tags/Attribute.cs.meta +3 -0
- package/Runtime/Tags/AttributeEffect.cs +276 -0
- package/Runtime/Tags/AttributeEffect.cs.meta +3 -0
- package/Runtime/Tags/AttributeModification.cs +51 -0
- package/Runtime/Tags/AttributeModification.cs.meta +3 -0
- package/Runtime/Tags/AttributeUtilities.cs +209 -0
- package/Runtime/Tags/AttributeUtilities.cs.meta +3 -0
- package/Runtime/Tags/AttributesComponent.cs +163 -0
- package/Runtime/Tags/AttributesComponent.cs.meta +3 -0
- package/Runtime/Tags/CosmeticEffectComponent.cs +50 -0
- package/Runtime/Tags/CosmeticEffectComponent.cs.meta +3 -0
- package/Runtime/Tags/CosmeticEffectData.cs +63 -0
- package/Runtime/Tags/CosmeticEffectData.cs.meta +3 -0
- package/Runtime/Tags/EffectHandle.cs +63 -0
- package/Runtime/Tags/EffectHandle.cs.meta +3 -0
- package/Runtime/Tags/EffectHandler.cs +380 -0
- package/Runtime/Tags/EffectHandler.cs.meta +3 -0
- package/Runtime/Tags/ModificationAction.cs +9 -0
- package/Runtime/Tags/ModificationAction.cs.meta +3 -0
- package/Runtime/Tags/ModifierDurationType.cs +13 -0
- package/Runtime/Tags/ModifierDurationType.cs.meta +3 -0
- package/Runtime/{Utils → Tags}/TagHandler.cs +42 -5
- package/Runtime/Tags.meta +3 -0
- package/Tests/Runtime/DataStructures/BalancedKDTreeTests.cs +1 -1
- package/Tests/Runtime/DataStructures/CyclicBufferTests.cs +1 -1
- package/Tests/Runtime/DataStructures/QuadTreeTests.cs +1 -1
- package/Tests/Runtime/DataStructures/SpatialTreeTests.cs +1 -1
- package/Tests/Runtime/DataStructures/UnbalancedKDTreeTests.cs +1 -1
- package/Tests/Runtime/Extensions/DictionaryExtensionTests.cs +1 -1
- package/Tests/Runtime/Extensions/EnumExtensionTests.cs +1 -1
- package/Tests/Runtime/Extensions/IListExtensionTests.cs +1 -1
- package/Tests/Runtime/Extensions/LoggingExtensionTests.cs +1 -1
- package/Tests/Runtime/Extensions/RandomExtensionTests.cs +1 -1
- package/Tests/Runtime/Extensions/StringExtensionTests.cs +1 -1
- package/Tests/Runtime/Helper/ObjectHelperTests.cs +1 -0
- package/Tests/Runtime/Helper/WallMathTests.cs +1 -1
- package/Tests/Runtime/Performance/KDTreePerformanceTests.cs +1 -1
- package/Tests/Runtime/Performance/QuadTreePerformanceTests.cs +1 -1
- package/Tests/Runtime/Performance/SpatialTreePerformanceTest.cs +1 -1
- package/Tests/Runtime/Performance/UnbalancedKDTreeTests.cs +1 -1
- package/Tests/Runtime/Random/RandomTestBase.cs +2 -2
- package/Tests/Runtime/Serialization/JsonSerializationTest.cs +1 -1
- package/package.json +1 -1
- package/Editor/FitTextureSizeWizard.cs +0 -147
- package/Editor/PrefabCheckWizard.cs +0 -167
- /package/Editor/{FitTextureSizeWizard.cs.meta → FitTextureSizeWindow.cs.meta} +0 -0
- /package/Editor/{PrefabCheckWizard.cs.meta → PrefabChecker.cs.meta} +0 -0
- /package/Runtime/{Utils → Tags}/TagHandler.cs.meta +0 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
namespace WallstopStudios.UnityHelpers.Tags
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Collections.Generic;
|
|
5
|
+
using System.ComponentModel;
|
|
6
|
+
using System.Linq;
|
|
7
|
+
using System.Text;
|
|
8
|
+
using Core.Extension;
|
|
9
|
+
using Core.Helper;
|
|
10
|
+
using Newtonsoft.Json;
|
|
11
|
+
using Sirenix.OdinInspector;
|
|
12
|
+
|
|
13
|
+
[Serializable]
|
|
14
|
+
public sealed class AttributeEffect :
|
|
15
|
+
#if ODIN_INSPECTOR
|
|
16
|
+
SerializedScriptableObject
|
|
17
|
+
#else
|
|
18
|
+
ScriptableObject
|
|
19
|
+
#endif
|
|
20
|
+
, IEquatable<AttributeEffect>
|
|
21
|
+
{
|
|
22
|
+
public string HumanReadableDescription => BuildDescription();
|
|
23
|
+
|
|
24
|
+
public readonly List<AttributeModification> modifications = new();
|
|
25
|
+
|
|
26
|
+
public ModifierDurationType durationType = ModifierDurationType.Duration;
|
|
27
|
+
|
|
28
|
+
#if ODIN_INSPECTOR
|
|
29
|
+
[ShowIf("@durationType == ModifierDurationType.Duration")]
|
|
30
|
+
#endif
|
|
31
|
+
public float duration;
|
|
32
|
+
|
|
33
|
+
#if ODIN_INSPECTOR
|
|
34
|
+
[ShowIf("@durationType == ModifierDurationType.Duration")]
|
|
35
|
+
#endif
|
|
36
|
+
public bool resetDurationOnReapplication;
|
|
37
|
+
|
|
38
|
+
public List<string> effectTags = new();
|
|
39
|
+
|
|
40
|
+
[JsonIgnore]
|
|
41
|
+
public readonly List<CosmeticEffectData> cosmeticEffects = new();
|
|
42
|
+
|
|
43
|
+
private List<string> CosmeticEffectsForJson =>
|
|
44
|
+
cosmeticEffects
|
|
45
|
+
?.Select(cosmeticEffectData => cosmeticEffectData.name)
|
|
46
|
+
.ToList(cosmeticEffects.Count) ?? new List<string>(0);
|
|
47
|
+
|
|
48
|
+
public override string ToString()
|
|
49
|
+
{
|
|
50
|
+
return new
|
|
51
|
+
{
|
|
52
|
+
Description = HumanReadableDescription,
|
|
53
|
+
CosmeticEffects = CosmeticEffectsForJson,
|
|
54
|
+
modifications,
|
|
55
|
+
durationType,
|
|
56
|
+
duration,
|
|
57
|
+
tags = effectTags,
|
|
58
|
+
}.ToJson();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private string BuildDescription()
|
|
62
|
+
{
|
|
63
|
+
if (modifications == null)
|
|
64
|
+
{
|
|
65
|
+
return nameof(AttributeEffect);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
StringBuilder descriptionBuilder = new();
|
|
69
|
+
for (int i = 0; i < modifications.Count; ++i)
|
|
70
|
+
{
|
|
71
|
+
AttributeModification modification = modifications[i];
|
|
72
|
+
switch (modification.action)
|
|
73
|
+
{
|
|
74
|
+
case ModificationAction.Addition:
|
|
75
|
+
{
|
|
76
|
+
if (modification.value < 0)
|
|
77
|
+
{
|
|
78
|
+
_ = descriptionBuilder.Append(modification.value);
|
|
79
|
+
_ = descriptionBuilder.Append(' ');
|
|
80
|
+
}
|
|
81
|
+
else if (modification.value == 0)
|
|
82
|
+
{
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
else
|
|
86
|
+
{
|
|
87
|
+
_ = descriptionBuilder.AppendFormat("+{0} ", modification.value);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case ModificationAction.Multiplication:
|
|
93
|
+
{
|
|
94
|
+
if (modification.value < 1)
|
|
95
|
+
{
|
|
96
|
+
_ = descriptionBuilder.AppendFormat(
|
|
97
|
+
"-{0}% ",
|
|
98
|
+
(1 - modification.value) * 100
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
|
102
|
+
else if (modification.value == 1)
|
|
103
|
+
{
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
else
|
|
107
|
+
{
|
|
108
|
+
_ = descriptionBuilder.AppendFormat(
|
|
109
|
+
"+{0}% ",
|
|
110
|
+
(modification.value - 1) * 100
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case ModificationAction.Override:
|
|
117
|
+
{
|
|
118
|
+
_ = descriptionBuilder.AppendFormat("{0} ", modification.value);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
default:
|
|
122
|
+
{
|
|
123
|
+
throw new InvalidEnumArgumentException(
|
|
124
|
+
nameof(modification.value),
|
|
125
|
+
(int)modification.value,
|
|
126
|
+
typeof(ModificationAction)
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
_ = descriptionBuilder.Append(modification.attribute.ToPascalCase(" "));
|
|
132
|
+
if (i < modifications.Count - 1)
|
|
133
|
+
{
|
|
134
|
+
_ = descriptionBuilder.Append(", ");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return descriptionBuilder.ToString();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Needed now since most things are based on serialized attribute effects and each unserialization will be a new instance
|
|
142
|
+
public bool Equals(AttributeEffect other)
|
|
143
|
+
{
|
|
144
|
+
if (ReferenceEquals(this, other))
|
|
145
|
+
{
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (other == null)
|
|
150
|
+
{
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!string.Equals(name, other.name))
|
|
155
|
+
{
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (durationType != other.durationType)
|
|
160
|
+
{
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
|
165
|
+
if (duration != other.duration)
|
|
166
|
+
{
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (resetDurationOnReapplication != other.resetDurationOnReapplication)
|
|
171
|
+
{
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (modifications == null)
|
|
176
|
+
{
|
|
177
|
+
if (other.modifications != null)
|
|
178
|
+
{
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else if (other.modifications == null)
|
|
183
|
+
{
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
else
|
|
187
|
+
{
|
|
188
|
+
if (modifications.Count != other.modifications.Count)
|
|
189
|
+
{
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
for (int i = 0; i < modifications.Count; ++i)
|
|
194
|
+
{
|
|
195
|
+
if (modifications[i] != other.modifications[i])
|
|
196
|
+
{
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (effectTags == null)
|
|
203
|
+
{
|
|
204
|
+
if (other.effectTags != null)
|
|
205
|
+
{
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else if (other.effectTags == null)
|
|
210
|
+
{
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
else
|
|
214
|
+
{
|
|
215
|
+
if (effectTags.Count != other.effectTags.Count)
|
|
216
|
+
{
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
for (int i = 0; i < effectTags.Count; ++i)
|
|
221
|
+
{
|
|
222
|
+
if (effectTags[i] != other.effectTags[i])
|
|
223
|
+
{
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (cosmeticEffects == null)
|
|
230
|
+
{
|
|
231
|
+
if (other.cosmeticEffects != null)
|
|
232
|
+
{
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else if (other.cosmeticEffects == null)
|
|
237
|
+
{
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
else
|
|
241
|
+
{
|
|
242
|
+
if (cosmeticEffects.Count != other.cosmeticEffects.Count)
|
|
243
|
+
{
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
for (int i = 0; i < cosmeticEffects.Count; ++i)
|
|
248
|
+
{
|
|
249
|
+
if (!Equals(cosmeticEffects[i], other.cosmeticEffects[i]))
|
|
250
|
+
{
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
public override bool Equals(object obj)
|
|
260
|
+
{
|
|
261
|
+
return ReferenceEquals(this, obj) || obj is AttributeEffect other && Equals(other);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
public override int GetHashCode()
|
|
265
|
+
{
|
|
266
|
+
return Objects.HashCode(
|
|
267
|
+
modifications?.Count,
|
|
268
|
+
durationType,
|
|
269
|
+
duration,
|
|
270
|
+
resetDurationOnReapplication,
|
|
271
|
+
effectTags?.Count,
|
|
272
|
+
cosmeticEffects?.Count
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
namespace WallstopStudios.UnityHelpers.Tags
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using Core.Extension;
|
|
5
|
+
using Core.Helper;
|
|
6
|
+
|
|
7
|
+
[Serializable]
|
|
8
|
+
public struct AttributeModification : IEquatable<AttributeModification>
|
|
9
|
+
{
|
|
10
|
+
[StringInList(typeof(AttributeUtilities), nameof(AttributeUtilities.GetAllAttributeNames))]
|
|
11
|
+
public string attribute;
|
|
12
|
+
|
|
13
|
+
public ModificationAction action;
|
|
14
|
+
public float value;
|
|
15
|
+
|
|
16
|
+
public override string ToString()
|
|
17
|
+
{
|
|
18
|
+
return this.ToJson();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public static bool operator !=(AttributeModification lhs, AttributeModification rhs)
|
|
22
|
+
{
|
|
23
|
+
return !(lhs == rhs);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public static bool operator ==(AttributeModification lhs, AttributeModification rhs)
|
|
27
|
+
{
|
|
28
|
+
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
|
29
|
+
return string.Equals(lhs.attribute, rhs.attribute)
|
|
30
|
+
&& lhs.action == rhs.action
|
|
31
|
+
&& lhs.value == rhs.value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public override bool Equals(object obj)
|
|
35
|
+
{
|
|
36
|
+
return obj is AttributeModification other && Equals(other);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public override int GetHashCode()
|
|
40
|
+
{
|
|
41
|
+
return Objects.HashCode(attribute, action, value);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public bool Equals(AttributeModification other)
|
|
45
|
+
{
|
|
46
|
+
return string.Equals(attribute, other.attribute, StringComparison.Ordinal)
|
|
47
|
+
&& action == other.action
|
|
48
|
+
&& value.Equals(other.value);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
namespace WallstopStudios.UnityHelpers.Tags
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Collections.Generic;
|
|
5
|
+
using System.Linq;
|
|
6
|
+
using System.Reflection;
|
|
7
|
+
using Core.Extension;
|
|
8
|
+
using Core.Helper;
|
|
9
|
+
using Object = UnityEngine.Object;
|
|
10
|
+
|
|
11
|
+
public static class AttributeUtilities
|
|
12
|
+
{
|
|
13
|
+
private static string[] AllAttributeNames;
|
|
14
|
+
private static readonly Dictionary<Type, Dictionary<string, FieldInfo>> AttributeFields =
|
|
15
|
+
new();
|
|
16
|
+
|
|
17
|
+
// TODO: Use TypeCache + serialize
|
|
18
|
+
public static string[] GetAllAttributeNames()
|
|
19
|
+
{
|
|
20
|
+
return AllAttributeNames ??= AppDomain
|
|
21
|
+
.CurrentDomain.GetAssemblies()
|
|
22
|
+
.SelectMany(assembly => assembly.GetTypes())
|
|
23
|
+
.Where(type => !type.IsAbstract)
|
|
24
|
+
.Where(type => type.IsSubclassOf(typeof(AttributesComponent)))
|
|
25
|
+
.SelectMany(type =>
|
|
26
|
+
type.GetFields(
|
|
27
|
+
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
.Where(fieldInfo => fieldInfo.FieldType == typeof(Attribute))
|
|
31
|
+
.Select(fieldInfo => fieldInfo.Name)
|
|
32
|
+
.Distinct()
|
|
33
|
+
.Ordered()
|
|
34
|
+
.ToArray();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public static bool HasTag(this Object target, string effectTag)
|
|
38
|
+
{
|
|
39
|
+
if (target == null)
|
|
40
|
+
{
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return target.TryGetComponent(out TagHandler tagHandler)
|
|
45
|
+
&& tagHandler.HasTag(effectTag);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public static bool HasAnyTag(this Object target, IEnumerable<string> effectTags)
|
|
49
|
+
{
|
|
50
|
+
if (target == null)
|
|
51
|
+
{
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return target.TryGetComponent(out TagHandler tagHandler)
|
|
56
|
+
&& tagHandler.HasAnyTag(effectTags);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public static bool HasAnyTag(this Object target, IReadOnlyList<string> effectTags)
|
|
60
|
+
{
|
|
61
|
+
if (target == null)
|
|
62
|
+
{
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return target.TryGetComponent(out TagHandler tagHandler)
|
|
67
|
+
&& tagHandler.HasAnyTag(effectTags);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public static EffectHandle? ApplyEffect(this Object target, AttributeEffect attributeEffect)
|
|
71
|
+
{
|
|
72
|
+
if (target == null)
|
|
73
|
+
{
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
EffectHandler effectHandler = target.GetGameObject().GetOrAddComponent<EffectHandler>();
|
|
78
|
+
return effectHandler.ApplyEffect(attributeEffect);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public static void ApplyEffectsNoAlloc(
|
|
82
|
+
this Object target,
|
|
83
|
+
List<AttributeEffect> attributeEffects
|
|
84
|
+
)
|
|
85
|
+
{
|
|
86
|
+
if (attributeEffects is not { Count: > 0 })
|
|
87
|
+
{
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (target == null)
|
|
92
|
+
{
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
EffectHandler effectHandler = target.GetGameObject().GetOrAddComponent<EffectHandler>();
|
|
96
|
+
foreach (AttributeEffect attributeEffect in attributeEffects)
|
|
97
|
+
{
|
|
98
|
+
_ = effectHandler.ApplyEffect(attributeEffect);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public static void ApplyEffectsNoAlloc(
|
|
103
|
+
this Object target,
|
|
104
|
+
IEnumerable<AttributeEffect> attributeEffects
|
|
105
|
+
)
|
|
106
|
+
{
|
|
107
|
+
if (target == null)
|
|
108
|
+
{
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
EffectHandler effectHandler = target.GetGameObject().GetOrAddComponent<EffectHandler>();
|
|
113
|
+
foreach (AttributeEffect attributeEffect in attributeEffects)
|
|
114
|
+
{
|
|
115
|
+
_ = effectHandler.ApplyEffect(attributeEffect);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public static void ApplyEffectsNoAlloc(
|
|
120
|
+
this Object target,
|
|
121
|
+
List<AttributeEffect> attributeEffects,
|
|
122
|
+
List<EffectHandle> effectHandles
|
|
123
|
+
)
|
|
124
|
+
{
|
|
125
|
+
if (target == null)
|
|
126
|
+
{
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
EffectHandler effectHandler = target.GetGameObject().GetOrAddComponent<EffectHandler>();
|
|
131
|
+
foreach (AttributeEffect attributeEffect in attributeEffects)
|
|
132
|
+
{
|
|
133
|
+
EffectHandle? handle = effectHandler.ApplyEffect(attributeEffect);
|
|
134
|
+
if (handle.HasValue)
|
|
135
|
+
{
|
|
136
|
+
effectHandles.Add(handle.Value);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public static List<EffectHandle> ApplyEffects(
|
|
142
|
+
this Object target,
|
|
143
|
+
List<AttributeEffect> attributeEffects
|
|
144
|
+
)
|
|
145
|
+
{
|
|
146
|
+
List<EffectHandle> handles = new(attributeEffects.Count);
|
|
147
|
+
ApplyEffectsNoAlloc(target, attributeEffects, handles);
|
|
148
|
+
return handles;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public static void RemoveEffect(this Object target, EffectHandle effectHandle)
|
|
152
|
+
{
|
|
153
|
+
if (target == null)
|
|
154
|
+
{
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (target.TryGetComponent(out EffectHandler effectHandler))
|
|
159
|
+
{
|
|
160
|
+
effectHandler.RemoveEffect(effectHandle);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
public static void RemoveEffects(this Object target, List<EffectHandle> effectHandles)
|
|
165
|
+
{
|
|
166
|
+
if (target == null || effectHandles.Count <= 0)
|
|
167
|
+
{
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (target.TryGetComponent(out EffectHandler effectHandler))
|
|
172
|
+
{
|
|
173
|
+
foreach (EffectHandle effectHandle in effectHandles)
|
|
174
|
+
{
|
|
175
|
+
effectHandler.RemoveEffect(effectHandle);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public static void RemoveAllEffects(this Object target)
|
|
181
|
+
{
|
|
182
|
+
if (target == null)
|
|
183
|
+
{
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (target.TryGetComponent(out EffectHandler effectHandler))
|
|
188
|
+
{
|
|
189
|
+
effectHandler.RemoveAllEffects();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
public static Dictionary<string, FieldInfo> GetAttributeFields(Type type)
|
|
194
|
+
{
|
|
195
|
+
return AttributeFields.GetOrAdd(
|
|
196
|
+
type,
|
|
197
|
+
inputType =>
|
|
198
|
+
{
|
|
199
|
+
return inputType
|
|
200
|
+
.GetFields(
|
|
201
|
+
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
|
202
|
+
)
|
|
203
|
+
.Where(field => field.FieldType == typeof(Attribute))
|
|
204
|
+
.ToDictionary(field => field.Name, StringComparer.Ordinal);
|
|
205
|
+
}
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
namespace WallstopStudios.UnityHelpers.Tags
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Collections.Generic;
|
|
5
|
+
using System.Reflection;
|
|
6
|
+
using Core.Attributes;
|
|
7
|
+
using UnityEngine;
|
|
8
|
+
|
|
9
|
+
[RequireComponent(typeof(TagHandler))]
|
|
10
|
+
[RequireComponent(typeof(EffectHandler))]
|
|
11
|
+
public abstract class AttributesComponent : MonoBehaviour
|
|
12
|
+
{
|
|
13
|
+
public event Action<string, float, float> OnAttributeModified;
|
|
14
|
+
|
|
15
|
+
private readonly Dictionary<string, FieldInfo> _attributeFields;
|
|
16
|
+
private readonly HashSet<EffectHandle> _effectHandles;
|
|
17
|
+
|
|
18
|
+
[SiblingComponent]
|
|
19
|
+
protected TagHandler _tagHandler;
|
|
20
|
+
|
|
21
|
+
[SiblingComponent]
|
|
22
|
+
protected EffectHandler _effectHandler;
|
|
23
|
+
|
|
24
|
+
protected AttributesComponent()
|
|
25
|
+
{
|
|
26
|
+
_attributeFields = AttributeUtilities.GetAttributeFields(GetType());
|
|
27
|
+
_effectHandles = new HashSet<EffectHandle>();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
protected virtual void Awake()
|
|
31
|
+
{
|
|
32
|
+
this.AssignSiblingComponents();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public void ApplyAttributeModifications(
|
|
36
|
+
IEnumerable<AttributeModification> attributeModifications,
|
|
37
|
+
EffectHandle? handle
|
|
38
|
+
)
|
|
39
|
+
{
|
|
40
|
+
if (handle.HasValue)
|
|
41
|
+
{
|
|
42
|
+
ForceApplyAttributeModifications(handle.Value);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
InternalApplyAttributeModifications(attributeModifications);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public void ForceRemoveAttributeModifications(EffectHandle handle)
|
|
50
|
+
{
|
|
51
|
+
InternalRemoveAttributeModifications(handle);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private void InternalApplyAttributeModifications(
|
|
55
|
+
IEnumerable<AttributeModification> attributeModifications
|
|
56
|
+
)
|
|
57
|
+
{
|
|
58
|
+
foreach (AttributeModification modification in attributeModifications)
|
|
59
|
+
{
|
|
60
|
+
if (!TryGetAttribute(modification.attribute, out Attribute attribute))
|
|
61
|
+
{
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
float oldValue = attribute;
|
|
66
|
+
attribute.ApplyAttributeModification(modification);
|
|
67
|
+
float currentValue = attribute;
|
|
68
|
+
|
|
69
|
+
OnAttributeModified?.Invoke(modification.attribute, oldValue, currentValue);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public void ForceApplyAttributeModifications(EffectHandle handle)
|
|
74
|
+
{
|
|
75
|
+
AttributeEffect effect = handle.effect;
|
|
76
|
+
if (effect.modifications is not { Count: > 0 })
|
|
77
|
+
{
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
bool isNewEffect = false;
|
|
82
|
+
foreach (AttributeModification modification in effect.modifications)
|
|
83
|
+
{
|
|
84
|
+
if (!TryGetAttribute(modification.attribute, out Attribute attribute))
|
|
85
|
+
{
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
isNewEffect = isNewEffect || _effectHandles.Add(handle);
|
|
90
|
+
if (isNewEffect)
|
|
91
|
+
{
|
|
92
|
+
float oldValue = attribute;
|
|
93
|
+
attribute.ApplyAttributeModification(modification, handle);
|
|
94
|
+
float currentValue = attribute;
|
|
95
|
+
OnAttributeModified?.Invoke(modification.attribute, oldValue, currentValue);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public void ForceApplyAttributeModifications(AttributeEffect effect)
|
|
101
|
+
{
|
|
102
|
+
if (effect.modifications is not { Count: > 0 })
|
|
103
|
+
{
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
foreach (AttributeModification modification in effect.modifications)
|
|
108
|
+
{
|
|
109
|
+
if (!TryGetAttribute(modification.attribute, out Attribute attribute))
|
|
110
|
+
{
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
float oldValue = attribute;
|
|
115
|
+
attribute.ApplyAttributeModification(modification);
|
|
116
|
+
float currentValue = attribute;
|
|
117
|
+
OnAttributeModified?.Invoke(modification.attribute, oldValue, currentValue);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private void InternalRemoveAttributeModifications(EffectHandle handle)
|
|
122
|
+
{
|
|
123
|
+
AttributeEffect effect = handle.effect;
|
|
124
|
+
if (effect.modifications is not { Count: > 0 })
|
|
125
|
+
{
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
foreach (AttributeModification modification in effect.modifications)
|
|
130
|
+
{
|
|
131
|
+
if (!TryGetAttribute(modification.attribute, out Attribute attribute))
|
|
132
|
+
{
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
float oldValue = attribute;
|
|
137
|
+
_ = attribute.RemoveAttributeModification(handle);
|
|
138
|
+
float currentValue = attribute;
|
|
139
|
+
_ = _effectHandles.Remove(handle);
|
|
140
|
+
OnAttributeModified?.Invoke(modification.attribute, oldValue, currentValue);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private bool TryGetAttribute(string attributeName, out Attribute attribute)
|
|
145
|
+
{
|
|
146
|
+
if (!_attributeFields.TryGetValue(attributeName, out FieldInfo fieldInfo))
|
|
147
|
+
{
|
|
148
|
+
attribute = default;
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
object fieldValue = fieldInfo.GetValue(this);
|
|
153
|
+
if (fieldValue is Attribute fieldAttribute)
|
|
154
|
+
{
|
|
155
|
+
attribute = fieldAttribute;
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
attribute = default;
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|