206 lines
5.9 KiB
C#
206 lines
5.9 KiB
C#
#if UNITY_EDITOR
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEditor;
|
|
using UnityEditor.ShortcutManagement;
|
|
using System.Reflection;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using Type = System.Type;
|
|
using static VInspector.Libs.VUtils;
|
|
using static VInspector.Libs.VGUI;
|
|
|
|
|
|
|
|
namespace VInspector
|
|
{
|
|
public class VInspectorComponentClipboard : ScriptableSingleton<VInspectorComponentClipboard>
|
|
{
|
|
public static void CopyComponent(Component component)
|
|
{
|
|
instance.RecordUndo();
|
|
|
|
if (instance.copiedComponetDatas.FirstOrDefault(r => r.sourceComponent == component) is ComponentData alreadyCopiedData)
|
|
{
|
|
instance.discardedComponentDatas.Add(alreadyCopiedData);
|
|
instance.copiedComponetDatas.Remove(alreadyCopiedData);
|
|
}
|
|
else
|
|
instance.copiedComponetDatas.Add(GetComponentData(component));
|
|
|
|
instance.Dirty();
|
|
|
|
}
|
|
public static void PasteComponentValues(ComponentData data, Component component)
|
|
{
|
|
component.RecordUndo();
|
|
|
|
ApplyComponentData(data, component);
|
|
|
|
component.Dirty();
|
|
|
|
|
|
|
|
instance.RecordUndo();
|
|
|
|
instance.copiedComponetDatas.Remove(data);
|
|
instance.discardedComponentDatas.Add(data);
|
|
|
|
instance.Dirty();
|
|
|
|
}
|
|
public static void PasteComponentAsNew(ComponentData data, GameObject gameObject)
|
|
{
|
|
var addedComponent = Undo.AddComponent(gameObject, data.sourceComponent.GetType());
|
|
|
|
ApplyComponentData(data, addedComponent);
|
|
|
|
}
|
|
|
|
public static void ClearCopiedDatas()
|
|
{
|
|
instance.RecordUndo();
|
|
|
|
instance.discardedComponentDatas.AddRange(instance.copiedComponetDatas);
|
|
instance.copiedComponetDatas.Clear();
|
|
|
|
instance.Dirty();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool CanComponentsBePastedTo(IEnumerable<GameObject> targetGos)
|
|
{
|
|
if (!targetGos.Any()) return false;
|
|
|
|
foreach (var copiedData in instance.copiedComponetDatas)
|
|
if (nonDuplicableComponentTypes.Contains(copiedData.sourceComponent.GetType()))
|
|
if (targetGos.Any(r => r.TryGetComponent(copiedData.sourceComponent.GetType(), out _)))
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
static Type[] nonDuplicableComponentTypes = new[]
|
|
{
|
|
typeof(Transform),
|
|
typeof(RectTransform),
|
|
typeof(MeshFilter),
|
|
typeof(MeshRenderer),
|
|
typeof(SkinnedMeshRenderer),
|
|
typeof(Camera),
|
|
typeof(AudioListener),
|
|
typeof(Rigidbody),
|
|
typeof(Rigidbody2D),
|
|
typeof(Light),
|
|
typeof(Canvas),
|
|
typeof(Animation),
|
|
typeof(Animator),
|
|
typeof(AudioSource),
|
|
typeof(ParticleSystem),
|
|
typeof(TrailRenderer),
|
|
typeof(LineRenderer),
|
|
typeof(LensFlare),
|
|
typeof(Projector),
|
|
typeof(AudioReverbZone),
|
|
typeof(AudioEchoFilter),
|
|
typeof(Terrain),
|
|
typeof(TerrainCollider),
|
|
|
|
};
|
|
|
|
|
|
|
|
[SerializeReference] public List<ComponentData> copiedComponetDatas = new();
|
|
|
|
[SerializeReference] public List<ComponentData> discardedComponentDatas = new(); // removed datas get stashed here so they can be restored on undo/redo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void SaveComponent(Component component)
|
|
{
|
|
instance.RecordUndo();
|
|
|
|
if (instance.savedComponentDatas.FirstOrDefault(r => r.sourceComponent == component) is ComponentData alreadySavedData)
|
|
{
|
|
instance.discardedComponentDatas.Add(alreadySavedData);
|
|
instance.savedComponentDatas.Remove(alreadySavedData);
|
|
}
|
|
else
|
|
instance.savedComponentDatas.Add(GetComponentData(component));
|
|
|
|
instance.Dirty();
|
|
|
|
}
|
|
|
|
public static void OnPlaymodeStateChanged(PlayModeStateChange state)
|
|
{
|
|
if (state != PlayModeStateChange.EnteredEditMode) return;
|
|
|
|
foreach (var data in instance.savedComponentDatas)
|
|
if (EditorUtility.InstanceIDToObject(data.sourceComponent.GetInstanceID()) is Component sourceComponent)
|
|
ApplyComponentData(data, sourceComponent);
|
|
|
|
instance.savedComponentDatas.Clear();
|
|
|
|
}
|
|
|
|
[SerializeReference] public List<ComponentData> savedComponentDatas = new();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static ComponentData GetComponentData(Component component)
|
|
{
|
|
var data = new ComponentData();
|
|
|
|
data.sourceComponent = component;
|
|
|
|
|
|
var property = new SerializedObject(component).GetIterator();
|
|
|
|
if (!property.Next(true)) return data;
|
|
|
|
|
|
do data.serializedPropertyValues_byPath[property.propertyPath] = property.GetBoxedValue();
|
|
while (property.NextVisible(true));
|
|
|
|
return data;
|
|
|
|
}
|
|
public static void ApplyComponentData(ComponentData componentData, Component targetComponent)
|
|
{
|
|
foreach (var kvp in componentData.serializedPropertyValues_byPath)
|
|
{
|
|
var so = new SerializedObject(targetComponent);
|
|
var property = so.FindProperty(kvp.Key);
|
|
|
|
so.Update();
|
|
|
|
property.SetBoxedValue(kvp.Value);
|
|
|
|
so.ApplyModifiedProperties();
|
|
|
|
targetComponent.Dirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class ComponentData { public Component sourceComponent; public Dictionary<string, object> serializedPropertyValues_byPath = new(); }
|
|
|
|
}
|
|
}
|
|
#endif |