Files
Fishing2/Assets/Plugins/vInspector/VInspectorComponentClipboard.cs
2025-05-10 12:49:47 +08:00

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