com.wallstop-studios.unity-helpers 2.0.0-rc73.19 → 2.0.0-rc73.2

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 (78) hide show
  1. package/Editor/{Sprites/AnimationCopier.cs → AnimationCopier.cs} +209 -84
  2. package/Editor/{Sprites/AnimationCreator.cs → AnimationCreator.cs} +100 -29
  3. package/Editor/AnimationEventEditor.cs +23 -10
  4. package/Editor/CustomEditors/MatchColliderToSpriteEditor.cs +1 -1
  5. package/Editor/FitTextureSizeWindow.cs +53 -14
  6. package/Editor/PrefabChecker.cs +18 -11
  7. package/Editor/SpriteAtlasGenerator.cs +914 -0
  8. package/Editor/SpriteAtlasGenerator.cs.meta +3 -0
  9. package/Editor/{Sprites/SpriteCropper.cs → SpriteCropper.cs} +143 -172
  10. package/Editor/{Sprites/SpriteSettingsApplier.cs → SpriteSettingsApplier.cs} +77 -12
  11. package/Editor/{Sprites/TextureResizerWizard.cs → TextureResizerWizard.cs} +1 -1
  12. package/Editor/{Sprites/TextureSettingsApplier.cs → TextureSettingsApplier.cs} +1 -1
  13. package/Editor/Utils/DxReadOnlyPropertyDrawer.cs +1 -1
  14. package/Editor/Utils/GUIHorizontalScope.cs +20 -0
  15. package/Editor/Utils/GUIHorizontalScope.cs.meta +3 -0
  16. package/Runtime/Core/DataStructure/Circle.cs +1 -1
  17. package/Runtime/Core/DataStructure/QuadTree.cs +4 -4
  18. package/Runtime/Core/Extension/ColorExtensions.cs +5 -5
  19. package/Runtime/Core/Extension/IEnumerableExtensions.cs +1 -1
  20. package/Runtime/Core/Extension/UnityExtensions.cs +14 -14
  21. package/Runtime/Core/Helper/DirectoryHelper.cs +0 -64
  22. package/Runtime/Core/Helper/Helpers.cs +9 -9
  23. package/Runtime/Core/Helper/Logging/UnityLogTagFormatter.cs +8 -31
  24. package/Runtime/Core/Helper/Partials/ObjectHelpers.cs +4 -5
  25. package/Runtime/Core/Helper/PathHelper.cs +1 -2
  26. package/Runtime/Core/Random/DotNetRandom.cs +1 -1
  27. package/Runtime/Core/Random/SplitMix64.cs +1 -1
  28. package/Runtime/Core/Random/SquirrelRandom.cs +7 -7
  29. package/Runtime/Core/Random/ThreadLocalRandom.cs +1 -1
  30. package/Runtime/Core/Random/WyRandom.cs +1 -1
  31. package/Runtime/Tags/AttributeEffect.cs +0 -1
  32. package/Runtime/Tags/EffectHandler.cs +1 -1
  33. package/Runtime/UI/LayeredImage.cs +161 -309
  34. package/Runtime/Utils/AnimatorEnumStateMachine.cs +1 -1
  35. package/Runtime/Utils/SetTextureImportData.cs +1 -1
  36. package/Runtime/Utils/TextureScale.cs +4 -4
  37. package/Styles/Elements/{Progress/CircularProgressBar.cs → CircularProgressBar.cs} +55 -56
  38. package/Styles/Elements/{Progress/RegularProgressBar.cs → RegularProgressBar.cs} +13 -24
  39. package/Styles/UXML/CircularProgressBar.uxml +11 -0
  40. package/Styles/UXML/CircularProgressBar.uxml.meta +10 -0
  41. package/Styles/UXML/RegularProgressBar.uxml +22 -0
  42. package/Styles/UXML/RegularProgressBar.uxml.meta +10 -0
  43. package/Styles/UXML.meta +3 -0
  44. package/package.json +1 -18
  45. package/Editor/CustomEditors/PersistentDirectoryGUI.cs +0 -796
  46. package/Editor/CustomEditors/PersistentDirectoryGUI.cs.meta +0 -3
  47. package/Editor/CustomEditors/SourceFolderEntryDrawer.cs +0 -275
  48. package/Editor/CustomEditors/SourceFolderEntryDrawer.cs.meta +0 -3
  49. package/Editor/PersistentDirectorySettings.cs +0 -248
  50. package/Editor/PersistentDirectorySettings.cs.meta +0 -3
  51. package/Editor/Sprites/ScriptableSpriteAtlas.cs +0 -95
  52. package/Editor/Sprites/ScriptableSpriteAtlas.cs.meta +0 -3
  53. package/Editor/Sprites/ScriptableSpriteAtlasEditor.cs +0 -930
  54. package/Editor/Sprites/ScriptableSpriteAtlasEditor.cs.meta +0 -3
  55. package/Editor/Sprites.meta +0 -3
  56. package/Styles/Elements/Progress/ArcedProgressBar.cs +0 -345
  57. package/Styles/Elements/Progress/ArcedProgressBar.cs.meta +0 -3
  58. package/Styles/Elements/Progress/GlitchProgressBar.cs +0 -416
  59. package/Styles/Elements/Progress/GlitchProgressBar.cs.meta +0 -3
  60. package/Styles/Elements/Progress/LiquidProgressBar.cs +0 -632
  61. package/Styles/Elements/Progress/LiquidProgressBar.cs.meta +0 -3
  62. package/Styles/Elements/Progress/MarchingAntsProgressBar.cs +0 -722
  63. package/Styles/Elements/Progress/MarchingAntsProgressBar.cs.meta +0 -3
  64. package/Styles/Elements/Progress/WigglyProgressBar.cs +0 -837
  65. package/Styles/Elements/Progress/WigglyProgressBar.cs.meta +0 -3
  66. package/Styles/Elements/Progress.meta +0 -3
  67. package/Styles/USS/ArcedProgressBar.uss +0 -19
  68. package/Styles/USS/ArcedProgressBar.uss.meta +0 -3
  69. package/Styles/USS/WigglyProgressBar.uss +0 -17
  70. package/Styles/USS/WigglyProgressBar.uss.meta +0 -3
  71. /package/Editor/{Sprites/AnimationCopier.cs.meta → AnimationCopier.cs.meta} +0 -0
  72. /package/Editor/{Sprites/AnimationCreator.cs.meta → AnimationCreator.cs.meta} +0 -0
  73. /package/Editor/{Sprites/SpriteCropper.cs.meta → SpriteCropper.cs.meta} +0 -0
  74. /package/Editor/{Sprites/SpriteSettingsApplier.cs.meta → SpriteSettingsApplier.cs.meta} +0 -0
  75. /package/Editor/{Sprites/TextureResizerWizard.cs.meta → TextureResizerWizard.cs.meta} +0 -0
  76. /package/Editor/{Sprites/TextureSettingsApplier.cs.meta → TextureSettingsApplier.cs.meta} +0 -0
  77. /package/Styles/Elements/{Progress/CircularProgressBar.cs.meta → CircularProgressBar.cs.meta} +0 -0
  78. /package/Styles/Elements/{Progress/RegularProgressBar.cs.meta → RegularProgressBar.cs.meta} +0 -0
