com.wallstop-studios.unity-helpers 2.0.0-rc61 → 2.0.0-rc63

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.
Files changed (177) hide show
  1. package/Editor/AnimationCopier.cs +7 -14
  2. package/Editor/AnimationCreator.cs +7 -11
  3. package/Editor/AnimationEventEditor.cs +6 -6
  4. package/Editor/AnimatorControllerCopier.cs +7 -13
  5. package/Editor/CustomEditors/MatchColliderToSpriteEditor.cs +4 -6
  6. package/Editor/FitTextureSizeWizard.cs +4 -4
  7. package/Editor/PrefabCheckWizard.cs +10 -13
  8. package/Editor/SpriteSettingsApplier.cs +4 -4
  9. package/Editor/StringInListeDrawer.cs +2 -2
  10. package/Editor/TextureResizerWizard.cs +6 -12
  11. package/Editor/TextureSettingsApplier.cs +5 -5
  12. package/Editor/Utils/DxReadOnlyPropertyDrawer.cs +2 -2
  13. package/Editor/Utils/EditorUtilities.cs +1 -1
  14. package/Editor/WShowIfPropertyDrawer.cs +4 -4
  15. package/Editor/WallstopStudios.UnityHelpers.Editor.asmdef +1 -1
  16. package/Runtime/Core/Attributes/AnimationEventAttribute.cs +1 -1
  17. package/Runtime/Core/Attributes/ChildComponentAttribute.cs +2 -1
  18. package/Runtime/Core/Attributes/DxReadOnlyAttribute.cs +1 -1
  19. package/Runtime/Core/Attributes/KSerializableAttribute.cs +1 -1
  20. package/Runtime/Core/Attributes/NotNullAttribute.cs +1 -1
  21. package/Runtime/Core/Attributes/ParentComponent.cs +1 -1
  22. package/Runtime/Core/Attributes/RelationalComponentExtensions.cs +1 -1
  23. package/Runtime/Core/Attributes/SiblingComponentAttribute.cs +1 -1
  24. package/Runtime/Core/Attributes/ValidateAssignmentAttribute.cs +12 -7
  25. package/Runtime/Core/Attributes/WShowIfAttribute.cs +1 -1
  26. package/Runtime/Core/DataStructure/Adapters/FastVector2Int.cs +1 -1
  27. package/Runtime/Core/DataStructure/Adapters/FastVector3Int.cs +1 -1
  28. package/Runtime/Core/DataStructure/Adapters/KGuid.cs +1 -1
  29. package/Runtime/Core/DataStructure/Adapters/KVector2.cs +1 -1
  30. package/Runtime/Core/DataStructure/Circle.cs +1 -1
  31. package/Runtime/Core/DataStructure/CyclicBuffer.cs +1 -1
  32. package/Runtime/Core/DataStructure/ISpatialTree.cs +1 -1
  33. package/Runtime/Core/DataStructure/KDTree.cs +1 -1
  34. package/Runtime/Core/DataStructure/QuadTree.cs +1 -1
  35. package/Runtime/Core/DataStructure/RTree.cs +1 -1
  36. package/Runtime/Core/DataStructure/StringWrapper.cs +1 -1
  37. package/Runtime/Core/DataStructure/TimedCache.cs +1 -1
  38. package/Runtime/Core/Extension/AnimatorExtensions.cs +1 -1
  39. package/Runtime/Core/Extension/AsyncOperationExtensions.cs +1 -1
  40. package/Runtime/Core/Extension/CircleExtensions.cs +1 -1
  41. package/Runtime/Core/Extension/ColorExtensions.cs +16 -1
  42. package/Runtime/Core/Extension/DictionaryExtensions.cs +1 -1
  43. package/Runtime/Core/Extension/DirectionExtensions.cs +1 -1
  44. package/Runtime/Core/Extension/EnumExtensions.cs +1 -1
  45. package/Runtime/Core/Extension/HashSetExtensions.cs +1 -1
  46. package/Runtime/Core/Extension/IEnumerableExtensions.cs +1 -1
  47. package/Runtime/Core/Extension/IListExtensions.cs +1 -1
  48. package/Runtime/Core/Extension/LoggingExtensions.cs +69 -122
  49. package/Runtime/Core/Extension/RandomExtensions.cs +1 -1
  50. package/Runtime/Core/Extension/SerializedPropertyExtensions.cs +2 -2
  51. package/Runtime/Core/Extension/StringExtensions.cs +1 -1
  52. package/Runtime/Core/Extension/UnityExtensions.cs +1 -2
  53. package/Runtime/Core/Helper/ArrayConverter.cs +1 -1
  54. package/Runtime/Core/Helper/AssignUtilities.cs +1 -1
  55. package/Runtime/Core/Helper/DirectoryHelper.cs +1 -1
  56. package/Runtime/Core/Helper/Enumerables.cs +1 -1
  57. package/Runtime/Core/Helper/FormattingHelpers.cs +1 -1
  58. package/Runtime/Core/Helper/Geometry.cs +1 -1
  59. package/Runtime/Core/Helper/Helpers.cs +6 -9
  60. package/Runtime/Core/Helper/IterationHelpers.cs +1 -1
  61. package/Runtime/Core/Helper/LifetimeHelpers.cs +2 -1
  62. package/Runtime/Core/Helper/Logging/UnityLogTagFormatter.cs +517 -0
  63. package/Runtime/Core/Helper/Logging/UnityLogTagFormatter.cs.meta +3 -0
  64. package/Runtime/Core/Helper/Logging.meta +3 -0
  65. package/Runtime/Core/Helper/Objects.cs +1 -1
  66. package/Runtime/Core/Helper/Partials/LogHelpers.cs +2 -2
  67. package/Runtime/Core/Helper/Partials/MathHelpers.cs +1 -1
  68. package/Runtime/Core/Helper/Partials/ObjectHelpers.cs +5 -11
  69. package/Runtime/Core/Helper/Partials/TransformHelpers.cs +1 -1
  70. package/Runtime/Core/Helper/ReflectionHelpers.cs +173 -36
  71. package/Runtime/Core/Helper/SceneHelper.cs +3 -5
  72. package/Runtime/Core/Helper/SpriteHelpers.cs +3 -3
  73. package/Runtime/Core/Helper/StringInList.cs +1 -1
  74. package/Runtime/Core/Helper/UnityMainThreadDispatcher.cs +2 -4
  75. package/Runtime/Core/Helper/WallMath.cs +1 -1
  76. package/Runtime/Core/Math/Line.cs +1 -1
  77. package/Runtime/Core/Math/Parabola.cs +1 -1
  78. package/Runtime/Core/Math/PointPolygonCheck.cs +1 -1
  79. package/Runtime/Core/Math/Range.cs +1 -1
  80. package/Runtime/Core/Math/XXHash.cs +1 -1
  81. package/Runtime/Core/Model/Direction.cs +1 -1
  82. package/Runtime/Core/OneOf/FastOneOf.cs +1 -1
  83. package/Runtime/Core/OneOf/None.cs +1 -1
  84. package/Runtime/Core/Random/AbstractRandom.cs +1 -1
  85. package/Runtime/Core/Random/DotNetRandom.cs +1 -1
  86. package/Runtime/Core/Random/IRandom.cs +1 -1
  87. package/Runtime/Core/Random/LinearCongruentialGenerator.cs +1 -1
  88. package/Runtime/Core/Random/NativePcgRandom.cs +1 -1
  89. package/Runtime/Core/Random/PRNG.cs +1 -1
  90. package/Runtime/Core/Random/PcgRandom.cs +1 -1
  91. package/Runtime/Core/Random/PerlinNoise.cs +1 -1
  92. package/Runtime/Core/Random/RandomState.cs +1 -1
  93. package/Runtime/Core/Random/RandomUtilities.cs +1 -1
  94. package/Runtime/Core/Random/RomuDuo.cs +1 -1
  95. package/Runtime/Core/Random/SplitMix64.cs +1 -1
  96. package/Runtime/Core/Random/SquirrelRandom.cs +1 -1
  97. package/Runtime/Core/Random/SystemRandom.cs +1 -1
  98. package/Runtime/Core/Random/ThreadLocalRandom.cs +1 -1
  99. package/Runtime/Core/Random/UnityRandom.cs +1 -1
  100. package/Runtime/Core/Random/WyRandom.cs +1 -1
  101. package/Runtime/Core/Random/XorShiftRandom.cs +1 -1
  102. package/Runtime/Core/Random/XorShiroRandom.cs +1 -1
  103. package/Runtime/Core/Serialization/JsonConverters/ColorConverter.cs +1 -1
  104. package/Runtime/Core/Serialization/JsonConverters/GameObjectConverter.cs +1 -2
  105. package/Runtime/Core/Serialization/JsonConverters/Matrix4x4Converter.cs +1 -1
  106. package/Runtime/Core/Serialization/JsonConverters/TypeConverter.cs +1 -1
  107. package/Runtime/Core/Serialization/JsonConverters/Vector2Converter.cs +1 -1
  108. package/Runtime/Core/Serialization/JsonConverters/Vector3Converter.cs +1 -1
  109. package/Runtime/Core/Serialization/JsonConverters/Vector4Converter.cs +1 -1
  110. package/Runtime/Core/Serialization/Serializer.cs +1 -1
  111. package/Runtime/Core/Threading/SingleThreadedThreadPool.cs +1 -1
  112. package/Runtime/UI/LayeredImage.cs +1 -1
  113. package/Runtime/Utils/AnimationEventEqualityComparer.cs +1 -1
  114. package/Runtime/Utils/AnimatorEnumStateMachine.cs +1 -1
  115. package/Runtime/Utils/Buffers.cs +1 -1
  116. package/Runtime/Utils/CenterPointOffset.cs +1 -1
  117. package/Runtime/Utils/CircleLineRenderer.cs +4 -6
  118. package/Runtime/Utils/CoroutineHandler.cs +1 -1
  119. package/Runtime/Utils/DeferredDisposalResult.cs +1 -1
  120. package/Runtime/Utils/MatchColliderToSprite.cs +1 -1
  121. package/Runtime/Utils/Oscillator.cs +1 -1
  122. package/Runtime/Utils/RuntimeSingleton.cs +1 -1
  123. package/Runtime/Utils/SetTextureImportData.cs +1 -1
  124. package/Runtime/Utils/SpriteRendererMetadata.cs +1 -1
  125. package/Runtime/Utils/SpriteRendererSyncer.cs +1 -1
  126. package/Runtime/Utils/StartTracker.cs +1 -1
  127. package/Runtime/Utils/TextureScale.cs +1 -1
  128. package/Runtime/Utils/TypeNameSorter.cs +17 -0
  129. package/Runtime/Utils/TypeNameSorter.cs.meta +3 -0
  130. package/Runtime/Utils/UnityObjectNameComparer.cs +1 -1
  131. package/Runtime/WallstopStudios.UnityHelpers.asmdef +1 -1
  132. package/Tests/Runtime/Attributes/ChildComponentTests.cs +2 -2
  133. package/Tests/Runtime/Attributes/Components/ExpectChildSpriteRenderers.cs +2 -2
  134. package/Tests/Runtime/Attributes/Components/ExpectParentSpriteRenderers.cs +2 -2
  135. package/Tests/Runtime/Attributes/ParentComponentTests.cs +2 -2
  136. package/Tests/Runtime/Components/RelationalComponentTesterComplex.cs +2 -2
  137. package/Tests/Runtime/Components/RelationalComponentsTesterSimple.cs +4 -4
  138. package/Tests/Runtime/DataStructures/BalancedKDTreeTests.cs +2 -2
  139. package/Tests/Runtime/DataStructures/CyclicBufferTests.cs +3 -3
  140. package/Tests/Runtime/DataStructures/QuadTreeTests.cs +2 -2
  141. package/Tests/Runtime/DataStructures/SpatialTreeTests.cs +4 -4
  142. package/Tests/Runtime/DataStructures/UnbalancedKDTreeTests.cs +2 -2
  143. package/Tests/Runtime/Extensions/DictionaryExtensionTests.cs +2 -3
  144. package/Tests/Runtime/Extensions/EnumExtensionTests.cs +2 -2
  145. package/Tests/Runtime/Extensions/IListExtensionTests.cs +3 -3
  146. package/Tests/Runtime/Extensions/LoggingExtensionTests.cs +718 -0
  147. package/Tests/Runtime/Extensions/LoggingExtensionTests.cs.meta +3 -0
  148. package/Tests/Runtime/Extensions/RandomExtensionTests.cs +3 -3
  149. package/Tests/Runtime/Extensions/StringExtensionTests.cs +2 -2
  150. package/Tests/Runtime/Helper/ArrayConverterTests.cs +3 -3
  151. package/Tests/Runtime/Helper/FormattingHelperTests.cs +3 -3
  152. package/Tests/Runtime/Helper/ObjectHelperTests.cs +2 -2
  153. package/Tests/Runtime/Helper/ReflectionHelperTests.cs +3 -3
  154. package/Tests/Runtime/Helper/SceneHelperTests.cs +3 -3
  155. package/Tests/Runtime/Helper/WallMathTests.cs +5 -5
  156. package/Tests/Runtime/Performance/KDTreePerformanceTests.cs +2 -2
  157. package/Tests/Runtime/Performance/QuadTreePerformanceTests.cs +2 -2
  158. package/Tests/Runtime/Performance/RandomPerformanceTests.cs +2 -2
  159. package/Tests/Runtime/Performance/RelationComponentPerformanceTests.cs +2 -2
  160. package/Tests/Runtime/Performance/SpatialTreePerformanceTest.cs +2 -2
  161. package/Tests/Runtime/Performance/UnbalancedKDTreeTests.cs +2 -2
  162. package/Tests/Runtime/Random/DotNetRandomTests.cs +2 -2
  163. package/Tests/Runtime/Random/LinearCongruentialGeneratorTests.cs +2 -2
  164. package/Tests/Runtime/Random/PcgRandomTests.cs +2 -2
  165. package/Tests/Runtime/Random/RandomTestBase.cs +7 -7
  166. package/Tests/Runtime/Random/RomuDuoRandomTests.cs +2 -2
  167. package/Tests/Runtime/Random/SplitMix64RandomTests.cs +2 -2
  168. package/Tests/Runtime/Random/SquirrelRandomTests.cs +2 -2
  169. package/Tests/Runtime/Random/SystemRandomTests.cs +2 -2
  170. package/Tests/Runtime/Random/UnityRandomTests.cs +2 -2
  171. package/Tests/Runtime/Random/WyRandomTests.cs +2 -2
  172. package/Tests/Runtime/Random/XorShiftRandomTests.cs +2 -2
  173. package/Tests/Runtime/Random/XorShiroRandomTests.cs +2 -2
  174. package/Tests/Runtime/Serialization/JsonSerializationTest.cs +5 -5
  175. package/Tests/Runtime/Utils/SpriteRendererMetadataTests.cs +3 -4
  176. package/Tests/Runtime/WallstopStudios.UnityHelpers.Tests.Runtime.asmdef +1 -1
  177. package/package.json +1 -1
