Ingen beskrivning
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RemoveAdditionalDataUtils.cs 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. using JetBrains.Annotations;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics.CodeAnalysis;
  5. using System.Linq;
  6. using UnityEngine;
  7. using UnityEngine.Rendering;
  8. namespace UnityEditor.Rendering
  9. {
  10. /// <summary>
  11. /// Utilities to remove <see cref="MonoBehaviour"/> implementing <see cref="IAdditionalData"/>
  12. /// </summary>
  13. public static class RemoveAdditionalDataUtils
  14. {
  15. static int s_DialogToSkip = 0;
  16. /// <summary>
  17. /// Removes a <see cref="IAdditionalData"/> and it's components defined by <see cref="RequireComponent"/>
  18. /// </summary>
  19. /// <param name="command">The command that is executing the removal</param>
  20. /// <param name="promptDisplay">If the command must prompt a display to get user confirmation</param>
  21. /// <exception cref="Exception">If the given <see cref="MonoBehaviour"/> is not an <see cref="IAdditionalData"/></exception>
  22. public static void RemoveAdditionalData([DisallowNull] MenuCommand command, bool promptDisplay = true)
  23. {
  24. if (command.context is not Component component)
  25. return;
  26. //If the user agree to remove component, everything is removed in the current selection.
  27. //So other components will not trigger this (contextual menu implementation check component existance)
  28. //But if the user chose to cancel, we need to skip the prompt for a certain amount of component given by the selection size.
  29. if (ShouldPrompt())
  30. RemoveAdditionalData(component, promptDisplay);
  31. }
  32. static void RemoveAdditionalData([DisallowNull] Component additionalDataComponent, bool promptDisplay = true)
  33. {
  34. using (ListPool<Type>.Get(out var componentTypesToRemove))
  35. {
  36. if (!TryGetComponentsToRemove(additionalDataComponent as IAdditionalData, componentTypesToRemove, out var error))
  37. throw error;
  38. if (!promptDisplay || EditorUtility.DisplayDialog(
  39. title: $"Are you sure you want to proceed?",
  40. message: $"This operation will also remove {string.Join($"{Environment.NewLine} - ", componentTypesToRemove)}.",
  41. ok: $"Remove everything",
  42. cancel: "Cancel"))
  43. {
  44. RemoveAdditionalDataComponentOnSelection(additionalDataComponent.GetType(), componentTypesToRemove);
  45. }
  46. else
  47. {
  48. IgnoreNextPromptsForThisSelection();
  49. }
  50. }
  51. }
  52. static void IgnoreNextPromptsForThisSelection()
  53. => s_DialogToSkip = Selection.count - 1;
  54. static bool ShouldPrompt()
  55. {
  56. if (s_DialogToSkip > 0)
  57. {
  58. --s_DialogToSkip;
  59. return false;
  60. }
  61. return true;
  62. }
  63. static void RemoveAdditionalDataComponentOnSelection([DisallowNull] Type additionalDataType, [DisallowNull] List<Type> componentsTypeToRemove)
  64. {
  65. foreach (var selectedGameObject in Selection.gameObjects)
  66. {
  67. RemoveAdditionalDataComponent(selectedGameObject.GetComponent(additionalDataType), componentsTypeToRemove);
  68. }
  69. }
  70. static void RemoveAdditionalDataComponent([DisallowNull] Component additionalDataComponent, [DisallowNull] List<Type> componentsTypeToRemove)
  71. {
  72. using (ListPool<Component>.Get(out var components))
  73. {
  74. // Fetch all components
  75. foreach (var type in componentsTypeToRemove)
  76. {
  77. components.AddRange(additionalDataComponent.GetComponents(type));
  78. }
  79. // Remove all of them
  80. foreach (var mono in components)
  81. {
  82. RemoveComponentUtils.RemoveComponent(mono);
  83. }
  84. }
  85. }
  86. //internal for tests
  87. [MustUseReturnValue]
  88. internal static bool TryGetComponentsToRemove([DisallowNull] IAdditionalData additionalData, [DisallowNull] List<Type> componentsToRemove, [NotNullWhen(false)] out Exception error)
  89. {
  90. if (additionalData == null)
  91. {
  92. error = new ArgumentNullException(nameof(additionalData));
  93. return false;
  94. }
  95. if (componentsToRemove == null)
  96. {
  97. error = new ArgumentNullException(nameof(componentsToRemove));
  98. return false;
  99. }
  100. var type = additionalData.GetType();
  101. var requiredComponents = type.GetCustomAttributes(typeof(RequireComponent), true).Cast<RequireComponent>();
  102. if (!requiredComponents.Any())
  103. {
  104. error = new Exception($"Missing attribute {typeof(RequireComponent).FullName} on type {type.FullName}");
  105. return false;
  106. }
  107. foreach (var rc in requiredComponents)
  108. {
  109. componentsToRemove.Add(rc.m_Type0);
  110. if (rc.m_Type1 != null)
  111. componentsToRemove.Add(rc.m_Type1);
  112. if (rc.m_Type2 != null)
  113. componentsToRemove.Add(rc.m_Type2);
  114. }
  115. error = null;
  116. return true;
  117. }
  118. }
  119. }