[Unity]自动将断链的Prefab替换为真Prefab

2019/10 23 20:10

环境:Unity2018.4

起因:美术在Runtime环境,拉出的Prefab是实例化之后的(断链了)
现在要将原来的Perfab替换为真的Prefab(看起来是蓝色的)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public static class EditorPrefabToolV2
{
    static private readonly string[] CFindPaths = new string[]
    {
        "Assets/Arts/",
    };

    private static bool InFindPath(string assetPath)
    {
        foreach(var cfp in CFindPaths)
        {
            if (assetPath.StartsWith(cfp))
            {
                return true;
            }
        }
        return false;
    }

    private static string FindAsset(string assetName)
    {
        var allAssetPaths = AssetDatabase.GetAllAssetPaths();
        foreach(var assetPath in allAssetPaths)
        {
            if ( System.IO.Path.GetExtension(assetPath).ToLower() != ".prefab")
            {
                continue;
            }
            
            if (!InFindPath(assetPath))
            {
                continue;
            }

            string fname = System.IO.Path.GetFileNameWithoutExtension(assetPath).ToLower().Trim();
            if (fname == assetName)
            {
                return assetPath;
            }
        }

        return string.Empty;
    }

    private static GameObject ReplaceGo(GameObject sobj)
    {  
        var pos = sobj.transform.position;
        var rot = sobj.transform.rotation;
        var parentObj = sobj.transform.parent;
        if (parentObj == null)
        {
            return null;
        }

        var sindex = sobj.transform.GetSiblingIndex();
        var sname = sobj.name.Trim();
        for(int i=30; i>=0; i--)
        {
            sname = sname.Replace("(" + i.ToString() + ")", "");
        }
        sname = sname.ToLower().Trim();

        var findAssetPath = FindAsset(sname);
        if (string.IsNullOrEmpty(findAssetPath))
        {
            Log.Warning("没有找到匹配的资源:{0}", sname);
            return null;
        }

        var prefabTemplate = AssetDatabase.LoadAssetAtPath<GameObject>(findAssetPath);
        if (prefabTemplate == null)
        {
            Log.Warning("载入失败1:{0}", findAssetPath);
            return null;
        }

        var newObj = PrefabUtility.InstantiatePrefab(prefabTemplate) as GameObject;
        if (newObj == null)
        {
            Log.Warning("载入失败2:{0}", findAssetPath);
            return null;
        }

        newObj.transform.SetParent(parentObj, false);
        newObj.transform.position = pos;
        newObj.transform.rotation = rot;
        newObj.transform.SetSiblingIndex(sindex);

        Undo.RegisterCreatedObjectUndo(newObj, "created rig");

        Log.Logic("<color=blue>替换成功: {0} -> {1}</color>", sname, findAssetPath);
        return newObj;
    }


    [MenuItem("GameObject/UwMapEditor/替换为Prefab %#V")]
    static public void ReplacePrefab()
    {
        var sobj = Selection.gameObjects;
        if ( sobj == null || sobj.Length == 0)
        {
            return;
        }

        List<GameObject> delObjs = new List<GameObject>();
        List<GameObject> addObjs = new List<GameObject>();
        for(int i=0; i<sobj.Length; ++i)
        {
            var addObj = ReplaceGo(sobj[i]);
            if (addObj != null)
            {
                addObjs.Add(addObj);
                delObjs.Add(sobj[i]);
            }
        }

        foreach(var obj in delObjs)
        {
            Undo.DestroyObjectImmediate(obj);
        }

        Selection.objects = addObjs.ToArray();

        foreach(var obj in addObjs)
        {
            UnityEditor.EditorUtility.SetDirty(obj);
        }
    }
}