Skip to content

Commit 068e485

Browse files
Editorフォルダ配置
1 parent d11f970 commit 068e485

11 files changed

+535
-0
lines changed

Assets/IntelligentCopyAndPaste/Editor.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Reflection;
3+
using UnityEngine;
4+
5+
namespace IntelligentCopyAndPaste
6+
{
7+
[Serializable]
8+
public class ArrayCopyAndPasteInfo
9+
{
10+
public MonoBehaviour TargetMonoBehaviour;
11+
public FieldInfo TargetFieldInfo;
12+
public Type ArrayElementType;
13+
public UnityEngine.Object[] CopySrcDatas;
14+
public UnityEngine.Object[] OriginalDatas;
15+
public bool IsOverride;
16+
public bool IsTypeList;
17+
public bool IsSingle;
18+
public string DisplayName;
19+
}
20+
}

Assets/IntelligentCopyAndPaste/Editor/ArrayCopyAndPasteInfo.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
using System;
2+
using System.Collections;
3+
using System.Linq;
4+
using System.Net;
5+
using System.Reflection;
6+
using UnityEngine;
7+
using UnityEditor;
8+
using Object = UnityEngine.Object;
9+
10+
namespace IntelligentCopyAndPaste
11+
{
12+
public static class ArrayCopyPasteComponent
13+
{
14+
public static System.Collections.Generic.List<Object> _data; //TODO 本当はprivateにしたいな
15+
16+
//# SHIFT
17+
//% CTRL
18+
//& ALT
19+
20+
/// <summary>
21+
/// 普通のコピー
22+
/// </summary>
23+
[MenuItem("Assets/Copy Assets Paths %c",false,-101)]
24+
private static void CopyAssetsPaths()
25+
{
26+
_data = new System.Collections.Generic.List<Object>(Selection.objects);
27+
IntelligentClipBoardWinow.Open();
28+
}
29+
30+
/// <summary>
31+
/// 追加コピー
32+
/// </summary>
33+
[MenuItem("Assets/AppendCopy Assets Paths #%c", false, -101)]
34+
private static void AppendCopyAssetsPaths()
35+
{
36+
if (_data == null) _data = new System.Collections.Generic.List<Object>();
37+
_data.AddRange(Selection.objects);
38+
IntelligentClipBoardWinow.Open();
39+
}
40+
41+
/// <summary>
42+
/// GameObjectを指定してのペースト ALT+V
43+
/// 可能性が非常に多いのでChoiceWindowを出す必要がある
44+
/// </summary>
45+
[MenuItem("Assets/Paste From Assets Paths %v", false, -101)]
46+
private static void _PasteFromCopiedObjects()
47+
{
48+
if (Validate() == false) return;
49+
var selection = Selection.gameObjects.First();
50+
var monoBehaviours = selection.GetComponents<MonoBehaviour>();
51+
ArrayCopyAndPaste(true, monoBehaviours);
52+
}
53+
54+
/// <summary>
55+
/// GameObjectを指定しての追加ペースト ALT+SHIFT+V
56+
/// 可能性が非常に多いのでChoiceWindowを出す必要がある
57+
/// </summary>
58+
[MenuItem("Assets/AppendPaste From Assets Paths #%v", false, -101)]
59+
private static void _AppendPasteFromCopiedObjects()
60+
{
61+
if (Validate() == false) return;
62+
var selection = Selection.gameObjects.First();
63+
var monoBehaviours = selection.GetComponents<MonoBehaviour>();
64+
ArrayCopyAndPaste(false, monoBehaviours);
65+
}
66+
67+
/// <summary>
68+
/// ContextMenuからのペースト ALT+V
69+
/// </summary>
70+
[MenuItem("CONTEXT/MonoBehaviour/Intelligent Paste %v", false)]
71+
private static void _PasetFromCopiedObjects(MenuCommand menuCommand)
72+
{
73+
if (Validate() == false) return;
74+
ArrayCopyAndPaste(true, menuCommand.context as MonoBehaviour);
75+
}
76+
77+
/// <summary>
78+
/// ContextMenuからの追加ペースト ALT+SHIFT+V
79+
/// </summary>
80+
[MenuItem("CONTEXT/MonoBehaviour/Intelligent AppendPaste #%v", false)]
81+
private static void _AppendPasteFromCopiedObjects(MenuCommand menuCommand)
82+
{
83+
if (Validate() == false) return;
84+
ArrayCopyAndPaste(false, menuCommand.context as MonoBehaviour);
85+
}
86+
87+
88+
private static void ArrayCopyAndPaste(bool isOverride, params MonoBehaviour[] monoBehaviours)
89+
{
90+
var arrayCopyAndPasteInfos = new System.Collections.Generic.List<ArrayCopyAndPasteInfo>();
91+
foreach (var mono in monoBehaviours)
92+
{
93+
var type = mono.GetType();
94+
var allFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.Instance);
95+
96+
foreach (var info in allFields)
97+
{
98+
//PrivateFieldはSerializeFieldAttributeが指定されてないものは対象にできない
99+
if (info.IsPrivate && info.GetCustomAttributes(typeof(SerializeField), false).Any() == false) continue;
100+
101+
//複数の場合があるので、どの配列に対して、どのインデックスから(追加か、上書きか)張り付けるかを判断するためのwindowを表示する
102+
var pasteInfo = new ArrayCopyAndPasteInfo
103+
{
104+
IsOverride = isOverride,
105+
TargetMonoBehaviour = mono,
106+
TargetFieldInfo = info,
107+
};
108+
109+
//配列かListか単品か判断
110+
var arrayType = info.FieldType;
111+
if (arrayType.IsGenericType && arrayType.GetGenericTypeDefinition() == typeof(System.Collections.Generic.List<>)) pasteInfo.IsTypeList = true;
112+
else if (arrayType.IsArray) pasteInfo.IsTypeList = false;
113+
else pasteInfo.IsSingle = true;
114+
115+
//配列(またはList)の要素のType
116+
if (pasteInfo.IsSingle)
117+
{
118+
pasteInfo.ArrayElementType = info.FieldType;
119+
}
120+
else
121+
{
122+
pasteInfo.ArrayElementType = pasteInfo.IsTypeList ? arrayType.GetGenericArguments().FirstOrDefault() : arrayType.GetElementType();
123+
}
124+
if (pasteInfo.ArrayElementType == null) continue;
125+
126+
//対象がこのMonoBehaviourのこのFieldだった場合のコピー元から張り付ける事ができる要素をまとめる
127+
pasteInfo.CopySrcDatas = _data.Select(o =>
128+
{
129+
if(o.GetType() == pasteInfo.ArrayElementType) return o;
130+
131+
Debug.Log(pasteInfo.ArrayElementType.Name);
132+
if (pasteInfo.ArrayElementType.IsSubclassOf(typeof(Component)))
133+
{
134+
var attachedComponent = (o as GameObject)?.GetComponent(pasteInfo.ArrayElementType);
135+
if (attachedComponent?.GetType() == pasteInfo.ArrayElementType) return attachedComponent;
136+
}
137+
return AssetDatabase.LoadAssetAtPath(AssetDatabase.GetAssetPath(o), pasteInfo.ArrayElementType);//TODO Spriteそのものの場合と、Spriteを持っているTextureの場合がある
138+
}).Where(o => o != null).ToArray();
139+
140+
if (pasteInfo.CopySrcDatas.Any() == false) continue; //コピー元が張り付ける先が無かった
141+
142+
if (pasteInfo.IsTypeList)
143+
{
144+
var originalData = pasteInfo.TargetFieldInfo.GetValue(pasteInfo.TargetMonoBehaviour) as IList;
145+
pasteInfo.OriginalDatas = new Object[originalData.Count];
146+
originalData.CopyTo(pasteInfo.OriginalDatas,0);
147+
}
148+
else if (pasteInfo.IsSingle)
149+
{
150+
var originalData = pasteInfo.TargetFieldInfo.GetValue(pasteInfo.TargetMonoBehaviour) as Object;
151+
pasteInfo.OriginalDatas = new []{originalData};
152+
}
153+
else
154+
{
155+
var originalData = pasteInfo.TargetFieldInfo.GetValue(pasteInfo.TargetMonoBehaviour) as Array;
156+
pasteInfo.OriginalDatas = originalData as Object[];
157+
}
158+
159+
pasteInfo.DisplayName = pasteInfo.TargetFieldInfo.DeclaringType.FullName + Environment.NewLine;
160+
161+
if (pasteInfo.IsSingle)
162+
{
163+
pasteInfo.DisplayName += pasteInfo.ArrayElementType.Name;
164+
}
165+
else if (pasteInfo.IsTypeList)
166+
{
167+
pasteInfo.DisplayName += "List<" + pasteInfo.ArrayElementType.Name + "> ";
168+
}
169+
else
170+
{
171+
pasteInfo.DisplayName += pasteInfo.ArrayElementType.Name + "[] ";
172+
}
173+
174+
//継承関係においては、同じフィールドが複数出てきてしまう可能性があるのでチェック
175+
if(arrayCopyAndPasteInfos.Any(inf => inf.TargetFieldInfo == pasteInfo.TargetFieldInfo))continue;
176+
177+
arrayCopyAndPasteInfos.Add(pasteInfo);
178+
}
179+
}
180+
181+
//TODO 対象が1つしか無かった場合にWindowを出すべきかどうか悩むところ
182+
if (arrayCopyAndPasteInfos.Any())
183+
{
184+
var message = arrayCopyAndPasteInfos.Count == 1 ? "以下のFieldが候補にあがりました。よろしいですか?" : "複数のFieldが候補にあがりました。どちらのFieldにペーストしますか?";
185+
CopyAndPasteChoiceWindow.Open(message, arrayCopyAndPasteInfos, pasteInfo =>
186+
{
187+
if (pasteInfo != null)
188+
{
189+
CopyProcess(pasteInfo);
190+
}
191+
});
192+
}
193+
}
194+
195+
private static void CopyProcess(ArrayCopyAndPasteInfo pasteInfo)
196+
{
197+
//Undoへ登録
198+
Undo.RecordObject(pasteInfo.TargetMonoBehaviour,"IntelligentCopyAndPaste - Paste");
199+
200+
if (pasteInfo.IsSingle)
201+
{
202+
//一つしかないので、IsOverride関係ない
203+
var pastData = pasteInfo.CopySrcDatas.FirstOrDefault();
204+
if (pastData == null)
205+
{
206+
pasteInfo.TargetFieldInfo.SetValue(pasteInfo.TargetMonoBehaviour, null);
207+
}
208+
else
209+
{
210+
pasteInfo.TargetFieldInfo.SetValue(pasteInfo.TargetMonoBehaviour, pastData);
211+
}
212+
}
213+
else if (pasteInfo.IsTypeList)
214+
{
215+
var list = pasteInfo.TargetFieldInfo.GetValue(pasteInfo.TargetMonoBehaviour) as IList;
216+
217+
if (pasteInfo.IsOverride) list.Clear(); //ペーストしたもので全て入れ替える場合
218+
foreach (var o in pasteInfo.CopySrcDatas)
219+
{
220+
list.Add(o);
221+
}
222+
}
223+
else
224+
{
225+
if (pasteInfo.IsOverride) //ペーストしたもので全て入れ替える場合
226+
{
227+
var converted = Array.CreateInstance(pasteInfo.ArrayElementType, pasteInfo.CopySrcDatas.Length);
228+
Array.Copy(pasteInfo.CopySrcDatas, 0, converted, 0, pasteInfo.CopySrcDatas.Length);
229+
pasteInfo.TargetFieldInfo.SetValue(pasteInfo.TargetMonoBehaviour, converted);
230+
}
231+
else //元データを維持して、追加する場合
232+
{
233+
var array = pasteInfo.TargetFieldInfo.GetValue(pasteInfo.TargetMonoBehaviour) as Array;
234+
var converted = Array.CreateInstance(pasteInfo.ArrayElementType, pasteInfo.CopySrcDatas.Length + array.Length);
235+
Array.Copy(array, 0, converted, 0, array.Length);
236+
Array.Copy(pasteInfo.CopySrcDatas, 0, converted, array.Length, pasteInfo.CopySrcDatas.Length);
237+
pasteInfo.TargetFieldInfo.SetValue(pasteInfo.TargetMonoBehaviour, converted);
238+
}
239+
}
240+
EditorUtility.SetDirty(pasteInfo.TargetMonoBehaviour);
241+
pasteInfo.TargetMonoBehaviour.SendMessage("OnValidate");//TODO mmmmmmmmmmmmmm これをやらないとEditor上で画像などが反映されないのツライ
242+
}
243+
244+
245+
private static bool Validate(bool isShowAlert = true)
246+
{
247+
if (_data == null || !_data.Any()) //C# 6.0 → if(data?.Any() != true)return;
248+
{
249+
if (isShowAlert) UnityEditor.EditorUtility.DisplayDialog("Notice", "なにもコピーされていないようです", "OK");
250+
return false;
251+
}
252+
253+
if (Selection.gameObjects.Length >= 2)
254+
{
255+
if (isShowAlert) UnityEditor.EditorUtility.DisplayDialog("Notice", "複数GameObjectへの同時ペーストは出来ません", "OK");
256+
return false;
257+
}
258+
259+
if (Selection.gameObjects.Any() == false)
260+
{
261+
if (isShowAlert) UnityEditor.EditorUtility.DisplayDialog("Notice", "GameObjectが選択されていません", "OK");
262+
return false;
263+
}
264+
265+
return true;
266+
}
267+
}
268+
}

Assets/IntelligentCopyAndPaste/Editor/ArrayCopyPasteComponent.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)