private static void CopyProcess(ArrayCopyAndPasteInfo pasteInfo) { //Undoへ登録 Undo.RecordObject(pasteInfo.TargetMonoBehaviour, "IntelligentCopyAndPaste - Paste"); if (pasteInfo.IsSingle) { //一つしかないので、IsOverride関係ない var pastData = pasteInfo.CopySrcDatas.FirstOrDefault(); if (pastData == null) { pasteInfo.TargetFieldInfo.SetValue(pasteInfo.TargetMonoBehaviour, null); } else { pasteInfo.TargetFieldInfo.SetValue(pasteInfo.TargetMonoBehaviour, pastData); } } else if (pasteInfo.IsTypeList) { var list = pasteInfo.TargetFieldInfo.GetValue(pasteInfo.TargetMonoBehaviour) as IList; if (pasteInfo.IsOverride) { list.Clear(); //ペーストしたもので全て入れ替える場合 } foreach (var o in pasteInfo.CopySrcDatas) { list.Add(o); } } else { if (pasteInfo.IsOverride) //ペーストしたもので全て入れ替える場合 { var converted = Array.CreateInstance(pasteInfo.ArrayElementType, pasteInfo.CopySrcDatas.Length); Array.Copy(pasteInfo.CopySrcDatas, 0, converted, 0, pasteInfo.CopySrcDatas.Length); pasteInfo.TargetFieldInfo.SetValue(pasteInfo.TargetMonoBehaviour, converted); } else //元データを維持して、追加する場合 { var array = pasteInfo.TargetFieldInfo.GetValue(pasteInfo.TargetMonoBehaviour) as Array; var converted = Array.CreateInstance(pasteInfo.ArrayElementType, pasteInfo.CopySrcDatas.Length + array.Length); Array.Copy(array, 0, converted, 0, array.Length); Array.Copy(pasteInfo.CopySrcDatas, 0, converted, array.Length, pasteInfo.CopySrcDatas.Length); pasteInfo.TargetFieldInfo.SetValue(pasteInfo.TargetMonoBehaviour, converted); } } EditorUtility.SetDirty(pasteInfo.TargetMonoBehaviour); pasteInfo.TargetMonoBehaviour.SendMessage("OnValidate");//TODO mmmmmmmmmmmmmm これをやらないとEditor上で画像などが反映されないのツライ }
private static void ArrayCopyAndPaste(bool isOverride, params MonoBehaviour[] monoBehaviours) { var arrayCopyAndPasteInfos = new System.Collections.Generic.List <ArrayCopyAndPasteInfo>(); foreach (var mono in monoBehaviours) { var type = mono.GetType(); var allFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.Instance); foreach (var info in allFields) { //PrivateFieldはSerializeFieldAttributeが指定されてないものは対象にできない if (info.IsPrivate && info.GetCustomAttributes(typeof(SerializeField), false).Any() == false) { continue; } //複数の場合があるので、どの配列に対して、どのインデックスから(追加か、上書きか)張り付けるかを判断するためのwindowを表示する var pasteInfo = new ArrayCopyAndPasteInfo { IsOverride = isOverride, TargetMonoBehaviour = mono, TargetFieldInfo = info, }; //配列かListか単品か判断 var arrayType = info.FieldType; if (arrayType.IsGenericType && arrayType.GetGenericTypeDefinition() == typeof(System.Collections.Generic.List <>)) { pasteInfo.IsTypeList = true; } else if (arrayType.IsArray) { pasteInfo.IsTypeList = false; } else { pasteInfo.IsSingle = true; } //配列(またはList)の要素のType if (pasteInfo.IsSingle) { pasteInfo.ArrayElementType = info.FieldType; } else { pasteInfo.ArrayElementType = pasteInfo.IsTypeList ? arrayType.GetGenericArguments().FirstOrDefault() : arrayType.GetElementType(); } if (pasteInfo.ArrayElementType == null) { continue; } //対象がこのMonoBehaviourのこのFieldだった場合のコピー元から張り付ける事ができる要素をまとめる pasteInfo.CopySrcDatas = _data.Select(o => { if (o.GetType() == pasteInfo.ArrayElementType) { return(o); } Debug.Log(pasteInfo.ArrayElementType.Name); if (pasteInfo.ArrayElementType.IsSubclassOf(typeof(Component))) { var attachedComponent = (o as GameObject)?.GetComponent(pasteInfo.ArrayElementType); if (attachedComponent?.GetType() == pasteInfo.ArrayElementType) { return(attachedComponent); } } return(AssetDatabase.LoadAssetAtPath(AssetDatabase.GetAssetPath(o), pasteInfo.ArrayElementType));//TODO Spriteそのものの場合と、Spriteを持っているTextureの場合がある }).Where(o => o != null).ToArray(); if (pasteInfo.CopySrcDatas.Any() == false) { continue; //コピー元が張り付ける先が無かった } if (pasteInfo.IsTypeList) { var originalData = pasteInfo.TargetFieldInfo.GetValue(pasteInfo.TargetMonoBehaviour) as IList; pasteInfo.OriginalDatas = new Object[originalData.Count]; originalData.CopyTo(pasteInfo.OriginalDatas, 0); } else if (pasteInfo.IsSingle) { var originalData = pasteInfo.TargetFieldInfo.GetValue(pasteInfo.TargetMonoBehaviour) as Object; pasteInfo.OriginalDatas = new [] { originalData }; } else { var originalData = pasteInfo.TargetFieldInfo.GetValue(pasteInfo.TargetMonoBehaviour) as Array; pasteInfo.OriginalDatas = originalData as Object[]; } pasteInfo.DisplayName = pasteInfo.TargetFieldInfo.DeclaringType.FullName + Environment.NewLine; if (pasteInfo.IsSingle) { pasteInfo.DisplayName += pasteInfo.ArrayElementType.Name; } else if (pasteInfo.IsTypeList) { pasteInfo.DisplayName += "List<" + pasteInfo.ArrayElementType.Name + "> "; } else { pasteInfo.DisplayName += pasteInfo.ArrayElementType.Name + "[] "; } pasteInfo.DisplayName += pasteInfo.TargetFieldInfo.Name; arrayCopyAndPasteInfos.Add(pasteInfo); } } //TODO 対象が1つしか無かった場合にWindowを出すべきかどうか悩むところ if (arrayCopyAndPasteInfos.Any()) { var message = arrayCopyAndPasteInfos.Count == 1 ? "以下のFieldが候補にあがりました。よろしいですか?" : "複数のFieldが候補にあがりました。どちらのFieldにペーストしますか?"; CopyAndPasteChoiceWindow.Open(message, arrayCopyAndPasteInfos, pasteInfo => { if (pasteInfo != null) { CopyProcess(pasteInfo); } }); } }