com.wallstop-studios.unity-helpers 2.0.0-rc67 → 2.0.0-rc69
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/Runtime/Core/Attributes/ValidateAssignmentAttribute.cs +1 -1
- package/Runtime/Core/Helper/Helpers.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 +208 -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 +379 -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/SpatialTreeTests.cs +1 -1
- package/Tests/Runtime/Helper/ObjectHelperTests.cs +1 -0
- package/package.json +1 -1
- /package/Runtime/{Utils → Tags}/TagHandler.cs.meta +0 -0
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
{
|
|
21
21
|
private static readonly WaitForEndOfFrame WaitForEndOfFrame = new();
|
|
22
22
|
private static readonly Dictionary<Type, MethodInfo> AwakeMethodsByType = new();
|
|
23
|
-
private static readonly Object LogObject = new()
|
|
23
|
+
private static readonly Object LogObject = new();
|
|
24
24
|
private static readonly Dictionary<string, Object> ObjectsByTag = new(
|
|
25
25
|
StringComparer.Ordinal
|
|
26
26
|
);
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
{
|
|
3
3
|
using System;
|
|
4
4
|
using Extension;
|
|
5
|
+
using UnityEditor;
|
|
6
|
+
using UnityEditor.SceneManagement;
|
|
5
7
|
using UnityEngine;
|
|
6
8
|
using UnityEngine.SceneManagement;
|
|
7
9
|
using Object = UnityEngine.Object;
|
|
8
|
-
|
|
9
|
-
using UnityEditor;
|
|
10
|
-
using UnityEditor.SceneManagement;
|
|
11
|
-
#endif
|
|
10
|
+
|
|
12
11
|
public static partial class Helpers
|
|
13
12
|
{
|
|
14
13
|
public static T Find<T>(this Object component, string tag, bool log = true)
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
namespace WallstopStudios.UnityHelpers.Tags
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Collections.Generic;
|
|
5
|
+
using System.ComponentModel;
|
|
6
|
+
using System.Globalization;
|
|
7
|
+
using System.Linq;
|
|
8
|
+
using System.Runtime.Serialization;
|
|
9
|
+
using System.Text.Json.Serialization;
|
|
10
|
+
using Core.Extension;
|
|
11
|
+
using ProtoBuf;
|
|
12
|
+
using UnityEngine;
|
|
13
|
+
|
|
14
|
+
[Serializable]
|
|
15
|
+
[ProtoContract]
|
|
16
|
+
public sealed class Attribute : IEquatable<Attribute>, IEquatable<float>
|
|
17
|
+
{
|
|
18
|
+
public float CurrentValue
|
|
19
|
+
{
|
|
20
|
+
get
|
|
21
|
+
{
|
|
22
|
+
#if UNITY_EDITOR
|
|
23
|
+
/*
|
|
24
|
+
For some reason, there's a bug with loot tables where
|
|
25
|
+
_currentValueCalculated will be true but the current
|
|
26
|
+
value is not calculated, so ignore the flag if we're
|
|
27
|
+
in editor mode, where this happens
|
|
28
|
+
*/
|
|
29
|
+
if (Application.isPlaying)
|
|
30
|
+
#endif
|
|
31
|
+
{
|
|
32
|
+
if (_currentValueCalculated)
|
|
33
|
+
{
|
|
34
|
+
return _currentValue;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
CalculateCurrentValue();
|
|
39
|
+
return _currentValue;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public float BaseValue => _baseValue;
|
|
44
|
+
|
|
45
|
+
[SerializeField]
|
|
46
|
+
internal float _baseValue;
|
|
47
|
+
|
|
48
|
+
[SerializeField]
|
|
49
|
+
private float _currentValue;
|
|
50
|
+
|
|
51
|
+
private bool _currentValueCalculated;
|
|
52
|
+
|
|
53
|
+
internal void CalculateCurrentValue()
|
|
54
|
+
{
|
|
55
|
+
float calculatedValue = _baseValue;
|
|
56
|
+
foreach (
|
|
57
|
+
AttributeModification attributeModification in _modifications
|
|
58
|
+
.SelectMany(kvp => kvp.Value)
|
|
59
|
+
.OrderBy(mod => mod.action)
|
|
60
|
+
)
|
|
61
|
+
{
|
|
62
|
+
ApplyAttributeModification(attributeModification, ref calculatedValue);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
_currentValue = calculatedValue;
|
|
66
|
+
_currentValueCalculated = true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private readonly Dictionary<EffectHandle, List<AttributeModification>> _modifications =
|
|
70
|
+
new();
|
|
71
|
+
|
|
72
|
+
public static implicit operator float(Attribute attribute) => attribute.CurrentValue;
|
|
73
|
+
|
|
74
|
+
public static implicit operator Attribute(float value) => new(value);
|
|
75
|
+
|
|
76
|
+
public Attribute()
|
|
77
|
+
: this(0) { }
|
|
78
|
+
|
|
79
|
+
public Attribute(float value)
|
|
80
|
+
{
|
|
81
|
+
_baseValue = value;
|
|
82
|
+
_currentValueCalculated = false;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
[JsonConstructor]
|
|
86
|
+
public Attribute(float baseValue, float currentValue)
|
|
87
|
+
{
|
|
88
|
+
_baseValue = baseValue;
|
|
89
|
+
_currentValue = currentValue;
|
|
90
|
+
_currentValueCalculated = true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public void ClearCache()
|
|
94
|
+
{
|
|
95
|
+
_currentValueCalculated = false;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public void ApplyAttributeModification(
|
|
99
|
+
AttributeModification attributeModification,
|
|
100
|
+
EffectHandle? handle = null
|
|
101
|
+
)
|
|
102
|
+
{
|
|
103
|
+
// If we don't have a handle, then this is an instant effect, apply it to the base value.
|
|
104
|
+
if (!handle.HasValue)
|
|
105
|
+
{
|
|
106
|
+
ApplyAttributeModification(attributeModification, ref _baseValue);
|
|
107
|
+
}
|
|
108
|
+
else
|
|
109
|
+
{
|
|
110
|
+
_modifications.GetOrAdd(handle.Value).Add(attributeModification);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
CalculateCurrentValue();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public bool RemoveAttributeModification(EffectHandle handle)
|
|
117
|
+
{
|
|
118
|
+
bool removed = _modifications.Remove(handle);
|
|
119
|
+
if (removed)
|
|
120
|
+
{
|
|
121
|
+
CalculateCurrentValue();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return removed;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
[OnDeserialized]
|
|
128
|
+
private void AfterDeserialize(StreamingContext streamingContext)
|
|
129
|
+
{
|
|
130
|
+
ClearCache();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
[ProtoAfterDeserialization]
|
|
134
|
+
private void AfterProtoDeserialized()
|
|
135
|
+
{
|
|
136
|
+
ClearCache();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private static void ApplyAttributeModification(
|
|
140
|
+
AttributeModification attributeModification,
|
|
141
|
+
ref float value
|
|
142
|
+
)
|
|
143
|
+
{
|
|
144
|
+
switch (attributeModification.action)
|
|
145
|
+
{
|
|
146
|
+
case ModificationAction.Addition:
|
|
147
|
+
value += attributeModification.value;
|
|
148
|
+
break;
|
|
149
|
+
case ModificationAction.Multiplication:
|
|
150
|
+
value *= attributeModification.value;
|
|
151
|
+
break;
|
|
152
|
+
case ModificationAction.Override:
|
|
153
|
+
value = attributeModification.value;
|
|
154
|
+
break;
|
|
155
|
+
default:
|
|
156
|
+
throw new InvalidEnumArgumentException(
|
|
157
|
+
nameof(attributeModification.action),
|
|
158
|
+
(int)attributeModification.action,
|
|
159
|
+
typeof(ModificationAction)
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
public bool Equals(Attribute other)
|
|
165
|
+
{
|
|
166
|
+
if (ReferenceEquals(this, other))
|
|
167
|
+
{
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return other != null && CurrentValue.Equals(other.CurrentValue);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
public override bool Equals(object other)
|
|
175
|
+
{
|
|
176
|
+
switch (other)
|
|
177
|
+
{
|
|
178
|
+
case Attribute attribute:
|
|
179
|
+
return Equals(attribute);
|
|
180
|
+
case float attribute:
|
|
181
|
+
return Equals(attribute);
|
|
182
|
+
case double attribute:
|
|
183
|
+
return Equals((float)attribute);
|
|
184
|
+
default:
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
public bool Equals(float other)
|
|
190
|
+
{
|
|
191
|
+
return CurrentValue.Equals(other);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public override int GetHashCode()
|
|
195
|
+
{
|
|
196
|
+
// ReSharper disable once BaseObjectGetHashCodeCallInGetHashCode
|
|
197
|
+
return base.GetHashCode();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public override string ToString()
|
|
201
|
+
{
|
|
202
|
+
return ((float)this).ToString(CultureInfo.InvariantCulture);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -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
|
+
}
|