A game about forced loneliness, made by TACStudios
at master 754 lines 27 kB view raw
1using System; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.U2D.Animation; 5 6namespace UnityEditor.U2D.Animation.SpriteLibraryEditor 7{ 8 internal class CategoryData 9 { 10 public readonly string name; 11 public readonly bool fromMain; 12 public readonly bool isOverride; 13 14 public CategoryData(string name, bool fromMain, bool isOverride) 15 { 16 this.name = name; 17 this.fromMain = fromMain; 18 this.isOverride = isOverride; 19 } 20 } 21 22 internal class LabelData 23 { 24 public readonly string name; 25 public readonly Sprite sprite; 26 public readonly bool fromMain; 27 public readonly bool spriteOverride; 28 public readonly bool categoryFromMain; 29 30 public LabelData(string name, Sprite sprite, bool fromMain, bool spriteOverride, bool categoryFromMain) 31 { 32 this.name = name; 33 this.sprite = sprite; 34 this.fromMain = fromMain; 35 this.spriteOverride = spriteOverride; 36 this.categoryFromMain = categoryFromMain; 37 } 38 } 39 40 internal class SpriteLibraryEditorModel : ScriptableObject 41 { 42 [SerializeField] 43 ActionType m_LastActionType; 44 45 public ActionType lastActionType 46 { 47 get => m_LastActionType; 48 set => m_LastActionType = value; 49 } 50 51 public SpriteLibraryAsset selectedAsset { get; private set; } 52 public bool hasSelectedCategories => m_SelectedCategoryIndices != null && m_SelectedCategoryIndices.Count > 0; 53 public bool hasSelectedLabels => m_SelectedLabelIndices != null && m_SelectedLabelIndices.Count > 0; 54 public bool isModified => m_CurrentVersion != m_SavedVersion; 55 public bool isSaving { get; private set; } 56 57 [SerializeField] 58 List<int> m_SelectedCategoryIndices = new(); 59 [SerializeField] 60 List<int> m_SelectedLabelIndices = new(); 61 62 [SerializeField] 63 List<SpriteLibCategoryOverride> m_CurrentLibrary; 64 65 [SerializeField] 66 uint m_CurrentVersion; 67 uint m_SavedVersion; 68 69 string m_SelectedAssetPath; 70 71 [SerializeField] 72 string m_PrimaryLibraryGUID; 73 74 public List<string> GetSelectedCategories() 75 { 76 var selection = new List<string>(); 77 if (m_CurrentLibrary == null) 78 return selection; 79 80 foreach (var selectedCategoryIndex in m_SelectedCategoryIndices) 81 selection.Add(m_CurrentLibrary[selectedCategoryIndex].name); 82 83 return selection; 84 } 85 86 public void SelectCategories(IList<string> newSelection) 87 { 88 if (newSelection == null || newSelection.Count == 0) 89 { 90 m_SelectedCategoryIndices = new List<int>(); 91 return; 92 } 93 94 if (m_CurrentLibrary == null) 95 return; 96 97 m_SelectedCategoryIndices = new List<int>(newSelection.Count); 98 for (var selection = 0; selection < newSelection.Count; selection++) 99 { 100 var index = -1; 101 for (var i = 0; i < m_CurrentLibrary.Count; i++) 102 { 103 if (m_CurrentLibrary[i].name == newSelection[selection]) 104 { 105 index = i; 106 break; 107 } 108 } 109 110 if (index != -1) 111 m_SelectedCategoryIndices.Add(index); 112 } 113 } 114 115 public List<string> GetSelectedLabels() 116 { 117 var selectedCategory = GetSelectedCategory(); 118 if (selectedCategory == null) 119 return new List<string>(); 120 121 var labels = selectedCategory.overrideEntries; 122 var selectedLabels = new List<string>(m_SelectedLabelIndices.Count); 123 for (var i = 0; i < m_SelectedLabelIndices.Count; i++) 124 selectedLabels.Add(labels[m_SelectedLabelIndices[i]].name); 125 126 return selectedLabels; 127 } 128 129 public void SelectLabels(IList<string> labels) 130 { 131 if (labels == null || labels.Count == 0) 132 { 133 m_SelectedLabelIndices = new List<int>(); 134 return; 135 } 136 137 var category = GetSelectedCategory(); 138 if (category == null) 139 return; 140 141 m_SelectedLabelIndices = new List<int>(labels.Count); 142 for (var i = 0; i < labels.Count; i++) 143 m_SelectedLabelIndices.Add(category.overrideEntries.FindIndex(label => label.name == labels[i])); 144 } 145 146 public List<CategoryData> GetAllCategories() 147 { 148 var allCategories = new List<CategoryData>(); 149 if (m_CurrentLibrary == null) 150 return allCategories; 151 152 for (var i = 0; i < m_CurrentLibrary.Count; i++) 153 allCategories.Add(CreateCategoryData(m_CurrentLibrary[i])); 154 155 return allCategories; 156 } 157 158 public List<CategoryData> GetFilteredCategories(string filterString, SearchType searchType, StringComparison comparison = StringComparison.OrdinalIgnoreCase) 159 { 160 var categories = new List<CategoryData>(); 161 if (m_CurrentLibrary != null) 162 { 163 var filter = searchType is SearchType.CategoryAndLabel or SearchType.Category && !string.IsNullOrEmpty(filterString); 164 foreach (var spriteLibCategoryOverride in m_CurrentLibrary) 165 { 166 if (!filter || spriteLibCategoryOverride.name.Contains(filterString, comparison)) 167 categories.Add(CreateCategoryData(spriteLibCategoryOverride)); 168 } 169 } 170 171 return categories; 172 } 173 174 public List<LabelData> GetAllLabels() 175 { 176 var category = GetSelectedCategory(); 177 if (category == null) 178 return new List<LabelData>(); 179 180 var categoryLabels = category.overrideEntries; 181 var labels = new List<LabelData>(category.entryOverrideCount); 182 for (var i = 0; i < categoryLabels.Count; i++) 183 labels.Add(CreateLabelData(category, categoryLabels[i])); 184 185 return labels; 186 } 187 188 public List<LabelData> GetFilteredLabels(string filterString, SearchType searchType, StringComparison comparison = StringComparison.OrdinalIgnoreCase) 189 { 190 var category = GetSelectedCategory(); 191 if (category == null) 192 return new List<LabelData>(); 193 194 var labels = new List<LabelData>(); 195 var filter = searchType is SearchType.CategoryAndLabel or SearchType.Label && !string.IsNullOrEmpty(filterString); 196 foreach (var categoryEntryOverride in category.overrideEntries) 197 { 198 if (!filter || categoryEntryOverride.name.Contains(filterString, comparison)) 199 labels.Add(CreateLabelData(category, categoryEntryOverride)); 200 } 201 202 return labels; 203 } 204 205 public void BeginUndo(ActionType actionType, string actionName) 206 { 207 lastActionType = actionType; 208 209 Undo.IncrementCurrentGroup(); 210 Undo.RegisterCompleteObjectUndo(this, actionName); 211 212 if (IsActionModifyingAssets(actionType)) 213 m_CurrentVersion++; 214 } 215 216 public void EndUndo() 217 { 218 Undo.CollapseUndoOperations(Undo.GetCurrentGroup()); 219 220 lastActionType = ActionType.None; 221 } 222 223 public static bool IsActionModifyingAssets(ActionType actionType) 224 { 225 var isNotModifying = actionType is 226 ActionType.None or 227 ActionType.SelectCategory or 228 ActionType.SelectLabels; 229 230 return !isNotModifying; 231 } 232 233 public void CreateNewLabel(string labelName) 234 { 235 var category = GetSelectedCategory(); 236 var newLabel = new SpriteCategoryEntryOverride 237 { 238 name = labelName, 239 sprite = null, 240 spriteOverride = null, 241 fromMain = false, 242 }; 243 category.overrideEntries.Add(newLabel); 244 category.RenameDuplicateOverrideEntries(); 245 category.UpdateOverrideCount(); 246 } 247 248 public void SetLabelSprite(string labelName, Sprite newSprite) 249 { 250 var category = GetSelectedCategory(); 251 var label = GetLabel(category, labelName); 252 if (label != null) 253 { 254 label.spriteOverride = newSprite; 255 if (!label.fromMain) 256 label.sprite = newSprite; 257 } 258 259 category.UpdateOverrideCount(); 260 } 261 262 public void DeleteSelectedLabels() 263 { 264 var category = GetSelectedCategory(); 265 if (category == null) 266 return; 267 268 var labelsToRemove = new List<SpriteCategoryEntryOverride>(); 269 for (var i = 0; i < m_SelectedLabelIndices.Count; i++) 270 { 271 var labelToRemove = category.overrideEntries[m_SelectedLabelIndices[i]]; 272 if (!labelToRemove.fromMain) 273 labelsToRemove.Add(labelToRemove); 274 } 275 276 foreach (var label in labelsToRemove) 277 category.overrideEntries.Remove(label); 278 279 category.UpdateOverrideCount(); 280 } 281 282 public void RenameSelectedLabel(string newName) 283 { 284 var category = GetSelectedCategory(); 285 var label = GetSelectedLabel(); 286 label.name = newName; 287 category.RenameDuplicateOverrideEntries(); 288 } 289 290 public void AddLabelsToCategory(string categoryName, IEnumerable<Sprite> sprites, bool replaceConflicting) 291 { 292 var category = GetCategory(categoryName); 293 var conflictingLabels = new List<Sprite>(); 294 var newLabels = new List<Sprite>(); 295 foreach (var sprite in sprites) 296 { 297 if (GetLabel(category, sprite.name) != null) 298 conflictingLabels.Add(sprite); 299 else 300 newLabels.Add(sprite); 301 } 302 303 foreach (var newLabel in newLabels) 304 category.overrideEntries.Add(new SpriteCategoryEntryOverride 305 { 306 name = newLabel.name, 307 sprite = newLabel, 308 spriteOverride = newLabel, 309 fromMain = false 310 }); 311 312 if (replaceConflicting) 313 { 314 foreach (var conflictingLabel in conflictingLabels) 315 { 316 var label = GetLabel(category, conflictingLabel.name); 317 label.spriteOverride = conflictingLabel; 318 if (!label.fromMain) 319 label.sprite = conflictingLabel; 320 } 321 } 322 else 323 { 324 foreach (var conflictingLabel in conflictingLabels) 325 { 326 category.overrideEntries.Add(new SpriteCategoryEntryOverride 327 { 328 name = conflictingLabel.name, 329 sprite = conflictingLabel, 330 spriteOverride = conflictingLabel, 331 fromMain = false 332 }); 333 } 334 } 335 336 category.RenameDuplicateOverrideEntries(); 337 category.UpdateOverrideCount(); 338 } 339 340 public void DeleteSelectedCategories() 341 { 342 if (m_CurrentLibrary == null || m_SelectedCategoryIndices == null || m_SelectedCategoryIndices.Count == 0) 343 return; 344 345 var categoriesToRemove = new List<SpriteLibCategoryOverride>(m_SelectedCategoryIndices.Count); 346 foreach (var selectedCategoryIndex in m_SelectedCategoryIndices) 347 categoriesToRemove.Add(m_CurrentLibrary[selectedCategoryIndex]); 348 349 foreach (var categoryToRemove in categoriesToRemove) 350 m_CurrentLibrary.Remove(categoryToRemove); 351 } 352 353 public void ReorderCategories(IList<string> reorderedCategories) 354 { 355 var categories = new List<SpriteLibCategoryOverride>(reorderedCategories.Count); 356 for (var i = 0; i < reorderedCategories.Count; i++) 357 { 358 var reorderedCategory = GetCategory(reorderedCategories[i]); 359 categories.Add(reorderedCategory); 360 } 361 362 m_CurrentLibrary = categories; 363 } 364 365 public void RenameSelectedCategory(string newName) 366 { 367 var category = GetSelectedCategory(); 368 category.name = newName; 369 RenameDuplicatedCategories(); 370 } 371 372 public void SelectAsset(SpriteLibraryAsset asset) 373 { 374 ClearUndo(); 375 376 m_SavedVersion = m_CurrentVersion; 377 378 selectedAsset = asset; 379 380 m_CurrentLibrary = new List<SpriteLibCategoryOverride>(); 381 m_PrimaryLibraryGUID = null; 382 383 m_SelectedAssetPath = selectedAsset != null ? AssetDatabase.GetAssetPath(selectedAsset) : null; 384 m_SelectedCategoryIndices = new List<int>(); 385 m_SelectedLabelIndices = new List<int>(); 386 387 var sourceAsset = selectedAsset != null ? SpriteLibrarySourceAssetImporter.LoadSpriteLibrarySourceAsset(m_SelectedAssetPath) : null; 388 if (sourceAsset != null) 389 { 390 m_CurrentLibrary = new List<SpriteLibCategoryOverride>(sourceAsset.library); 391 392 // Update hashes to make sure name hashes are correct. 393 foreach (var categoryOverride in m_CurrentLibrary) 394 categoryOverride.UpdateHash(); 395 396 m_PrimaryLibraryGUID = sourceAsset.primaryLibraryGUID; 397 398 var mainLibrary = GetMainLibrary(); 399 if (mainLibrary) 400 SetMainLibrary(mainLibrary); 401 } 402 } 403 404 public void ReorderLabels(IList<string> reorderedLabels) 405 { 406 var category = GetSelectedCategory(); 407 var labels = new List<SpriteCategoryEntryOverride>(reorderedLabels.Count); 408 for (var i = 0; i < reorderedLabels.Count; i++) 409 labels.Add(GetLabel(category, reorderedLabels[i])); 410 411 for (var i = 0; i < labels.Count; i++) 412 { 413 var label = labels[i]; 414 if (label.fromMain) 415 continue; 416 417 var index = category.overrideEntries.IndexOf(label); 418 419 (category.overrideEntries[i], category.overrideEntries[index]) = (category.overrideEntries[index], category.overrideEntries[i]); 420 } 421 422 category.overrideEntries = labels; 423 } 424 425 public void CreateNewCategory(string categoryName, IList<Sprite> sprites) 426 { 427 var newLabelCount = sprites?.Count ?? 0; 428 var newLabels = new List<SpriteCategoryEntryOverride>(newLabelCount); 429 if (sprites != null) 430 { 431 for (var i = 0; i < newLabelCount; i++) 432 newLabels.Add(new SpriteCategoryEntryOverride 433 { 434 name = sprites[i].name, 435 fromMain = false, 436 sprite = sprites[i], 437 spriteOverride = sprites[i] 438 }); 439 } 440 441 var category = new SpriteLibCategoryOverride 442 { 443 name = categoryName, 444 fromMain = false, 445 entryOverrideCount = newLabelCount, 446 overrideEntries = newLabels 447 }; 448 449 m_CurrentLibrary.Add(category); 450 RenameDuplicatedCategories(); 451 } 452 453 public void SaveLibrary(string path) 454 { 455 if (m_CurrentLibrary == null) 456 return; 457 458 Debug.Assert(!string.IsNullOrEmpty(path), "Asset path cannot be empty."); 459 460 m_SavedVersion = m_CurrentVersion; 461 isSaving = true; 462 var assetToSave = CreateInstance<SpriteLibrarySourceAsset>(); 463 assetToSave.SetLibrary(m_CurrentLibrary); 464 assetToSave.SetPrimaryLibraryGUID(m_PrimaryLibraryGUID); 465 SpriteLibrarySourceAssetImporter.SaveSpriteLibrarySourceAsset(assetToSave, path); 466 AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); 467 isSaving = false; 468 } 469 470 public SpriteLibraryAsset GetMainLibrary() 471 { 472 if (string.IsNullOrEmpty(m_PrimaryLibraryGUID)) 473 return null; 474 var assetPath = AssetDatabase.GUIDToAssetPath(m_PrimaryLibraryGUID); 475 var asset = AssetDatabase.LoadAssetAtPath<SpriteLibraryAsset>(assetPath); 476 return asset; 477 } 478 479 public void SetMainLibrary(SpriteLibraryAsset newMainLibrary) 480 { 481 m_PrimaryLibraryGUID = newMainLibrary != null ? AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(newMainLibrary)) : null; 482 var newCategories = newMainLibrary != null ? newMainLibrary.categories : new List<SpriteLibCategory>(); 483 484 var existingCategories = new List<SpriteLibCategoryOverride>(m_CurrentLibrary); 485 m_CurrentLibrary.Clear(); 486 487 // populate new primary 488 foreach (var newCategory in newCategories) 489 { 490 var labels = new List<SpriteCategoryEntryOverride>(); 491 SpriteLibCategoryOverride existingCategory = null; 492 for (var i = 0; i < existingCategories.Count; i++) 493 { 494 var category = existingCategories[i]; 495 if (category.name == newCategory.name) 496 { 497 existingCategory = category; 498 existingCategory.fromMain = true; 499 existingCategories.RemoveAt(i); 500 break; 501 } 502 } 503 504 var newEntries = newCategory.categoryList; 505 foreach (var newEntry in newEntries) 506 { 507 var sprite = newEntry.sprite; 508 509 labels.Add(new SpriteCategoryEntryOverride 510 { 511 name = newEntry.name, 512 sprite = sprite, 513 spriteOverride = sprite, 514 fromMain = true 515 }); 516 } 517 518 var overrideCount = 0; 519 if (existingCategory != null) 520 { 521 foreach (var existingLabel in existingCategory.overrideEntries) 522 { 523 var foundLabel = false; 524 foreach (var newLabel in labels) 525 { 526 if (existingLabel.name == newLabel.name) 527 { 528 if (newLabel.spriteOverride != existingLabel.spriteOverride) 529 { 530 newLabel.spriteOverride = existingLabel.spriteOverride; 531 overrideCount++; 532 } 533 534 foundLabel = true; 535 break; 536 } 537 } 538 539 if (!foundLabel) 540 { 541 overrideCount++; 542 labels.Add(new SpriteCategoryEntryOverride 543 { 544 name = existingLabel.name, 545 sprite = existingLabel.sprite, 546 spriteOverride = existingLabel.spriteOverride, 547 fromMain = false 548 }); 549 } 550 } 551 } 552 553 m_CurrentLibrary.Add(new SpriteLibCategoryOverride 554 { 555 name = newCategory.name, 556 overrideEntries = labels, 557 fromMain = true, 558 entryOverrideCount = overrideCount 559 }); 560 } 561 562 foreach (var existingCategory in existingCategories) 563 { 564 var keepCategory = false; 565 if (existingCategory.fromMain) 566 { 567 for (var i = existingCategory.overrideEntries.Count; i-- > 0;) 568 { 569 var entry = existingCategory.overrideEntries[i]; 570 if (!entry.fromMain || entry.sprite != entry.spriteOverride) 571 { 572 entry.fromMain = false; 573 entry.sprite = entry.spriteOverride; 574 keepCategory = true; 575 } 576 else 577 existingCategory.overrideEntries.RemoveAt(i); 578 } 579 } 580 581 if (!existingCategory.fromMain || keepCategory) 582 { 583 existingCategory.fromMain = false; 584 existingCategory.entryOverrideCount = 0; 585 m_CurrentLibrary.Add(existingCategory); 586 } 587 } 588 } 589 590 public void RevertLabels(IList<string> labels) 591 { 592 var category = GetSelectedCategory(); 593 foreach (var labelName in labels) 594 { 595 var label = GetLabel(category, labelName); 596 if (label.fromMain && label.sprite != label.spriteOverride) 597 { 598 label.spriteOverride = label.sprite; 599 } 600 else if (category.fromMain && !label.fromMain) 601 { 602 category.overrideEntries.Remove(label); 603 } 604 } 605 606 category.UpdateOverrideCount(); 607 } 608 609 public void SetAssetPath(string assetPath) 610 { 611 m_SelectedAssetPath = assetPath; 612 } 613 614 SpriteLibCategoryOverride GetSelectedCategory() 615 { 616 if (m_CurrentLibrary == null || m_CurrentLibrary.Count == 0 || !hasSelectedCategories) 617 return null; 618 619 var selectedCategoryIndex = m_SelectedCategoryIndices[0]; 620 if (selectedCategoryIndex < 0 || selectedCategoryIndex >= m_CurrentLibrary.Count) 621 return null; 622 623 return m_CurrentLibrary[selectedCategoryIndex]; 624 } 625 626 SpriteLibCategoryOverride GetCategory(string categoryName) 627 { 628 if (m_CurrentLibrary == null || m_CurrentLibrary.Count == 0) 629 return null; 630 631 foreach (var category in m_CurrentLibrary) 632 { 633 if (category.name == categoryName) 634 return category; 635 } 636 637 return null; 638 } 639 640 SpriteCategoryEntryOverride GetSelectedLabel() 641 { 642 var selectedCategory = GetSelectedCategory(); 643 if (selectedCategory == null || !hasSelectedLabels) 644 return null; 645 646 var selectedLabelIndex = m_SelectedLabelIndices[0]; 647 if (selectedLabelIndex < 0 || selectedLabelIndex >= selectedCategory.overrideEntries.Count) 648 return null; 649 650 return selectedCategory.overrideEntries[selectedLabelIndex]; 651 } 652 653 static SpriteCategoryEntryOverride GetLabel(SpriteLibCategoryOverride category, string labelName) 654 { 655 if (category == null) 656 return null; 657 658 foreach (var spriteCategoryEntryOverride in category.overrideEntries) 659 { 660 if (spriteCategoryEntryOverride.name == labelName) 661 return spriteCategoryEntryOverride; 662 } 663 664 return null; 665 } 666 667 public List<LabelData> GetLabels(string categoryName) 668 { 669 if (m_CurrentLibrary != null && m_CurrentLibrary != null) 670 { 671 foreach (var spriteLibCategoryOverride in m_CurrentLibrary) 672 { 673 if (spriteLibCategoryOverride.name == categoryName) 674 { 675 var labelsCache = spriteLibCategoryOverride.overrideEntries; 676 var labels = new List<LabelData>(labelsCache.Count); 677 foreach (var categoryEntryOverride in labelsCache) 678 labels.Add(CreateLabelData(spriteLibCategoryOverride, categoryEntryOverride)); 679 return labels; 680 } 681 } 682 } 683 684 return new List<LabelData>(); 685 } 686 687 public bool CompareLabels(IList<string> labelsToCompare) 688 { 689 if (labelsToCompare == null) 690 return false; 691 692 var category = GetSelectedCategory(); 693 if (category == null || category.entryOverrideCount != labelsToCompare.Count) 694 return false; 695 696 for (var i = 0; i < labelsToCompare.Count; i++) 697 { 698 if (category.overrideEntries[i].name != labelsToCompare[i]) 699 return false; 700 } 701 702 return true; 703 } 704 705 public bool CompareCategories(IList<string> categoriesToCompare) 706 { 707 if (categoriesToCompare == null) 708 return false; 709 710 if (m_CurrentLibrary.Count != categoriesToCompare.Count) 711 return false; 712 713 for (var i = 0; i < categoriesToCompare.Count; i++) 714 { 715 if (m_CurrentLibrary[i].name != categoriesToCompare[i]) 716 return false; 717 } 718 719 return true; 720 } 721 722 void RenameDuplicatedCategories() 723 { 724 if (m_CurrentLibrary != null) 725 SpriteLibraryAsset.RenameDuplicate(m_CurrentLibrary, (_, _) => { }); 726 } 727 728 void ClearUndo() => Undo.ClearUndo(this); 729 730 public void Destroy() 731 { 732 ClearUndo(); 733 DestroyImmediate(this); 734 } 735 736 static CategoryData CreateCategoryData(SpriteLibCategoryOverride category) 737 { 738 return new CategoryData( 739 name: category.name, 740 fromMain: category.fromMain, 741 isOverride: category.fromMain && category.entryOverrideCount > 0); 742 } 743 744 static LabelData CreateLabelData(SpriteLibCategoryOverride category, SpriteCategoryEntryOverride label) 745 { 746 return new LabelData( 747 name: label.name, 748 sprite: label.spriteOverride, 749 fromMain: label.fromMain, 750 spriteOverride: label.sprite != label.spriteOverride, 751 categoryFromMain: category.fromMain); 752 } 753 } 754}