com.wallstop-studios.unity-helpers 2.0.0-rc60 → 2.0.0-rc62

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.
@@ -121,8 +121,7 @@
121
121
  if (animationClip == null)
122
122
  {
123
123
  this.LogError(
124
- "Invalid AnimationClip (null) found at path '{0}', skipping.",
125
- path
124
+ $"Invalid AnimationClip (null) found at path '{path}', skipping."
126
125
  );
127
126
  continue;
128
127
  }
@@ -136,9 +135,7 @@
136
135
  if (prefixIndex < 0)
137
136
  {
138
137
  this.LogWarn(
139
- "Unsupported animation at '{0}', expected to be prefixed by '{1}'.",
140
- path,
141
- prefix
138
+ $"Unsupported animation at '{path}', expected to be prefixed by '{prefix}'."
142
139
  );
143
140
  continue;
144
141
  }
@@ -159,18 +156,14 @@
159
156
  bool deleteSuccessful = AssetDatabase.DeleteAsset(path);
160
157
  if (!deleteSuccessful)
161
158
  {
162
- this.LogError("Failed to delete asset at path '{0}'.", path);
159
+ this.LogError($"Failed to delete asset at path '{path}'.");
163
160
  }
164
161
 
165
162
  ++processed;
166
163
  }
167
164
  else
168
165
  {
169
- this.LogError(
170
- "Failed to copy animation from '{0}' to '{1}'.",
171
- path,
172
- destination
173
- );
166
+ this.LogError($"Failed to copy animation from '{path}' to '{destination}'.");
174
167
  }
175
168
  }
176
169
 
@@ -113,7 +113,7 @@
113
113
  }
114
114
  else
115
115
  {
116
- this.LogWarn("Failed to process frame {0}.", frameName);
116
+ this.LogWarn($"Failed to process frame {frameName}.");
117
117
  }
118
118
  }
119
119
 
@@ -179,7 +179,7 @@
179
179
  string animationName = data.animationName;
180
180
  if (string.IsNullOrWhiteSpace(animationName))
181
181
  {
182
- this.LogWarn("Ignoring animationData without an animation name.");
182
+ this.LogWarn($"Ignoring animationData without an animation name.");
183
183
  continue;
184
184
  }
185
185
 
@@ -187,9 +187,7 @@
187
187
  if (framesPerSecond <= 0)
188
188
  {
189
189
  this.LogWarn(
190
- "Ignoring animationData with FPS of {0} with name {1}.",
191
- framesPerSecond,
192
- animationName
190
+ $"Ignoring animationData with FPS of {framesPerSecond} with name {animationName}."
193
191
  );
194
192
  continue;
195
193
  }
@@ -198,8 +196,7 @@
198
196
  if (frames is not { Count: > 0 })
199
197
  {
200
198
  this.LogWarn(
201
- "Ignoring animationData without frames with name {0}.",
202
- animationName
199
+ $"Ignoring animationData without frames with name {animationName}."
203
200
  );
204
201
  continue;
205
202
  }
@@ -227,8 +224,7 @@
227
224
  if (keyFrames.Count <= 0)
228
225
  {
229
226
  this.LogWarn(
230
- "Ignoring animationData with empty frames with name {0}.",
231
- animationName
227
+ $"Ignoring animationData with empty frames with name {animationName}."
232
228
  );
233
229
  continue;
234
230
  }
@@ -99,8 +99,7 @@
99
99
  if (animatorController == null)
100
100
  {
101
101
  this.LogError(
102
- "Invalid Animator Controller (null) found at path '{0}', skipping.",
103
- path
102
+ $"Invalid Animator Controller (null) found at path '{path}', skipping."
104
103
  );
105
104
  continue;
106
105
  }
@@ -114,9 +113,7 @@
114
113
  if (prefixIndex < 0)
115
114
  {
116
115
  this.LogWarn(
117
- "Unsupported AnimatorController at '{0}', expected to be prefixed by '{1}'.",
118
- path,
119
- prefix
116
+ $"Unsupported AnimatorController at '{path}', expected to be prefixed by '{prefix}'."
120
117
  );
121
118
  continue;
122
119
  }