@@ -0,0 +1,517 @@
1
+ namespace WallstopStudios.UnityHelpers.Core.Helper.Logging
2
+ {
3
+ using System;
4
+ using System.Collections.Generic;
5
+ using System.Linq;
6
+ using System.Text;
7
+ using Extension;
8
+ using UnityEngine;
9
+ using Debug = UnityEngine.Debug;
10
+ using Object = UnityEngine.Object;
11
+
12
+ /// <summary>
13
+ /// Default supported formats:
14
+ /// b -> Bold text
15
+ /// bold -> Bold text
16
+ /// ! -> Bold text
17
+ /// i -> Italic text
18
+ /// italic -> Italic text
19
+ /// _ -> Italic text
20
+ /// json -> format as JSON
21
+ /// #color-hex -> Colored text
22
+ /// #color-name -> Colored text
23
+ /// color=value -> Colored text
24
+ /// 1-100 -> Sized text
25
+ /// size=1-100 -> Sized text
26
+ /// </summary>
27
+ public sealed class UnityLogTagFormatter : IFormatProvider, ICustomFormatter
28
+ {
29
+ public const char Separator = ',';
30
+
31
+ private static readonly string NewLine = Environment.NewLine;
32
+
33
+ private static readonly Dictionary<string, string> ColorNamesToHex = ReflectionHelpers
34
+ .LoadStaticPropertiesForType<Color>()
35
+ .Where(kvp => kvp.Value.PropertyType == typeof(Color))
36
+ .Select(kvp => (kvp.Key, ((Color)kvp.Value.GetValue(null)).ToHex()))
37
+ .ToDictionary(StringComparer.OrdinalIgnoreCase);
38
+
39
+ /// <summary>
40
+ /// All currently registered decorations by tag.
41
+ /// </summary>
42
+ public IEnumerable<string> Decorations =>
43
+ _matchingDecorations.Values.SelectMany(x => x).Select(value => value.tag);
44
+
45
+ public IReadOnlyCollection<
46
+ IReadOnlyList<(
47
+ string tag,
48
+ bool editorOnly,
49
+ Func<string, bool> predicate,
50
+ Func<string, object, string> formatter
51
+ )>
52
+ > MatchingDecorations => _matchingDecorations.Values;
53
+
54
+ private readonly SortedDictionary<
55
+ int,
56
+ List<(
57
+ string tag,
58
+ bool editorOnly,
59
+ Func<string, bool> predicate,
60
+ Func<string, object, string> formatter
61
+ )>
62
+ > _matchingDecorations = new();
63
+ private readonly StringBuilder _cachedStringBuilder = new();
64
+ private readonly List<string> _cachedDecorators = new();
65
+ private readonly HashSet<string> _appliedTags = new(StringComparer.OrdinalIgnoreCase);
66
+
67
+ public UnityLogTagFormatter()
68
+ : this(true) { }
69
+
70
+ /// <summary>
71
+ /// Creates a new UnityLogTagFormatter.
72
+ /// </summary>
73
+ /// <param name="createDefaultDecorators">If true, applies default decorators (bold, italic, color, size, and json).</param>
74
+ public UnityLogTagFormatter(bool createDefaultDecorators)
75
+ {
76
+ if (!createDefaultDecorators)
77
+ {
78
+ return;
79
+ }
80
+
81
+ AddDecoration(
82
+ format =>
83
+ string.Equals(format, "b", StringComparison.OrdinalIgnoreCase)
84
+ || string.Equals(format, "bold", StringComparison.OrdinalIgnoreCase)
85
+ || string.Equals(format, "!", StringComparison.OrdinalIgnoreCase),
86
+ format: (_, value) => $"<b>{value}</b>",
87
+ tag: "Bold",
88
+ editorOnly: true,
89
+ force: true
90
+ );
91
+
92
+ AddDecoration(
93
+ format =>
94
+ string.Equals(format, "i", StringComparison.OrdinalIgnoreCase)
95
+ || string.Equals(format, "italic", StringComparison.OrdinalIgnoreCase)
96
+ || string.Equals(format, "_", StringComparison.OrdinalIgnoreCase),
97
+ format: (_, value) => $"<i>{value}</i>",
98
+ tag: "Italic",
99
+ editorOnly: true,
100
+ force: true
101
+ );
102
+
103
+ AddDecoration(
104
+ match: "json",
105
+ format: value => value?.ToJson() ?? "{}",
106
+ tag: "JSON",
107
+ editorOnly: false,
108
+ force: true
109
+ );
110
+
111
+ const char colorCharCheck = '#';
112
+ const string colorStringCheck = "color=";
113
+ AddDecoration(
114
+ format =>
115
+ format.StartsWith(colorCharCheck)
116
+ || format.StartsWith(colorStringCheck, StringComparison.OrdinalIgnoreCase),
117
+ format: (format, value) =>
118
+ {
119
+ string baseColor = format.StartsWith(
120
+ colorStringCheck,
121
+ StringComparison.OrdinalIgnoreCase
122
+ )
123
+ ? format.Substring(colorStringCheck.Length)
124
+ : format;
125
+
126
+ string hexCode = ColorNamesToHex.GetValueOrDefault(
127
+ format.StartsWith(colorCharCheck) ? format.Substring(1) : baseColor,
128
+ baseColor
129
+ );
130
+ return $"<color={hexCode}>{value}</color>";
131
+ },
132
+ tag: "Color",
133
+ editorOnly: true,
134
+ force: true
135
+ );
136
+
137
+ const string sizeCheck = "size=";
138
+ AddDecoration(
139
+ format =>
140
+ (
141
+ format.StartsWith(sizeCheck, StringComparison.OrdinalIgnoreCase)
142
+ && int.TryParse(format.Substring(sizeCheck.Length), out _)
143
+ || int.TryParse(format, out _)
144
+ ),
145
+ format: (format, value) =>
146
+ {
147
+ if (!int.TryParse(format, out int size))
148
+ {
149
+ size = int.Parse(format.Substring(sizeCheck.Length));
150
+ }
151
+ return $"<size={size}>{value}</size>";
152
+ },
153
+ tag: "Size",
154
+ editorOnly: true,
155
+ force: true
156
+ );
157
+ }
158
+
159
+ [HideInCallstack]
160
+ public object GetFormat(Type formatType)
161
+ {
162
+ return formatType.IsAssignableFrom(typeof(ICustomFormatter)) ? this : null;
163
+ }
164
+
165
+ [HideInCallstack]
166
+ public string Format(string format, object arg, IFormatProvider formatProvider)
167
+ {
168
+ if (string.IsNullOrWhiteSpace(format))
169
+ {
170
+ return arg?.ToString() ?? string.Empty;
171
+ }
172
+
173
+ _cachedDecorators.Clear();
174
+ if (!format.Contains(Separator))
175
+ {
176
+ _cachedDecorators.Add(format);
177
+ }
178
+ else
179
+ {
180
+ _cachedStringBuilder.Clear();
181
+ foreach (char element in format)
182
+ {
183
+ if (element == Separator)
184
+ {
185
+ if (0 < _cachedStringBuilder.Length)
186
+ {
187
+ _cachedDecorators.Add(_cachedStringBuilder.ToString());
188
+ _cachedStringBuilder.Clear();
189
+ }
190
+ }
191
+ else
192
+ {
193
+ _cachedStringBuilder.Append(element);
194
+ }
195
+ }
196
+ if (0 < _cachedStringBuilder.Length)
197
+ {
198
+ _cachedDecorators.Add(_cachedStringBuilder.ToString());
199
+ _cachedStringBuilder.Clear();
200
+ }
201
+ }
202
+
203
+ _appliedTags.Clear();
204
+ object formatted = arg;
205
+ foreach (string key in _cachedDecorators)
206
+ {
207
+ foreach (
208
+ List<(
209
+ string tag,
210
+ bool editorOnly,
211
+ Func<string, bool> predicate,
212
+ Func<string, object, string> formatter
213
+ )> matchingDecoration in _matchingDecorations.Values
214
+ )
215
+ {
216
+ foreach (
217
+ (
218
+ string tag,
219
+ bool editorOnly,
220
+ Func<string, bool> predicate,
221
+ Func<string, object, string> matchingFormatter
222
+ ) in matchingDecoration
223
+ )
224
+ {
225
+ if (
226
+ (Application.isEditor || !editorOnly)
227
+ && predicate(key)
228
+ && _appliedTags.Add(tag)
229
+ )
230
+ {
231
+ formatted = matchingFormatter(key, formatted);
232
+ }
233
+ }
234
+ }
235
+ }
236
+
237
+ if (0 < _appliedTags.Count)
238
+ {
239
+ return formatted.ToString();
240
+ }
241
+
242
+ if (arg is not string && arg is IFormattable formattable)
243
+ {
244
+ return formattable.ToString(format, this);
245
+ }
246
+
247
+ return arg?.ToString() ?? string.Empty;
248
+ }
249
+
250
+ [HideInCallstack]
251
+ public string Log(
252
+ FormattableString message,
253
+ Object context = null,
254
+ Exception e = null,
255
+ bool pretty = true
256
+ )
257
+ {
258
+ string rendered = Render(message, context, e, pretty);
259
+ if (context != null)
260
+ {
261
+ Debug.Log(rendered, context);
262
+ }
263
+ else
264
+ {
265
+ Debug.Log(rendered);
266
+ }
267
+
268
+ return rendered;
269
+ }
270
+
271
+ [HideInCallstack]
272
+ public string LogWarn(
273
+ FormattableString message,
274
+ Object context = null,
275
+ Exception e = null,
276
+ bool pretty = true
277
+ )
278
+ {
279
+ string rendered = Render(message, context, e, pretty);
280
+ if (context != null)
281
+ {
282
+ Debug.LogWarning(rendered, context);
283
+ }
284
+ else
285
+ {
286
+ Debug.LogWarning(rendered);
287
+ }
288
+
289
+ return rendered;
290
+ }
291
+
292
+ [HideInCallstack]
293
+ public string LogError(
294
+ FormattableString message,
295
+ Object context = null,
296
+ Exception e = null,
297
+ bool pretty = true
298
+ )
299
+ {
300
+ string rendered = Render(message, context, e, pretty);
301
+ if (context != null)
302
+ {
303
+ Debug.LogError(rendered, context);
304
+ }
305
+ else
306
+ {
307
+ Debug.LogError(rendered);
308
+ }
309
+
310
+ return rendered;
311
+ }
312
+
313
+ /// <summary>
314
+ /// Attempts to add a decoration.
315
+ /// </summary>
316
+ /// <param name="match">An exact match for tag ("a" would correspond to ${value:a})</param>
317
+ /// <param name="format">A formatter to apply to the matched object (typically something like value => $"<newFormat>{value}</newFormat>"){</param>
318
+ /// <param name="tag">A descriptive, unique identifier for the decoration (for example, "Bold", or "Color")</param>
319
+ /// <param name="priority">The priority to register the decoration at. Lower values will be evaluated first.</param>
320
+ /// <param name="editorOnly">If true, will only be applied when the game is running in the Unity Editor.</param>
321
+ /// <param name="force">
322
+ /// If true, will override any existing decorations for the same tag, regardless of priority.
323
+ /// If false, decorations with the same tag (compared OrdinalIgnoreCase) will cause the registration to fail.
324
+ /// </param>
325
+ /// <returns>True if the decoration was added, false if the decoration was not added.</returns>
326
+ public bool AddDecoration(
327
+ string match,
328
+ Func<object, string> format,
329
+ string tag = null,
330
+ int priority = 0,
331
+ bool editorOnly = false,
332
+ bool force = false
333
+ )
334
+ {
335
+ return AddDecoration(
336
+ check => string.Equals(check, match, StringComparison.OrdinalIgnoreCase),
337
+ format: (_, value) => format(value),
338
+ tag: tag ?? match,
339
+ priority: priority,
340
+ editorOnly: editorOnly,
341
+ force: force
342
+ );
343
+ }
344
+
345
+ /// <summary>
346
+ /// Attempts to add a decoration.
347
+ /// </summary>
348
+ /// <param name="predicate">
349
+ /// Tag matcher. Can be as complex as you want. For example, the default color matcher
350
+ /// is implemented something like tag => tag.StartsWith('#') || tag.StartsWith("color=")
351
+ /// </param>
352
+ /// <param name="format">
353
+ /// Custom formatting function. Takes in both the matched tag as well the current object to format. In
354
+ /// the same case of color matching, the implementation needs to be smart enough to handle the case where
355
+ /// the tag is "#red" or "color=red" or "color=#FF0000".
356
+ /// </param>
357
+ /// <param name="tag">A descriptive, unique identifier for the decoration (for example, "Bold", or "Color")</param>
358
+ /// <param name="priority">The priority to register the decoration at. Lower values will be evaluated first.</param>
359
+ /// <param name="editorOnly">If true, will only be applied when the game is running in the Unity Editor.</param>
360
+ /// <param name="force">
361
+ /// If true, will override any existing decorations for the same tag, regardless of priority.
362
+ /// If false, decorations with the same tag (compared OrdinalIgnoreCase) will cause the registration to fail.
363
+ /// </param>
364
+ /// <returns>True if the decoration was added, false if the decoration was not added.</returns>
365
+
366
+ public bool AddDecoration(
367
+ Func<string, bool> predicate,
368
+ Func<string, object, string> format,
369
+ string tag,
370
+ int priority = 0,
371
+ bool editorOnly = false,
372
+ bool force = false
373
+ )
374
+ {
375
+ bool stopLooping = false;
376
+ foreach (var entry in _matchingDecorations)
377
+ {
378
+ for (int i = 0; i < entry.Value.Count; i++)
379
+ {
380
+ var existingDecoration = entry.Value[i];
381
+ if (
382
+ !string.Equals(
383
+ existingDecoration.tag,
384
+ tag,
385
+ StringComparison.OrdinalIgnoreCase
386
+ )
387
+ )
388
+ {
389
+ continue;
390
+ }
391
+
392
+ if (force)
393
+ {
394
+ if (priority != entry.Key)
395
+ {
396
+ entry.Value.RemoveAt(i);
397
+ if (entry.Value.Count == 0)
398
+ {
399
+ _matchingDecorations.Remove(entry.Key);
400
+ }
401
+
402
+ stopLooping = true;
403
+ break;
404
+ }
405
+
406
+ entry.Value[i] = (tag, editorOnly, predicate, format);
407
+ return true;
408
+ }
409
+ return false;
410
+ }
411
+
412
+ if (stopLooping)
413
+ {
414
+ break;
415
+ }
416
+ }
417
+
418
+ if (
419
+ !_matchingDecorations.TryGetValue(
420
+ priority,
421
+ out List<(
422
+ string tag,
423
+ bool editorOnly,
424
+ Func<string, bool> predicate,
425
+ Func<string, object, string> formatter
426
+ )> matchingDecorations
427
+ )
428
+ )
429
+ {
430
+ _matchingDecorations[priority] = new List<(
431
+ string tag,
432
+ bool editorOnly,
433
+ Func<string, bool> predicate,
434
+ Func<string, object, string> formatter
435
+ )>
436
+ {
437
+ (tag, editorOnly, predicate, format),
438
+ };
439
+ return true;
440
+ }
441
+
442
+ matchingDecorations.Add((tag, editorOnly, predicate, format));
443
+ return true;
444
+ }
445
+
446
+ /// <summary>
447
+ /// Attempts to remove a decoration by its tag.
448
+ /// </summary>
449
+ /// <param name="tag">Tag for the decoration ("Bold", "Color", etc.)</param>
450
+ /// <param name="decoration">The removed decoration, if one was found.</param>
451
+ /// <returns>True if a decoration was found for that tag and removed, false otherwise.</returns>
452
+ public bool RemoveDecoration(
453
+ string tag,
454
+ out (
455
+ string tag,
456
+ bool editorOnly,
457
+ Func<string, bool> predicate,
458
+ Func<string, object, string> formatter
459
+ ) decoration
460
+ )
461
+ {
462
+ foreach (var entry in _matchingDecorations)
463
+ {
464
+ for (int i = 0; i < entry.Value.Count; ++i)
465
+ {
466
+ decoration = entry.Value[i];
467
+ if (string.Equals(tag, decoration.tag, StringComparison.OrdinalIgnoreCase))
468
+ {
469
+ entry.Value.RemoveAt(i);
470
+ if (entry.Value.Count == 0)
471
+ {
472
+ _matchingDecorations.Remove(entry.Key);
473
+ }
474
+ return true;
475
+ }
476
+ }
477
+ }
478
+
479
+ decoration = default;
480
+ return false;
481
+ }
482
+
483
+ [HideInCallstack]
484
+ private string Render(
485
+ FormattableString message,
486
+ Object unityObject,
487
+ Exception e,
488
+ bool pretty
489
+ )
490
+ {
491
+ if (!pretty)
492
+ {
493
+ return e != null
494
+ ? $"{message.ToString(this)}{NewLine} {e}"
495
+ : message.ToString(this);
496
+ }
497
+
498
+ float now = Time.time;
499
+ string componentType;
500
+ string gameObjectName;
501
+ if (unityObject != null)
502
+ {
503
+ componentType = unityObject.GetType().Name;
504
+ gameObjectName = unityObject.name;
505
+ }
506
+ else
507
+ {
508
+ componentType = "NO_TYPE";
509
+ gameObjectName = "NO_NAME";
510
+ }
511
+
512
+ return e != null
513
+ ? $"{now}|{gameObjectName}[{componentType}]|{message.ToString(this)}{NewLine} {e}"
514
+ : $"{now}|{gameObjectName}[{componentType}]|{message.ToString(this)}";
515
+ }
516
+ }
517
+ }
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: 4209667fb72340e4a133b76b2a074b5e
3
+ timeCreated: 1745446454
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: abd8f6a44318484083dc400b307d82d5
3
+ timeCreated: 1745446447
@@ -1,4 +1,4 @@
1
- namespace UnityHelpers.Core.Helper
1
+ namespace WallstopStudios.UnityHelpers.Core.Helper
2
2
  {
3
3
  using System;
4
4
  using System.Collections;
@@ -1,4 +1,4 @@
1
- namespace UnityHelpers.Core.Helper
1
+ namespace WallstopStudios.UnityHelpers.Core.Helper.Partials
2
2
  {
3
3
  using Extension;
4
4
  using UnityEngine;
@@ -7,7 +7,7 @@
7
7
  {
8
8
  public static void LogNotAssigned(this Object component, string name)
9
9
  {
10
- component.LogWarn("{0} not found.", name);
10
+ component.LogWarn($"{name} not found.");
11
11
  }
12
12
  }
13
13
  }
@@ -1,4 +1,4 @@
1
- namespace UnityHelpers.Core.Helper
1
+ namespace WallstopStudios.UnityHelpers.Core.Helper.Partials
2
2
  {
3
3
  using UnityEngine;
4
4
 
@@ -1,14 +1,12 @@
1
- namespace UnityHelpers.Core.Helper
1
+ namespace WallstopStudios.UnityHelpers.Core.Helper
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
- #if UNITY_EDITOR
9
- using UnityEditor;
10
- using UnityEditor.SceneManagement;
11
- #endif
12
10
 
13
11
  public static partial class Helpers
14
12
  {
@@ -30,7 +28,7 @@
30
28
  {
31
29
  if (log)
32
30
  {
33
- component.LogWarn("Could not find {0}.", tag);
31
+ component.LogWarn($"Could not find {tag}.");
34
32
  }
35
33
 
36
34
  return default;
@@ -45,11 +43,7 @@
45
43
  if (log)
46
44
  {
47
45
  component.LogWarn(
48
- "Failed to find {0} on {1} (name: {2}), id [{3}].",
49
- typeof(T).Name,
50
- tag,
51
- gameObject.name,
52
- gameObject.GetInstanceID()
46
+ $"Failed to find {typeof(T).Name} on {tag} (name: {gameObject.name}), id [{gameObject.GetInstanceID()}]."
53
47
  );
54
48
  }
55
49
 
@@ -1,4 +1,4 @@
1
- namespace UnityHelpers.Core.Helper
1
+ namespace WallstopStudios.UnityHelpers.Core.Helper.Partials
2
2
  {
3
3
  using System.Collections.Generic;
4
4
  using UnityEngine;