Component move/copy utility
This commit is contained in:
217
Assets/Editor/Utilities/ComponentTransferWindow.cs
Normal file
217
Assets/Editor/Utilities/ComponentTransferWindow.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Editor.Utilities
|
||||
{
|
||||
public class ComponentTransferWindow : EditorWindow
|
||||
{
|
||||
private GameObject sourceGameObject;
|
||||
private GameObject targetGameObject;
|
||||
private Vector2 scrollPosition;
|
||||
private Dictionary<Component, bool> componentSelections = new Dictionary<Component, bool>();
|
||||
private bool selectAll = false;
|
||||
|
||||
[MenuItem("Tools/Component Transfer Tool")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
ComponentTransferWindow window = GetWindow<ComponentTransferWindow>("Component Transfer");
|
||||
window.minSize = new Vector2(400, 300);
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
GUILayout.Label("Component Transfer Tool", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
DrawGameObjectSelectors();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (sourceGameObject != null)
|
||||
{
|
||||
DrawComponentSelectionArea();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
DrawOperationButtons();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawGameObjectSelectors()
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
GameObject newSource = EditorGUILayout.ObjectField("Source GameObject", sourceGameObject, typeof(GameObject), true) as GameObject;
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
if (newSource != sourceGameObject)
|
||||
{
|
||||
sourceGameObject = newSource;
|
||||
RefreshComponentList();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
targetGameObject = EditorGUILayout.ObjectField("Target GameObject", targetGameObject, typeof(GameObject), true) as GameObject;
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
// Error validation
|
||||
if (sourceGameObject == targetGameObject && sourceGameObject != null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Source and target cannot be the same GameObject.", MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawComponentSelectionArea()
|
||||
{
|
||||
if (componentSelections.Count == 0)
|
||||
{
|
||||
EditorGUILayout.LabelField("No components found on source GameObject.");
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("Select Components to Transfer:", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
bool newSelectAll = EditorGUILayout.ToggleLeft("Select All", selectAll);
|
||||
if (EditorGUI.EndChangeCheck() && newSelectAll != selectAll)
|
||||
{
|
||||
selectAll = newSelectAll;
|
||||
foreach (var key in componentSelections.Keys.ToArray())
|
||||
{
|
||||
componentSelections[key] = selectAll;
|
||||
}
|
||||
}
|
||||
|
||||
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
||||
|
||||
foreach (var kvp in componentSelections.ToArray())
|
||||
{
|
||||
Component component = kvp.Key;
|
||||
if (component != null)
|
||||
{
|
||||
string componentName = component.GetType().Name;
|
||||
componentSelections[component] = EditorGUILayout.ToggleLeft(componentName, componentSelections[component]);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
private void DrawOperationButtons()
|
||||
{
|
||||
bool isValid = sourceGameObject != null && targetGameObject != null && sourceGameObject != targetGameObject;
|
||||
bool hasSelection = HasSelectedComponents();
|
||||
|
||||
EditorGUI.BeginDisabledGroup(!isValid || !hasSelection);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (GUILayout.Button("Copy Components"))
|
||||
{
|
||||
CopyComponents(false);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Move Components"))
|
||||
{
|
||||
CopyComponents(true);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
|
||||
private void RefreshComponentList()
|
||||
{
|
||||
componentSelections.Clear();
|
||||
|
||||
if (sourceGameObject != null)
|
||||
{
|
||||
Component[] components = sourceGameObject.GetComponents<Component>();
|
||||
|
||||
foreach (Component component in components)
|
||||
{
|
||||
// Skip Transform component as it's required and should not be transferred
|
||||
if (component is Transform)
|
||||
continue;
|
||||
|
||||
componentSelections.Add(component, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasSelectedComponents()
|
||||
{
|
||||
foreach (bool selected in componentSelections.Values)
|
||||
{
|
||||
if (selected)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CopyComponents(bool moveInsteadOfCopy)
|
||||
{
|
||||
if (sourceGameObject == null || targetGameObject == null)
|
||||
return;
|
||||
|
||||
Undo.RegisterCompleteObjectUndo(targetGameObject, moveInsteadOfCopy ? "Move Components" : "Copy Components");
|
||||
if (moveInsteadOfCopy)
|
||||
{
|
||||
Undo.RegisterCompleteObjectUndo(sourceGameObject, "Move Components (Source)");
|
||||
}
|
||||
|
||||
// Store references to components that need to be destroyed after copying
|
||||
List<Component> componentsToDestroy = new List<Component>();
|
||||
|
||||
// Copy each selected component
|
||||
foreach (var kvp in componentSelections)
|
||||
{
|
||||
if (kvp.Value) // If component is selected
|
||||
{
|
||||
Component sourceComponent = kvp.Key;
|
||||
|
||||
if (sourceComponent != null)
|
||||
{
|
||||
// Skip Transform component as it's required
|
||||
if (sourceComponent is Transform)
|
||||
continue;
|
||||
|
||||
// Add the component of the same type to the target
|
||||
ComponentUtility.CopyComponent(sourceComponent);
|
||||
ComponentUtility.PasteComponentAsNew(targetGameObject);
|
||||
|
||||
// If we're moving components, mark this for destruction
|
||||
if (moveInsteadOfCopy)
|
||||
{
|
||||
componentsToDestroy.Add(sourceComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy components on source if needed (after copying all components)
|
||||
if (moveInsteadOfCopy)
|
||||
{
|
||||
foreach (Component component in componentsToDestroy)
|
||||
{
|
||||
Undo.DestroyObjectImmediate(component);
|
||||
}
|
||||
}
|
||||
|
||||
RefreshComponentList();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Editor/Utilities/ComponentTransferWindow.cs.meta
Normal file
11
Assets/Editor/Utilities/ComponentTransferWindow.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9dae5cb1c71f74a4eb8c8c0a77fe2e3f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user