@@ -138,8 +135,7 @@
138
135
  if (!deleteSuccessful)
139
136
  {
140
137
  this.LogError(
141
- "Failed to delete Animator Controller asset at path '{0}'.",
142
- path
138
+ $"Failed to delete Animator Controller asset at path '{path}'."
143
139
  );
144
140
  }
145
141
 
@@ -148,9 +144,7 @@
148
144
  else
149
145
  {
150
146
  this.LogError(
151
- "Failed to copy Animator Controller from '{0}' to '{1}'.",
152
- path,
153
- destination
147
+ $"Failed to copy Animator Controller from '{path}' to '{destination}'."
154
148
  );
155
149
  }
156
150
  }
@@ -17,9 +17,7 @@
17
17
  if (matchColliderToSprite == null)
18
18
  {
19
19
  this.LogError(
20
- "Target was of type {0}, expected {1}.",
21
- target?.GetType(),
22
- typeof(MatchColliderToSprite)
20
+ $"Target was of type {target?.GetType()}, expected {nameof(MatchColliderToSprite)}."
23
21
  );
24
22
  return;
25
23
  }
@@ -71,7 +71,7 @@
71
71
  textures = textures.Distinct().OrderBy(texture => texture.name).ToList();
72
72
  if (textures.Count <= 0)
73
73
  {
74
- this.Log("Failed to find any texture paths.");
74
+ this.Log($"Failed to find any texture paths.");
75
75
  return;
76
76
  }
77
77
 
@@ -140,7 +140,7 @@
140
140
  }
141
141
  else
142
142
  {
143
- this.Log("No textures updated.");
143
+ this.Log($"No textures updated.");
144
144
  }
145
145
  }
146
146
  }
@@ -60,13 +60,12 @@
60
60
  Type scriptType = script?.GetType();
61
61
  if (scriptType == null)
62
62
  {
63
- prefab.LogError("Detected missing script.");
63
+ prefab.LogError($"Detected missing script.");
64
64
  }
65
65
  else
66
66
  {
67
67
  prefab.LogError(
68
- "Detected missing script for script type {0}.",
69
- scriptType
68
+ $"Detected missing script for script type {scriptType}."
70
69
  );
71
70
  }
72
71
 