@@ -1,930 +0,0 @@
1
- namespace WallstopStudios.UnityHelpers.Editor.Sprites
2
- {
3
- #if UNITY_EDITOR
4
- using System;
5
- using System.Collections.Generic;
6
- using System.IO;
7
- using System.Linq;
8
- using System.Text.RegularExpressions;
9
- using Core.Extension;
10
- using Core.Helper;
11
- using UnityEditor;
12
- using UnityEditor.U2D;
13
- using UnityEngine;
14
- using UnityEngine.U2D;
15
- using Object = UnityEngine.Object;
16
-
17
- public sealed class ScriptableSpriteAtlasEditor : EditorWindow
18
- {
19
- private List<ScriptableSpriteAtlas> _atlasConfigs = new();
20
- private Vector2 _scrollPosition;
21
-
22
- private sealed class ScanResult
23
- {
24
- public List<Sprite> spritesToAdd = new();
25
- public List<Sprite> spritesToRemove = new();
26
- public bool hasScanned;
27
- }
28
-
29
- private readonly Dictionary<ScriptableSpriteAtlas, ScanResult> _scanResultsCache = new();
30
- private readonly Dictionary<ScriptableSpriteAtlas, bool> _foldoutStates = new();
31
-
32
- private const string NewAtlasConfigDirectory = "Assets/Data";
33
-
34
- [MenuItem("Tools/Wallstop Studios/Unity Helpers/Sprite Atlas Generator")]
35
- public static void ShowWindow()
36
- {
37
- GetWindow<ScriptableSpriteAtlasEditor>("Sprite Atlas Generator");
38
- }
39
-
40
- private void OnEnable()
41
- {
42
- LoadAtlasConfigs();
43
- }
44
-
45
- private void OnFocus()
46
- {
47
- LoadAtlasConfigs();
48
- }
49
-
50
- private void OnProjectChange()
51
- {
52
- LoadAtlasConfigs();
53
- }
54
-
55
- private void LoadAtlasConfigs()
56
- {
57
- _atlasConfigs.Clear();
58
- Dictionary<ScriptableSpriteAtlas, ScanResult> existingScanCache = new(
59
- _scanResultsCache
60
- );
61
- _scanResultsCache.Clear();
62
-
63
- string[] guids = AssetDatabase.FindAssets("t:ScriptableSpriteAtlas");
64
- foreach (string guid in guids)
65
- {
66
- string path = AssetDatabase.GUIDToAssetPath(guid);
67
- ScriptableSpriteAtlas config = AssetDatabase.LoadAssetAtPath<ScriptableSpriteAtlas>(
68
- path
69
- );
70
- if (config != null)
71
- {
72
- _atlasConfigs.Add(config);
73
- if (existingScanCache.TryGetValue(config, out ScanResult cachedResult))
74
- {
75
- _scanResultsCache[config] = cachedResult;
76
- }
77
- else if (!_scanResultsCache.ContainsKey(config))
78
- {
79
- _scanResultsCache[config] = new ScanResult();
80
- }
81
- _foldoutStates.TryAdd(config, true);
82
- }
83
- }
84
- _atlasConfigs = _atlasConfigs.OrderBy(c => c.name).ToList();
85
- }
86
-
87
- private void OnGUI()
88
- {
89
- EditorGUILayout.LabelField("Sprite Atlas Generation Tool", EditorStyles.boldLabel);
90
- EditorGUILayout.Space();
91
-
92
- using (new EditorGUILayout.HorizontalScope())
93
- {
94
- if (GUILayout.Button("Refresh Config List", GUILayout.Height(30)))
95
- {
96
- LoadAtlasConfigs();
97
- }
98
-
99
- if (
100
- GUILayout.Button(
101
- $"Create New Config in '{NewAtlasConfigDirectory}'",
102
- GUILayout.Height(30)
103
- )
104
- )
105
- {
106
- CreateNewScriptableSpriteAtlas();
107
- }
108
- }
109
-
110
- EditorGUILayout.Space();
111
-
112
- if (GUILayout.Button("Generate/Update All .spriteatlas Assets", GUILayout.Height(40)))
113
- {
114
- GenerateAllAtlases();
115
- }
116
-
117
- if (GUILayout.Button("Pack All Generated Sprite Atlases", GUILayout.Height(40)))
118
- {
119
- PackAllProjectAtlases();
120
- }
121
- EditorGUILayout.Space(20);
122
- _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
123
- if (_atlasConfigs.Count == 0)
124
- {
125
- EditorGUILayout.HelpBox(
126
- "No ScriptableSpriteAtlas configurations found. Use the 'Create New Config' button above or create one via Assets > Create > Wallstop Studios > Unity Helpers > Scriptable Sprite Atlas Config.",
127
- MessageType.Info
128
- );
129
- }
130
-
131
- foreach (ScriptableSpriteAtlas config in _atlasConfigs)
132
- {
133
- if (config == null)
134
- {
135
- LoadAtlasConfigs();
136
- Repaint();
137
- return;
138
- }
139
-
140
- EditorGUILayout.BeginVertical(EditorStyles.helpBox);
141
- string foldoutLabel =
142
- $"{config.name} (Output: {config.FullOutputPath ?? "Path Not Set"})";
143
- if (AssetDatabase.Contains(config))
144
- {
145
- foldoutLabel += $" - Path: {AssetDatabase.GetAssetPath(config)}";
146
- }
147
-
148
- _foldoutStates[config] = EditorGUILayout.Foldout(
149
- _foldoutStates[config],
150
- foldoutLabel,
151
- true,
152
- EditorStyles.foldoutHeader
153
- );
154
-
155
- if (_foldoutStates[config])
156
- {
157
- using EditorGUI.IndentLevelScope indentScope = new();
158
- SerializedObject serializedConfig = new(config);
159
- serializedConfig.Update();
160
- EditorGUI.BeginChangeCheck();
161
-
162
- string currentAssetName = config.name;
163
- Rect nameRect = EditorGUILayout.GetControlRect();
164
- EditorGUI.BeginChangeCheck();
165
- string newAssetName = EditorGUI.TextField(
166
- new Rect(nameRect.x, nameRect.y, nameRect.width - 60, nameRect.height),
167
- "Asset Name",
168
- currentAssetName
169
- );
170
- if (EditorGUI.EndChangeCheck())
171
- {
172
- if (
173
- !string.IsNullOrWhiteSpace(newAssetName)
174
- && newAssetName != currentAssetName
175
- && AssetDatabase.Contains(config)
176
- )
177
- {
178
- string assetPath = AssetDatabase.GetAssetPath(config);
179
- string error = AssetDatabase.RenameAsset(assetPath, newAssetName);
180
- if (string.IsNullOrWhiteSpace(error))
181
- {
182
- LoadAtlasConfigs();
183
- GUIUtility.ExitGUI();
184
- }
185
- else
186
- {
187
- this.LogError($"Failed to rename asset: {error}");
188
- }
189
- }
190
- }
191
-
192
- SerializedProperty scriptProperty = serializedConfig.FindProperty("m_Script");
193
- if (scriptProperty != null)
194
- {
195
- GUI.enabled = false;
196
- EditorGUILayout.PropertyField(scriptProperty);
197
- GUI.enabled = true;
198
- }
199
-
200
- SerializedProperty property = serializedConfig.GetIterator();
201
- bool enterChildren = true;
202
- while (property.NextVisible(enterChildren))
203
- {
204
- enterChildren = false;
205
- if (string.Equals(property.name, "m_Script", StringComparison.Ordinal))
206
- {
207
- continue;
208
- }
209
-
210
- EditorGUILayout.PropertyField(property, true);
211
- }
212
-
213
- if (EditorGUI.EndChangeCheck())
214
- {
215
- serializedConfig.ApplyModifiedProperties();
216
- }
217
-
218
- EditorGUILayout.Space();
219
- if (GUILayout.Button("Add New Source Folder Entry"))
220
- {
221
- string folderPath = EditorUtility.OpenFolderPanel(
222
- "Select Source Folder",
223
- Application.dataPath,
224
- ""
225
- );
226
- if (!string.IsNullOrWhiteSpace(folderPath))
227
- {
228
- if (folderPath.StartsWith(Application.dataPath))
229
- {
230
- string relativePath =
231
- "Assets" + folderPath.Substring(Application.dataPath.Length);
232
- relativePath = relativePath.SanitizePath();
233
- SerializedProperty sourceFolderEntriesProp =
234
- serializedConfig.FindProperty(
235
- nameof(ScriptableSpriteAtlas.sourceFolderEntries)
236
- );
237
-
238
- bool pathExists = false;
239
- for (int j = 0; j < sourceFolderEntriesProp.arraySize; j++)
240
- {
241
- SerializedProperty entryProp =
242
- sourceFolderEntriesProp.GetArrayElementAtIndex(j);
243
- SerializedProperty pathProp = entryProp.FindPropertyRelative(
244
- "folderPath"
245
- );
246
- if (
247
- string.Equals(
248
- pathProp.stringValue,
249
- relativePath,
250
- StringComparison.Ordinal
251
- )
252
- )
253
- {
254
- pathExists = true;
255
- this.LogWarn(
256
- $"Folder path '{relativePath}' already exists in an entry for '{config.name}'."
257
- );
258
- break;
259
- }
260
- }
261
-
262
- if (!pathExists)
263
- {
264
- sourceFolderEntriesProp.InsertArrayElementAtIndex(
265
- sourceFolderEntriesProp.arraySize
266
- );
267
- SerializedProperty newEntryProp =
268
- sourceFolderEntriesProp.GetArrayElementAtIndex(
269
- sourceFolderEntriesProp.arraySize - 1
270
- );
271
- newEntryProp.FindPropertyRelative("folderPath").stringValue =
272
- relativePath;
273
-
274
- serializedConfig.ApplyModifiedProperties();
275
- this.Log(
276
- $"Added new source folder entry for '{relativePath}' to '{config.name}'. You can add regexes to it below."
277
- );
278
- }
279
- }
280
- else
281
- {
282
- EditorUtility.DisplayDialog(
283
- "Invalid Folder",
284
- "The selected folder must be within the project's 'Assets' directory.",
285
- "OK"
286
- );
287
- }
288
- }
289
- }
290
-
291
- EditorGUILayout.Space();
292
- EditorGUILayout.LabelField("Analysis & Actions", EditorStyles.boldLabel);
293
-
294
- if (GUILayout.Button($"Scan Folders for '{config.name}'"))
295
- {
296
- ScanFoldersForConfig(config);
297
- }
298
-
299
- ScanResult result = _scanResultsCache[config];
300
- if (result.hasScanned)
301
- {
302
- EditorGUILayout.LabelField(
303
- $"Current manually added sprites: {config.spritesToPack.Count(s => s != null)}"
304
- );
305
- EditorGUILayout.LabelField(
306
- "Sprites found by scan (not yet added/removed):"
307
- );
308
- using EditorGUI.IndentLevelScope nextIndentScope = new();
309
-
310
- if (result.spritesToAdd.Count > 0)
311
- {
312
- EditorGUILayout.LabelField(
313
- $"To Add: {result.spritesToAdd.Count} sprites."
314
- );
315
- if (
316
- GUILayout.Button(
317
- $"Add {result.spritesToAdd.Count} Sprites to '{config.name}' List"
318
- )
319
- )
320
- {
321
- AddScannedSprites(config, result);
322
- }
323
- }
324
- else
325
- {
326
- EditorGUILayout.LabelField(
327
- "To Add: 0 sprites.",
328
- EditorStyles.miniLabel
329
- );
330
- }
331
-
332
- if (result.spritesToRemove.Count > 0)
333
- {
334
- EditorGUILayout.LabelField(
335
- $"To Remove: {result.spritesToRemove.Count} sprites (currently in list but not found by scan)."
336
- );
337
- if (
338
- GUILayout.Button(
339
- $"Remove {result.spritesToRemove.Count} Sprites from '{config.name}' List"
340
- )
341
- )
342
- {
343
- RemoveUnfoundSprites(config, result);
344
- }
345
- }
346
- else
347
- {
348
- EditorGUILayout.LabelField(
349
- "To Remove: 0 sprites.",
350
- EditorStyles.miniLabel
351
- );
352
- }
353
- }
354
- else
355
- {
356
- EditorGUILayout.HelpBox(
357
- "Scan to see potential changes from folder sources.",
358
- MessageType.None
359
- );
360
- }
361
-
362
- EditorGUILayout.Space();
363
- EditorGUILayout.LabelField("Source Sprite Utilities", EditorStyles.boldLabel);
364
-
365
- int validSpriteCount = config.spritesToPack.Count(s => s != null);
366
- EditorGUI.BeginDisabledGroup(validSpriteCount == 0);
367
- if (
368
- GUILayout.Button(
369
- $"Force Uncompressed for {validSpriteCount} Source Sprites in '{config.name}'"
370
- )
371
- )
372
- {
373
- if (
374
- EditorUtility.DisplayDialog(
375
- "Force Uncompressed Source Sprites",
376
- $"This will modify the import settings of {validSpriteCount} source sprites currently in the '{config.name}' list.\n\n"
377
- + "- Crunch compression will be disabled.\n"
378
- + "- Texture format for the 'Default' platform will be set to uncompressed (RGBA32 or RGB24).\n\n"
379
- + "This action modifies source asset import settings and may require re-packing atlases. Are you sure?",
380
- "Yes, Modify Source Sprites",
381
- "Cancel"
382
- )
383
- )
384
- {
385
- ForceUncompressedSourceSprites(config);
386
- }
387
- }
388
- EditorGUI.EndDisabledGroup();
389
-
390
- EditorGUILayout.Space();
391
- if (
392
- GUILayout.Button(
393
- $"Generate/Update '{config.outputSpriteAtlasName}.spriteatlas' ONLY"
394
- )
395
- )
396
- {
397
- if (
398
- EditorUtility.DisplayDialog(
399
- $"Generate Atlas: {config.name}",
400
- $"This will create or update '{config.outputSpriteAtlasName}.spriteatlas'. Continue?",
401
- "Yes",
402
- "No"
403
- )
404
- )
405
- {
406
- GenerateSingleAtlas(config);
407
- }
408
- }
409
- }
410
- EditorGUILayout.EndVertical();
411
- EditorGUILayout.Space();
412
- }
413
- EditorGUILayout.EndScrollView();
414
- }
415
-
416
- private void CreateNewScriptableSpriteAtlas()
417
- {
418
- if (!Directory.Exists(NewAtlasConfigDirectory))
419
- {
420
- Directory.CreateDirectory(NewAtlasConfigDirectory);
421
- AssetDatabase.Refresh();
422
- }
423
-
424
- ScriptableSpriteAtlas newAtlasConfig = CreateInstance<ScriptableSpriteAtlas>();
425
- newAtlasConfig.outputSpriteAtlasDirectory = "Assets/GeneratedSpriteAtlases";
426
- newAtlasConfig.outputSpriteAtlasName = "NewlyCreatedAtlas";
427
-
428
- string path = AssetDatabase.GenerateUniqueAssetPath(
429
- Path.Combine(NewAtlasConfigDirectory, "NewScriptableSpriteAtlas.asset")
430
- );
431
-
432
- AssetDatabase.CreateAsset(newAtlasConfig, path);
433
- AssetDatabase.SaveAssets();
434
- AssetDatabase.Refresh();
435
-
436
- EditorUtility.FocusProjectWindow();
437
- Selection.activeObject = newAtlasConfig;
438
-
439
- this.Log($"Created new ScriptableSpriteAtlas at: {path}");
440
- LoadAtlasConfigs();
441
- Repaint();
442
- }
443
-
444
- private void ScanFoldersForConfig(ScriptableSpriteAtlas config)
445
- {
446
- if (config.sourceFolderEntries == null || config.sourceFolderEntries.Count == 0)
447
- {
448
- this.LogWarn(
449
- $"'{config.name}': No source folder entries defined. Scan will find nothing from folders."
450
- );
451
- _scanResultsCache[config] = new ScanResult { hasScanned = true };
452
- Repaint();
453
- return;
454
- }
455
-
456
- ScanResult currentScan = new();
457
- HashSet<Sprite> foundSpritesInFolders = new();
458
-
459
- foreach (SourceFolderEntry entry in config.sourceFolderEntries)
460
- {
461
- if (
462
- string.IsNullOrWhiteSpace(entry.folderPath)
463
- || !AssetDatabase.IsValidFolder(entry.folderPath)
464
- )
465
- {
466
- this.LogWarn(
467
- $"'{config.name}': Invalid or empty folder path '{entry.folderPath}' in an entry. Skipping this entry."
468
- );
469
- continue;
470
- }
471
-
472
- string[] textureGuids = AssetDatabase.FindAssets(
473
- "t:Texture2D",
474
- new[] { entry.folderPath }
475
- );
476
- foreach (string guid in textureGuids)
477
- {
478
- string assetPath = AssetDatabase.GUIDToAssetPath(guid);
479
- string fileName = Path.GetFileName(assetPath);
480
-
481
- bool matchesAllRegexesInEntry;
482
- List<string> activeRegexPatterns = entry
483
- .regexes.Where(r => !string.IsNullOrWhiteSpace(r))
484
- .ToList();
485
-
486
- if (activeRegexPatterns.Count == 0)
487
- {
488
- matchesAllRegexesInEntry = true;
489
- }
490
- else
491
- {
492
- matchesAllRegexesInEntry = true;
493
- foreach (string regexPattern in activeRegexPatterns)
494
- {
495
- try
496
- {
497
- if (!Regex.IsMatch(fileName, regexPattern, RegexOptions.IgnoreCase))
498
- {
499
- matchesAllRegexesInEntry = false;
500
- break;
501
- }
502
- }
503
- catch (ArgumentException ex)
504
- {
505
- this.LogError(
506
- $"'{config.name}', Folder '{entry.folderPath}': Invalid Regex pattern '{regexPattern}': {ex.Message}. File '{fileName}' will not be matched by this entry due to this error."
507
- );
508
- matchesAllRegexesInEntry = false;
509
- break;
510
- }
511
- }
512
- }
513
-
514
- if (matchesAllRegexesInEntry)
515
- {
516
- Object[] assets = AssetDatabase.LoadAllAssetsAtPath(assetPath);
517
- foreach (Object asset in assets)
518
- {
519
- if (asset is Sprite spriteAsset && spriteAsset != null)
520
- {
521
- foundSpritesInFolders.Add(spriteAsset);
522
- }
523
- }
524
- }
525
- }
526
- }
527
-
528
- List<Sprite> validSpritesInConfigList = config
529
- .spritesToPack.Where(s => s != null)
530
- .ToList();
531
-
532
- currentScan.spritesToAdd = foundSpritesInFolders
533
- .Except(validSpritesInConfigList)
534
- .ToList();
535
-
536
- currentScan.spritesToRemove = validSpritesInConfigList
537
- .Except(foundSpritesInFolders)
538
- .ToList();
539
-
540
- currentScan.hasScanned = true;
541
- _scanResultsCache[config] = currentScan;
542
- this.Log(
543
- $"'{config.name}': Scan complete. Total unique sprites found across all folder entries: {foundSpritesInFolders.Count}. Potential to add: {currentScan.spritesToAdd.Count}, Potential to remove: {currentScan.spritesToRemove.Count}."
544
- );
545
- Repaint();
546
- }
547
-
548
- private void AddScannedSprites(ScriptableSpriteAtlas config, ScanResult result)
549
- {
550
- if (result.spritesToAdd.Count <= 0)
551
- {
552
- return;
553
- }
554
-
555
- SerializedObject so = new(config);
556
- SerializedProperty spritesListProp = so.FindProperty(
557
- nameof(ScriptableSpriteAtlas.spritesToPack)
558
- );
559
-
560
- Undo.RecordObject(config, "Add Scanned Sprites to Atlas Config");
561
-
562
- int addedCount = 0;
563
- foreach (Sprite sprite in result.spritesToAdd)
564
- {
565
- bool alreadyExists = false;
566
- for (int i = 0; i < spritesListProp.arraySize; ++i)
567
- {
568
- if (spritesListProp.GetArrayElementAtIndex(i).objectReferenceValue == sprite)
569
- {
570
- alreadyExists = true;
571
- break;
572
- }
573
- }
574
- if (!alreadyExists)
575
- {
576
- spritesListProp.InsertArrayElementAtIndex(spritesListProp.arraySize);
577
- spritesListProp
578
- .GetArrayElementAtIndex(spritesListProp.arraySize - 1)
579
- .objectReferenceValue = sprite;
580
- addedCount++;
581
- }
582
- }
583
-
584
- if (addedCount > 0)
585
- {
586
- so.ApplyModifiedProperties();
587
- this.Log($"'{config.name}': Added {addedCount} sprites.");
588
- }
589
- else
590
- {
591
- this.Log(
592
- $"'{config.name}': No new sprites to add (all found sprites might already be in the list)."
593
- );
594
- }
595
-
596
- result.spritesToAdd.Clear();
597
- ScanFoldersForConfig(config);
598
- Repaint();
599
- }
600
-
601
- private void RemoveUnfoundSprites(ScriptableSpriteAtlas config, ScanResult result)
602
- {
603
- if (result.spritesToRemove.Count <= 0)
604
- {
605
- return;
606
- }
607
-
608
- SerializedObject so = new(config);
609
- SerializedProperty spritesListProp = so.FindProperty("spritesToPack");
610
-
611
- Undo.RecordObject(config, "Remove Unfound Sprites from Atlas Config");
612
-
613
- int countRemoved = 0;
614
- List<Sprite> spritesActuallyToRemove = new(result.spritesToRemove);
615
-
616
- for (int i = spritesListProp.arraySize - 1; 0 <= i; --i)
617
- {
618
- SerializedProperty element = spritesListProp.GetArrayElementAtIndex(i);
619
- if (
620
- element.objectReferenceValue != null
621
- && spritesActuallyToRemove.Contains(element.objectReferenceValue as Sprite)
622
- )
623
- {
624
- element.objectReferenceValue = null;
625
- spritesListProp.DeleteArrayElementAtIndex(i);
626
- countRemoved++;
627
- }
628
- }
629
-
630
- if (countRemoved > 0)
631
- {
632
- so.ApplyModifiedProperties();
633
- this.Log(
634
- $"'{config.name}': Removed {countRemoved} sprites that were no longer found by scan."
635
- );
636
- }
637
- result.spritesToRemove.Clear();
638
- ScanFoldersForConfig(config);
639
- Repaint();
640
- }
641
-
642
- private void GenerateAllAtlases()
643
- {
644
- if (_atlasConfigs.Count == 0)
645
- {
646
- EditorUtility.DisplayDialog(
647
- "No Configurations",
648
- "No ScriptableSpriteAtlas configurations found to generate.",
649
- "OK"
650
- );
651
- return;
652
- }
653
-
654
- int totalConfigs = _atlasConfigs.Count;
655
- int currentConfig = 0;
656
-
657
- AssetDatabase.StartAssetEditing();
658
- try
659
- {
660
- foreach (ScriptableSpriteAtlas config in _atlasConfigs)
661
- {
662
- if (config == null)
663
- {
664
- continue;
665
- }
666
-
667
- currentConfig++;
668
- float progress = (float)currentConfig / totalConfigs;
669
- EditorUtility.DisplayProgressBar(
670
- "Generating Sprite Atlases",
671
- $"Processing: {config.name}",
672
- progress
673
- );
674
- GenerateSingleAtlas(config, false);
675
- }
676
- }
677
- finally
678
- {
679
- AssetDatabase.StopAssetEditing();
680
- EditorUtility.ClearProgressBar();
681
- AssetDatabase.SaveAssets();
682
- AssetDatabase.Refresh();
683
- }
684
- }
685
-
686
- private void GenerateSingleAtlas(
687
- ScriptableSpriteAtlas config,
688
- bool refreshAssetsImmediately = true
689
- )
690
- {
691
- if (config == null)
692
- {
693
- this.LogError($"Attempted to generate atlas from a null config.");
694
- return;
695
- }
696
- string outputPath = config.FullOutputPath;
697
- if (string.IsNullOrWhiteSpace(outputPath))
698
- {
699
- this.LogError(
700
- $"'{config.name}': Output path or name is not set. Cannot generate atlas."
701
- );
702
- return;
703
- }
704
-
705
- string directory = Path.GetDirectoryName(outputPath);
706
- if (!string.IsNullOrWhiteSpace(directory) && !Directory.Exists(directory))
707
- {
708
- Directory.CreateDirectory(directory);
709
- AssetDatabase.Refresh();
710
- }
711
-
712
- SpriteAtlas atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(outputPath);
713
- bool newAtlas = false;
714
- if (atlas == null)
715
- {
716
- atlas = new SpriteAtlas();
717
- newAtlas = true;
718
- this.Log($"'{config.name}': Creating new SpriteAtlas at {outputPath}");
719
- }
720
- else
721
- {
722
- this.Log($"'{config.name}': Updating existing SpriteAtlas at {outputPath}");
723
- atlas.Remove(atlas.GetPackables());
724
- }
725
-
726
- SpriteAtlasPackingSettings packingSettings = atlas.GetPackingSettings();
727
- packingSettings.enableRotation = config.enableRotation;
728
- packingSettings.padding = config.padding;
729
- atlas.SetPackingSettings(packingSettings);
730
-
731
- SpriteAtlasTextureSettings textureSettings = atlas.GetTextureSettings();
732
- textureSettings.readable = config.readWriteEnabled;
733
- atlas.SetTextureSettings(textureSettings);
734
-
735
- TextureImporterPlatformSettings platformSettings = atlas.GetPlatformSettings(
736
- "DefaultTexturePlatform"
737
- );
738
- if (string.IsNullOrWhiteSpace(platformSettings.name))
739
- {
740
- platformSettings.name = "DefaultTexturePlatform";
741
- }
742
-
743
- platformSettings.overridden = true;
744
- platformSettings.maxTextureSize = config.maxTextureSize;
745
- platformSettings.crunchedCompression = config.useCrunchCompression;
746
- platformSettings.compressionQuality = config.crunchCompressionLevel;
747
- platformSettings.format = TextureImporterFormat.Automatic;
748
- platformSettings.textureCompression = config.compression;
749
- atlas.SetPlatformSettings(platformSettings);
750
-
751
- Object[] spritesToAdd = config.spritesToPack.Where(s => s != null).ToArray<Object>();
752
- if (spritesToAdd.Length > 0)
753
- {
754
- atlas.Add(spritesToAdd);
755
- }
756
- else
757
- {
758
- this.LogWarn(
759
- $"'{config.name}': No sprites in the 'spritesToPack' list. Atlas will be empty."
760
- );
761
- }
762
-
763
- if (newAtlas)
764
- {
765
- AssetDatabase.CreateAsset(atlas, outputPath);
766
- }
767
- else
768
- {
769
- EditorUtility.SetDirty(atlas);
770
- }
771
-
772
- if (refreshAssetsImmediately)
773
- {
774
- AssetDatabase.SaveAssets();
775
- AssetDatabase.Refresh();
776
- }
777
- this.Log(
778
- $"'{config.name}': Successfully generated/updated at {outputPath}. Sprites included: {spritesToAdd.Length}."
779
- );
780
- }
781
-
782
- private void PackAllProjectAtlases()
783
- {
784
- this.Log(
785
- $"Starting to pack all Sprite Atlases in the project for target: {EditorUserBuildSettings.activeBuildTarget}"
786
- );
787
- SpriteAtlasUtility.PackAllAtlases(EditorUserBuildSettings.activeBuildTarget);
788
- this.Log($"Finished packing all Sprite Atlases.");
789
- AssetDatabase.Refresh();
790
- }
791
-
792
- private void ForceUncompressedSourceSprites(ScriptableSpriteAtlas config)
793
- {
794
- if (config == null)
795
- {
796
- return;
797
- }
798
-
799
- List<Sprite> spritesToProcess = config
800
- .spritesToPack.Where(s => s != null && s.texture != null)
801
- .ToList();
802
- if (spritesToProcess.Count == 0)
803
- {
804
- this.LogWarn(
805
- $"'{config.name}': No valid sprites with textures in the list to modify."
806
- );
807
- EditorUtility.DisplayDialog(
808
- "No Sprites",
809
- "No valid sprites found in the configuration's list to process.",
810
- "OK"
811
- );
812
- return;
813
- }
814
-
815
- int modifiedCount = 0;
816
- int errorCount = 0;
817
- HashSet<string> processedAssetPaths = new();
818
-
819
- AssetDatabase.StartAssetEditing();
820
- try
821
- {
822
- for (int i = 0; i < spritesToProcess.Count; ++i)
823
- {
824
- Sprite sprite = spritesToProcess[i];
825
- EditorUtility.DisplayProgressBar(
826
- "Modifying Source Sprite Import Settings",
827
- $"Processing: {sprite.name} ({i + 1}/{spritesToProcess.Count})",
828
- (float)(i + 1) / spritesToProcess.Count
829
- );
830
-
831
- string assetPath = AssetDatabase.GetAssetPath(sprite.texture);
832
- if (string.IsNullOrWhiteSpace(assetPath))
833
- {
834
- this.LogWarn(
835
- $"Could not find asset path for sprite's texture: {sprite.name}. Skipping."
836
- );
837
- errorCount++;
838
- continue;
839
- }
840
-
841
- if (!processedAssetPaths.Add(assetPath))
842
- {
843
- continue;
844
- }
845
-
846
- TextureImporter importer =
847
- AssetImporter.GetAtPath(assetPath) as TextureImporter;
848
- if (importer == null)
849
- {
850
- this.LogWarn(
851
- $"Could not get TextureImporter for asset: {assetPath} (from sprite: {sprite.name}). Skipping."
852
- );
853
- errorCount++;
854
- continue;
855
- }
856
-
857
- bool settingsActuallyModified = false;
858
-
859
- if (importer.crunchedCompression)
860
- {
861
- importer.crunchedCompression = false;
862
- settingsActuallyModified = true;
863
- }
864
-
865
- if (importer.textureCompression != TextureImporterCompression.Uncompressed)
866
- {
867
- importer.textureCompression = TextureImporterCompression.Uncompressed;
868
- settingsActuallyModified = true;
869
- }
870
-
871
- TextureImporterPlatformSettings platformSettings =
872
- importer.GetDefaultPlatformTextureSettings();
873
- bool platformSettingsChangedThisTime = false;
874
- TextureImporterFormat targetFormat = importer.DoesSourceTextureHaveAlpha()
875
- ? TextureImporterFormat.RGBA32
876
- : TextureImporterFormat.RGB24;
877
-
878
- if (platformSettings.format != targetFormat)
879
- {
880
- platformSettings.format = targetFormat;
881
- platformSettingsChangedThisTime = true;
882
- }
883
- if (platformSettings.crunchedCompression)
884
- {
885
- platformSettings.crunchedCompression = false;
886
- platformSettingsChangedThisTime = true;
887
- }
888
- if (platformSettings.compressionQuality != 100)
889
- {
890
- platformSettings.compressionQuality = 100;
891
- platformSettingsChangedThisTime = true;
892
- }
893
-
894
- if (platformSettingsChangedThisTime || !platformSettings.overridden)
895
- {
896
- platformSettings.overridden = true;
897
- importer.SetPlatformTextureSettings(platformSettings);
898
- settingsActuallyModified = true;
899
- }
900
-
901
- if (settingsActuallyModified)
902
- {
903
- importer.SaveAndReimport();
904
- modifiedCount++;
905
- this.Log(
906
- $"Set import settings for texture: {assetPath} (from sprite: {sprite.name}) to uncompressed ({targetFormat})."
907
- );
908
- }
909
- }
910
- }
911
- finally
912
- {
913
- AssetDatabase.StopAssetEditing();
914
- EditorUtility.ClearProgressBar();
915
- }
916
-
917
- if (modifiedCount > 0 || errorCount > 0)
918
- {
919
- AssetDatabase.Refresh();
920
- }
921
-
922
- string summaryMessage =
923
- $"Finished processing source sprite textures for '{config.name}'.\n"
924
- + $"Successfully modified importers for: {modifiedCount} textures.\n"
925
- + $"Errors/Skipped duplicates: {errorCount + (spritesToProcess.Count - processedAssetPaths.Count)}.";
926
- this.Log($"{summaryMessage}");
927
- }
928
- }
929
- #endif
930
- }