@@ -111,7 +110,7 @@
111
110
  {
112
111
  if (fieldValue == null)
113
112
  {
114
- component.LogError("Field {0} (array) was null.", field.Name);
113
+ component.LogError($"Field {field.Name} (array) was null.");
115
114
  continue;
116
115
  }
117
116
 
@@ -141,20 +140,18 @@
141
140
 
142
141
  continue;
143
142
 
144
- bool LogIfNull(object thing, int? position = null)
143
+ bool LogIfNull(object thing, int? elementIndex = null)
145
144
  {
146
145
  if (thing == null || (thing is Object unityThing && !unityThing))
147
146
  {
148
- if (position == null)
147
+ if (elementIndex == null)
149
148
  {
150
- component.LogError("Field {0} has a null element in it.", field.Name);
149
+ component.LogError($"Field {field.Name} has a null element in it.");
151
150
  }
152
151
  else
153
152
  {
154
153
  component.LogError(
155
- "Field {0} has a null element at position {1}.",
156
- field.Name,
157
- position
154
+ $"Field {field.Name} has a null element at position {elementIndex}."
158
155
  );
159
156
  }
160
157
 
@@ -61,6 +61,11 @@
61
61
  [WShowIf(nameof(applyFilterMode))]
62
62
  public FilterMode filterMode = FilterMode.Point;
63
63
 
64
+ public bool applyCrunchCompression;
65
+
66
+ [WShowIf(nameof(applyCrunchCompression))]
67
+ public bool useCrunchCompression;
68
+
64
69
  public string name = string.Empty;
65
70
  }
66
71
 
@@ -87,7 +92,7 @@
87
92
 
88
93
  private void OnWizardCreate()
89
94
  {
90
- HashSet<string> uniqueDirectories = new();
95
+ HashSet<string> uniqueDirectories = new(StringComparer.OrdinalIgnoreCase);
91
96
  foreach (
92
97
  string assetPath in directories
93
98
  .Where(Objects.NotNull)
@@ -101,14 +106,19 @@
101
106
  }
102
107
  }
103
108
 
104
- HashSet<string> processedSpritePaths = new();
109
+ HashSet<string> processedSpritePaths = new(StringComparer.OrdinalIgnoreCase);
105
110
  Queue<string> directoriesToCheck = new(uniqueDirectories);
106
111
  int spriteCount = 0;
107
112
  while (directoriesToCheck.TryDequeue(out string directoryPath))
108
113
  {
109
114
  foreach (string fullFilePath in Directory.EnumerateFiles(directoryPath))
110
115
  {
111
- if (!spriteFileExtensions.Contains(Path.GetExtension(fullFilePath)))
116
+ if (
117
+ !spriteFileExtensions.Contains(
118
+ Path.GetExtension(fullFilePath),
119
+ StringComparer.OrdinalIgnoreCase
120
+ )
121
+ )
112
122
  {
113
123
  continue;
114
124
  }
@@ -150,7 +160,7 @@
150
160
  string filePath in sprites
151
161
  .Where(Objects.NotNull)
152
162
  .Select(AssetDatabase.GetAssetPath)
153
- .Where(Objects.NotNull)
163
+ .Where(path => !string.IsNullOrWhiteSpace(path))
154
164
  )
155
165
  {
156
166
  if (
@@ -162,7 +172,7 @@
162
172
  }
163
173
  }
164
174
 
165
- this.Log("Processed {0} sprites.", spriteCount);
175
+ this.Log($"Processed {spriteCount} sprites.");
166
176
  if (0 < spriteCount)
167
177
  {
168
178
  AssetDatabase.Refresh();
@@ -171,26 +181,27 @@
171
181
 
172
182
  private bool TryUpdateTextureSettings(string filePath)
173
183
  {
174
- bool changed = false;
175
184
  if (string.IsNullOrWhiteSpace(filePath))
176
185
  {
177
- return changed;
186
+ return false;
178
187
  }
179
188
 
180
189
  TextureImporter textureImporter = AssetImporter.GetAtPath(filePath) as TextureImporter;
181
190
  if (textureImporter == null)
182
191
  {
183
- return changed;
192
+ return false;
184
193
  }
185
194
 
186
195
  SpriteSettings spriteData = spriteSettings.Find(settings =>
187
- string.IsNullOrWhiteSpace(settings.name) || filePath.Contains(settings.name)
196
+ string.IsNullOrWhiteSpace(settings.name)
197
+ || filePath.Contains(settings.name, StringComparison.OrdinalIgnoreCase)
188
198
  );
189
199
  if (spriteData == null)
190
200
  {
191
- return changed;
201
+ return false;
192
202
  }
193
203
 
204
+ bool changed = false;
194
205
  if (spriteData.applyPixelsPerUnit)
195
206
  {
196
207
  // ReSharper disable once CompareOfFloatsByEqualityOperator
@@ -210,6 +221,12 @@
210
221
  textureImporter.mipmapEnabled = spriteData.generateMipMaps;
211
222
  }
212
223
 
224
+ if (spriteData.applyCrunchCompression)
225
+ {
226
+ changed |= textureImporter.crunchedCompression != spriteData.useCrunchCompression;
227
+ textureImporter.crunchedCompression = spriteData.useCrunchCompression;
228
+ }
229
+
213
230
  bool changedSettings = false;
214
231
  TextureImporterSettings settings = new();
215
232
  textureImporter.ReadTextureSettings(settings);
@@ -155,17 +155,12 @@
155
155
  byte[] bytes = copy.EncodeToPNG();
156
156
  File.WriteAllBytes(assetPath, bytes);
157
157
  this.Log(
158
- "Resized {0} from [{1}x{2}] to [{3}x{4}]",
159
- texture.name,
160
- texture.width,
161
- texture.height,
162
- copy.width,
163
- copy.height
158
+ $"Resized {texture.name} from [{texture.width}x{texture.height}] to [{copy.width}x{copy.height}]"
164
159
  );
165
160
  }
166
161
  catch (Exception e)
167
162
  {
168
- this.LogError("Failed to resize {0}.", e, texture.name);
163
+ this.LogError($"Failed to resize {texture.name}.", e);
169
164
  }
170
165
  finally
171
166
  {
@@ -125,7 +125,7 @@
125
125
  }
126
126
  }
127
127
 
128
- this.Log("Processed {0} textures.", textureCount);
128
+ this.Log($"Processed {textureCount} textures.");
129
129
  if (0 < textureCount)
130
130
  {
131
131
  AssetDatabase.Refresh();
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "WallstopStudios.UnityHelpers.Editor",
3
- "rootNamespace": "",
3
+ "rootNamespace": "UnityHelpers",
4
4
  "references": [
5
5
  "WallstopStudios.UnityHelpers"
6
6
  ],
@@ -20,6 +20,21 @@
20
20
  {
21
21
  private static readonly Dictionary<Vector3Int, int> ColorBucketCache = new();
22
22
 
23
+ public static string ToHex(this Color color, bool includeAlpha = true)
24
+ {
25
+ int r = (int)(Mathf.Clamp01(color.r) * 255f);
26
+ int g = (int)(Mathf.Clamp01(color.g) * 255f);
27
+ int b = (int)(Mathf.Clamp01(color.b) * 255f);
28
+
29
+ if (!includeAlpha)
30
+ {
31
+ return $"#{r:X2}{g:X2}{b:X2}";
32
+ }
33
+
34
+ int a = (int)(Mathf.Clamp01(color.a) * 255f);
35
+ return $"#{r:X2}{g:X2}{b:X2}{a:X2}";
36
+ }
37
+
23
38
  public static Color GetAverageColor(
24
39
  this Sprite sprite,
25
40
  ColorAveragingMethod method = ColorAveragingMethod.LAB,
@@ -6,17 +6,21 @@ namespace UnityHelpers.Core.Extension
6
6
  {
7
7
  using System;
8
8
  using System.Collections.Generic;
9
+ using System.Linq;
9
10
  using System.Reflection;
10
- using System.Runtime.CompilerServices;
11
11
  using System.Threading;
12
- using JetBrains.Annotations;
12
+ using Helper;
13
+ using Helper.Logging;
13
14
  using UnityEngine;
14
15
  using Utils;
15
- using Debug = UnityEngine.Debug;
16
16
  using Object = UnityEngine.Object;
17
17
 
18
18
  public static class LoggingExtensions
19
19
  {
20
+ public static readonly UnityLogTagFormatter LogInstance = new(
21
+ createDefaultDecorators: true
22
+ );
23
+
20
24
  private static readonly Thread UnityMainThread;
21
25
  private const int LogsPerCacheClean = 5;
22
26
 
@@ -24,8 +28,10 @@ namespace UnityHelpers.Core.Extension
24
28
  private static long _cacheAccessCount;
25
29
 
26
30
  private static readonly HashSet<Object> Disabled = new();
27
- private static readonly Dictionary<Type, FieldInfo[]> FieldCache = new();
28
- private static readonly Dictionary<Type, PropertyInfo[]> PropertyCache = new();
31
+ private static readonly Dictionary<Type, (string, Func<object, object>)[]> MetadataCache =
32
+ new();
33
+
34
+ private static readonly Dictionary<string, object> GenericObject = new();
29
35
 
30
36
  static LoggingExtensions()
31
37
  {
@@ -33,7 +39,7 @@ namespace UnityHelpers.Core.Extension
33
39
  /*
34
40
  Unity throws exceptions if you try to log on something that isn't the main thread.
35
41
  Sometimes, it's nice to log in async Tasks. Assume that the first initialization of
36
- this class will be done by the Unity main thread, and then check every time we log.
42
+ this class will be done by the Unity main thread and then check every time we log.
37
43
  If the logging thread is not the unity main thread, then do nothing
38
44
  (instead of throwing...)
39
45
  */
@@ -61,6 +67,7 @@ namespace UnityHelpers.Core.Extension
61
67
  Disabled.Add(component);
62
68
  }
63
69
 
70
+ [HideInCallstack]
64
71
  public static string GenericToString(this Object component)
65
72
  {
66
73
  if (component == null)
@@ -68,148 +75,114 @@ namespace UnityHelpers.Core.Extension
68
75
  return "null";
69
76
  }
70
77
 
71
- Dictionary<string, object> structure = new();
72
- Type type = component.GetType();
73
- FieldInfo[] fields = FieldCache.GetOrAdd(
74
- type,
75
- inType => inType.GetFields(BindingFlags.Public | BindingFlags.Instance)
76
- );
77
- PropertyInfo[] properties = PropertyCache.GetOrAdd(
78
- type,
79
- inType => inType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
78
+ (string, Func<object, object>)[] metadataAccess = MetadataCache.GetOrAdd(
79
+ component.GetType(),
80
+ inType =>
81
+ inType
82
+ .GetFields(BindingFlags.Public | BindingFlags.Instance)
83
+ .Select(field => (field.Name, ReflectionHelpers.GetFieldGetter(field)))
84
+ .Concat(
85
+ inType
86
+ .GetProperties(BindingFlags.Public | BindingFlags.Instance)
87
+ .Select(property =>
88
+ (property.Name, ReflectionHelpers.GetPropertyGetter(property))
89
+ )
90
+ )
91
+ .ToArray()
80
92
  );
81
- foreach (FieldInfo field in fields)
82
- {
83
- structure[field.Name] = ValueFormat(field.GetValue(component));
84
- }
85
-
86
- foreach (PropertyInfo property in properties)
87
- {
88
- structure[property.Name] = ValueFormat(property.GetValue(component));
89
- }
90
-
91
- return structure.ToJson();
92
93
 
93
- object ValueFormat(object value)
94
+ GenericObject.Clear();
95
+ foreach ((string name, Func<object, object> access) in metadataAccess)
94
96
  {
95
- if (value is Object obj)
97
+ try
98
+ {
99
+ string valueFormat = ValueFormat(access(component));
100
+ if (valueFormat != null)
101
+ {
102
+ GenericObject[name] = valueFormat;
103
+ }
104
+ }
105
+ catch
96
106
  {
97
- return obj != null ? obj.name : null;
107
+ // Skip
98
108
  }
99
- return value?.ToString();
100
109
  }
101
- }
102
-
103
- [StringFormatMethod("message")]
104
- public static void Log(this Object component, string message, params object[] args)
105
- {
106
- #if ENABLE_UBERLOGGING
107
- LogDebug(component, message, args);
108
- #endif
109
- }
110
110
 
111
- [StringFormatMethod("message")]
112
- public static void LogMethod(this Object component, [CallerMemberName] string caller = "")
113
- {
114
- #if ENABLE_UBERLOGGING
115
- LogDebug(component, caller);
116
- #endif
111
+ return GenericObject.ToJson();
117
112
  }
118
113
 
119
- [StringFormatMethod("message")]
120
- public static void LogDebug(this Object component, string message, params object[] args)
114
+ [HideInCallstack]
115
+ private static string ValueFormat(object value)
121
116
  {
122
- #if ENABLE_UBERLOGGING
123
- LogDebug(component, message, null, args);
124
- #endif
125
- }
126
-
127
- [StringFormatMethod("message")]
128
- public static void LogWarn(this Object component, string message, params object[] args)
129
- {
130
- #if ENABLE_UBERLOGGING
131
- LogWarn(component, message, null, args);
132
- #endif
133
- }
134
-
135
- [StringFormatMethod("message")]
136
- public static void LogError(this Object component, string message, params object[] args)
137
- {
138
- #if ENABLE_UBERLOGGING
139
- LogError(component, message, null, args);
140
- #endif
117
+ if (value is Object obj)
118
+ {
119
+ return obj != null ? obj.name : "null";
120
+ }
121
+ return value?.ToString();
141
122
  }
142
123
 
143
- [StringFormatMethod("message")]
124
+ [HideInCallstack]
144
125
  public static void Log(
145
126
  this Object component,
146
- string message,
147
- Exception e,
148
- params object[] args
127
+ FormattableString message,
128
+ Exception e = null,
129
+ bool pretty = true
149
130
  )
150
131
  {
151
132
  #if ENABLE_UBERLOGGING
152
- LogDebug(component, message, e, args);
133
+ LogDebug(component, message, e, pretty);
153
134
  #endif
154
135
  }
155
136
 
156
- [StringFormatMethod("message")]
137
+ [HideInCallstack]
157
138
  public static void LogDebug(
158
139
  this Object component,
159
- string message,
160
- Exception e,
161
- params object[] args
140
+ FormattableString message,
141
+ Exception e = null,
142
+ bool pretty = true
162
143
  )
163
144
  {
164
145
  #if ENABLE_UBERLOGGING
165
146
  if (LoggingAllowed(component))
166
147
  {
167
- Debug.Log(
168
- Wrap(component, args.Length != 0 ? string.Format(message, args) : message, e),
169
- component
170
- );
148
+ LogInstance.Log(message, component, e, pretty);
171
149
  }
172
150
  #endif
173
151
  }
174
152
 
175
- [StringFormatMethod("message")]
153
+ [HideInCallstack]
176
154
  public static void LogWarn(
177
155
  this Object component,
178
- string message,
179
- Exception e,
180
- params object[] args
156
+ FormattableString message,
157
+ Exception e = null,
158
+ bool pretty = true
181
159
  )
182
160
  {
183
161
  #if ENABLE_UBERLOGGING
184
162
  if (LoggingAllowed(component))
185
163
  {
186
- Debug.LogWarning(
187
- Wrap(component, args.Length != 0 ? string.Format(message, args) : message, e),
188
- component
189
- );
164
+ LogInstance.LogWarn(message, component, e, pretty);
190
165
  }
191
166
  #endif
192
167
  }
193
168
 
194
- [StringFormatMethod("message")]
169
+ [HideInCallstack]
195
170
  public static void LogError(
196
171
  this Object component,
197
- string message,
198
- Exception e,
199
- params object[] args
172
+ FormattableString message,
173
+ Exception e = null,
174
+ bool pretty = true
200
175
  )
201
176
  {
202
177
  #if ENABLE_UBERLOGGING
203
178
  if (LoggingAllowed(component))
204
179
  {
205
- Debug.LogError(
206
- Wrap(component, args.Length != 0 ? string.Format(message, args) : message, e),
207
- component
208
- );
180
+ LogInstance.LogError(message, component, e, pretty);
209
181
  }
210
182
  #endif
211
183
  }
212
184
 
185
+ [HideInCallstack]
213
186
  private static bool LoggingAllowed(Object component)
214
187
  {
215
188
  if (Interlocked.Increment(ref _cacheAccessCount) % LogsPerCacheClean == 0)
@@ -234,31 +207,5 @@ namespace UnityHelpers.Core.Extension
234
207
  && Equals(Thread.CurrentThread, UnityMainThread)
235
208
  && !Disabled.Contains(component);
236
209
  }
237
-
238
- private static string Wrap(Object component, string message, Exception e)
239
- {
240
- #if ENABLE_UBERLOGGING
241
- float now = Time.time;
242
- string componentType;
243
- string gameObjectName;
244
- if (component != null)
245
- {
246
- componentType = component.GetType().Name;
247
- gameObjectName = component.name;
248
- }
249
- else
250
- {
251
- componentType = "NO_TYPE";
252
- gameObjectName = "NO_NAME";
253
- }
254
-
255
- return e != null
256
- ? $"{now}|{gameObjectName}[{componentType}]|{message}\n {e}"
257
- : $"{now}|{gameObjectName}[{componentType}]|{message}";
258
-
259
- #else
260
- return string.Empty;
261
- #endif
262
- }
263
210
  }
264
211
  }