CardResourceArtToolEditor.md 53 KB

#unity/白日梦/代码缓存

using System;
using System.Collections.Generic;
using System.IO;
using JetBrains.Annotations;
using ResourcesModule.LMNA;
using UnityEditor;
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities;
using Sirenix.Utilities.Editor;
using UnityEngine;
using UnityEngine.UIElements;
using Object = UnityEngine.Object;

namespace MThread.Common.ToolsModule.CardResourceArtImportToolModule
{


    /// <summary>
    /// 导入的文件路径相关
    /// </summary>
    public class FilePath
    {
        public List<string> MainPrefabPath;
        public List<string> OtherPrefabPaths;
        public List<string> OtherAnimPaths;
        public string jsonPath;
    }
    

    /// <summary>
    /// 道具卡配置类
    /// </summary>
    public class CardConfig
    {
        public string OriginIndex;
        public string TargetIndex;
        public string CardName;
        public Dictionary<string, string> OldAndNewNameDic;
    }

    public class CardType
    {
        public string CardName; //所属道具卡名字
        public string CardNumber; //所属道具卡编号
        public string InOut; //所属道具卡局内外
        public string OriginalName; //道具卡原名
        public bool IsSkin; //是否是皮肤fbx
    }
    
    public class CardResourceArtToolEditor : OdinMenuEditorWindow
    {
        
        #region 逻辑常量

        private const string m_FbxDirIng = "Assets/ResourcesRaw/CommonRegion/InGame/Skins/Cards/";
        private const string m_PrefabDirIng = "Assets/BundleResources/CommonRegion/InGame/Skins/Cards/";
        private const string m_JsonDirIng = "Assets/BundleResources/CommonRegion/InGame/CardJson/";

        private const string m_FbxDirOut = "Assets/ResourcesRaw/CommonRegion/OutsideGame/Skins/Cards/";
        private const string m_PrefabDirOut = "Assets/BundleResources/CommonRegion/OutsideGame/Skins/Cards/";

        #endregion

        #region 逻辑变量

        private static List<string> InGameCardList = new List<string>(); //局内道具卡列表
        private CardType currentCardType = new CardType(); //当前处理的道具卡数据类型
        
        
        private FileInfo m_FbxFile; //FBX文件信息
        private string numberResult = ""; //新编号 文本
        private int currentNumberResult = 0; //新编号 数字
        private string cardName = ""; //道具卡名字
        private string FbxCardPath = ""; //道具卡路径(fbx)
        private string AnimCardPath = ""; //道具卡路径(动画)
        private string PrefabCardPath = ""; //道具卡路径(prefab)
        private string IndexFullName = ""; //旧道具卡编号 全名
        private string OldCardPrefabDirectory = ""; //旧道具卡 文件目录
        private string NewCardPrefabDirectory = ""; //新道具卡 文件目录
        private string NewPrefabPath = ""; //新prefab路径
        
        private Dictionary<string, string> WriteJsonDic; //写入Json文件列表
        public List<GameObject> tempGameObejct; //临时变量
        
        #endregion
        
        

        #region 道具卡合入界面
        
        private static CardResourceArtToolEditor _CardResourceArtToolEditorUI;

        public static CardResourceArtToolEditor GetCardResourceArtToolEditor
        {
            get
            {
                return _CardResourceArtToolEditorUI;
            }
        }
        
        
        [MenuItem("GameObject/美术道具卡合入")]
        private static void OpenWindow()
        {
             _CardResourceArtToolEditorUI = GetWindow<CardResourceArtToolEditor>();
             _CardResourceArtToolEditorUI.position = GUIHelper.GetEditorWindowRect().AlignCenter(1000, 600);

             InitData();
        }
        

        #endregion

        
        #region 道具卡功能逻辑

        /// <summary>
        /// 判断节点是否为fbx模型 (之前没绑定的前提下)
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        private bool JudgeFBX(string name)
        {
            
            string cardNumber = System.Text.RegularExpressions.Regex.Replace(name, @"[^0-9]+", "");
            if (cardNumber == String.Empty)
            {
                return false;
            }

            string lowerName = name.ToLower();
            
            if (!(lowerName.Contains("ing") || lowerName.Contains("low") || lowerName.Contains("lob") || lowerName.Contains("height")))
            {
                return false;
            }

            if (!lowerName.Contains("skin"))
            {
                return false;
            }
            
            
            
            return true;
        }



        /// <summary>
        /// 通过道具卡名字获得道具卡类型
        /// </summary>
        /// <param name="cardType"></param>
        /// <param name="cardName"></param>
        private string[] GetCardType(ref CardType cardType,string cardName)
        {
            cardType.CardName = null;
            cardType.CardNumber = null;
            cardType.InOut = null;
            cardType.OriginalName = null;
            
            string[] nameList = cardName.Split('_');

            string cardNumber = System.Text.RegularExpressions.Regex.Replace(cardName, @"[^0-9]+", "");
            if (cardNumber != String.Empty)
            {
                cardType.CardNumber = cardNumber;
            }
            
            for (int i = 0; i < nameList.Length; i++)
            {
                if (InGameCardList.Contains(nameList[i]))
                {
                    cardType.CardName = nameList[i];
                    break;
                }
            }


            string lowerName = cardName.ToLower(); //名字小写处理
            if (lowerName.Contains("ing") || lowerName.Contains("low"))
            {
                cardType.InOut = "ing";
            }
            else if (lowerName.Contains("lob") || lowerName.Contains("height"))
            {
                cardType.InOut = "lob";
            }

            cardType.IsSkin = lowerName.Contains("skin");
            cardType.OriginalName = cardName;

            return nameList;
        }

        /// <summary>
        /// 根据道具卡类型和物品属性 获得对应的道具卡名字
        /// </summary>
        /// <param name="cardType"></param>
        /// <param name="eAssetFunctionType"></param>
        /// <returns></returns>
        private string GetCardNameByCardType(CardType cardType, eAssetFunctionType eAssetFunctionType)
        {
            string cardName = String.Empty;

            if (CheckCardTypeNotNull(cardType))
            {
                switch (eAssetFunctionType)
                {
                    case eAssetFunctionType.Model:
                        if (cardType.IsSkin)
                        {
                            cardName = LMNAResMapUtil.AssembleAssetName(cardType.InOut+cardType.CardNumber+"_"+cardType.CardName+"_skin.FBX", eAssetFunctionType, eAssetLodLevel.None);
                        }
                        else
                        {
                            cardName = cardType.OriginalName;
                        }
                        break;
                }
            }


            return cardName;
        }

        /// <summary>
        /// 如果参照物是有OverController的 新物体也创建一个OverControlller
        /// </summary>
        /// <param name="trans"></param>
        /// <param name="checkResource"></param>
        /// <returns></returns>
        private string CreateOverController(Transform trans,bool checkResource)
        {
            string newOverControllerPath = String.Empty;

            if (!checkResource)
            {
                Animator originalAnimator = trans.GetComponent<Animator>();
                if (originalAnimator != null)
                {
                    AnimatorOverrideController overrideController = originalAnimator.runtimeAnimatorController as AnimatorOverrideController;
                    string rootPath = AssetDatabase.GetAssetPath(overrideController);
                    if (numberResult != IndexFullName && rootPath.Contains(IndexFullName)) //判断是前后不同编号的道具卡
                    {
                        newOverControllerPath = rootPath.Replace(IndexFullName, numberResult);
                        string filePathOnly = Path.GetDirectoryName(newOverControllerPath);  //获得文件夹路径
                        if (!Directory.Exists(filePathOnly))
                        {
                            Directory.CreateDirectory(filePathOnly);
                        }
                        
                        
                        AnimatorOverrideController newOverrideController = new AnimatorOverrideController();
                        EditorUtility.CopySerialized(overrideController, newOverrideController);

                        AssetDatabase.CreateAsset(newOverrideController, newOverControllerPath);
                        AssetDatabase.Refresh();
                    }
                    else if (numberResult == IndexFullName && rootPath.Contains(IndexFullName)) //如果是同一编号的道具卡,说明是第二次创建,直接拿到资源路径就好
                    {
                        overrideController = originalAnimator.runtimeAnimatorController as AnimatorOverrideController;
                        newOverControllerPath = AssetDatabase.GetAssetPath(overrideController);
                    }
                }
            }
            

            return newOverControllerPath;
        }

        /// <summary>
        /// 检测是否存在动画(导入)
        /// </summary>
        /// <param name="fbxPath"></param>
        /// <param name="filePath"></param>
        /// <param name="checkResource"></param>
        /// <param name="fbxName"></param>
        private void CheckPushAnim(ref string fbxPath,ref FilePath filePath,bool checkResource,string fbxName)
        {

            string targetPath = String.Empty;
            Object[] fbxSubAssets = AssetDatabase.LoadAllAssetRepresentationsAtPath(fbxPath);
            if (fbxSubAssets.Length <= 0) //说明路径不对,需要修正路径到Animations路径
            {
                targetPath = AnimCardPath + fbxName;
                fbxSubAssets = AssetDatabase.LoadAllAssetRepresentationsAtPath(targetPath);
            }
            foreach (Object subAsset in fbxSubAssets)
            {
                if (typeof(AnimationClip) == subAsset?.GetType())
                {
                    targetPath = AnimCardPath + fbxName;
                    string[] splitAssetName = fbxName.Split(LMNAResMapUtil.ASSET_FULL_NAME_SPLITTER_ARRAY, StringSplitOptions.RemoveEmptyEntries);
                    if (splitAssetName.Length != 2)
                    {
                        return;
                    }
                    string logigPart = splitAssetName[1]; //逻辑名
                    string AnimName = LMNAResMapUtil.AssembleAssetName(logigPart.Replace(".FBX",".anim"),
                        eAssetFunctionType.AnimationClip, eAssetLodLevel.None);
                    
                    
                    if (!checkResource)
                    {
                        
                        //移动对应的fbx文件
                        if (File.Exists(targetPath))
                        {
                            File.Delete(targetPath);
                        }
                        AssetDatabase.MoveAsset(fbxPath, targetPath);
                        AssetDatabase.Refresh();
                        
                        //基于fbx文件创建Anim动画文件
                        AnimationClip originalAnimationClip = subAsset as AnimationClip;
                        AnimationClip targetAnimationClip = new AnimationClip();

                        EditorUtility.CopySerialized(originalAnimationClip, targetAnimationClip);
                        AssetDatabase.CreateAsset(targetAnimationClip,AnimCardPath+AnimName);
                        AssetDatabase.Refresh();

                    }


                    filePath.OtherAnimPaths.Add(AnimCardPath + AnimName);

                    fbxPath = targetPath;
                    
                    break;
                }
            }
            

        }
        

        private bool CheckCardTypeNotNull(CardType cardType)
        {
            return cardType != null && cardType.CardName != null && cardType.CardNumber != null &&
                   cardType.InOut != null;
        }

        
        private bool CompareCardType(CardType source, CardType target)
        {
            if (CheckCardTypeNotNull(source) && CheckCardTypeNotNull(target))
            {
                return source.CardName == target.CardName && source.CardNumber == target.CardNumber &&
                       source.InOut == target.InOut;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 初始化数据
        /// </summary>
        private static void InitData()
        {
            
            InGameCardList.Clear();
            
            string[] InGameCards = Directory.GetDirectories(m_PrefabDirIng, "*.*", SearchOption.TopDirectoryOnly);
            for (int i = 0; i < InGameCards.Length; i++)
            {
                string filePathOnly = Path.GetFileName(InGameCards[i]);  
                InGameCardList.Add(filePathOnly);
            }
        }

        
        RightTabEditor GetCardData()
        {
            RightTabEditor RightTabEditorData = new RightTabEditor();
            string defaultFolder = PlayerPrefs.GetString("CardFilesDefalutFolder", "");
            string folder = EditorUtility.OpenFolderPanel("Select Versions Folder", defaultFolder, "");
            if (string.IsNullOrEmpty(folder))
            {
                return RightTabEditorData;
            }
            
            PlayerPrefs.SetString("CardFilesDefalutFolder", folder);
            DirectoryInfo direction = new DirectoryInfo(folder);
            
            FileInfo[] fbxFiles = direction.GetFiles("*.fbx", SearchOption.AllDirectories);
            if (fbxFiles.Length == 0)
            {
                // NamingChecker.PopupErrorMessage("未检测到有fbx导入!");
                return RightTabEditorData;
            }
            RightTabEditorData.m_FbxFiles = fbxFiles;
            return RightTabEditorData;
        }

        /// <summary>
        /// 导入资源 检测资源是否已有
        /// </summary>
        /// <param name="fbxFiles"></param>
        /// <param name="checkResource"></param>
        /// <returns></returns>
        public FilePath OnClickLoadButton(FileInfo[] fbxFiles,bool checkResource = false)
        {
            
            tempGameObejct = new List<GameObject>();
            
            FilePath filePaths = new FilePath();
            List<string> PrefabList = new List<string>(); //已处理预制体名称

            for (int i = 0; i < fbxFiles.Length; i++)
            {

                if (filePaths.OtherPrefabPaths == null)
                {
                    filePaths.OtherPrefabPaths = new List<string>();
                }

                if (filePaths.OtherAnimPaths == null)
                {
                    filePaths.OtherAnimPaths = new List<string>();
                }
                
                
                
                m_FbxFile = fbxFiles[i];// 当前fbx文件
                string[] nameList = GetCardType(ref currentCardType, m_FbxFile.Name);
                
                WriteJsonDic = new Dictionary<string, string>();
                // treeData.Add(fbxFiles[i].Name);
                
                if (nameList.Length <= 1)
                {
                    // EditorUtility.DisplayDialog("小提醒", $"{m_FbxFile.Name}模型文件命名不对哇,请确认一下", "好哒");
                    continue;
                }

                if (CheckCardTypeNotNull(currentCardType))
                {
                    numberResult = currentCardType.CardNumber;
                    cardName = currentCardType.CardName;


                    if (currentCardType.InOut == "lob")
                    {
                        FbxCardPath = m_FbxDirOut + cardName +  "/" + numberResult + "/Models/";
                        AnimCardPath = m_FbxDirOut + cardName +  "/" + numberResult + "/Animations/";
                        PrefabCardPath = m_PrefabDirOut + cardName  + "/";
                    }
                    else if (currentCardType.InOut == "ing")
                    {
                        FbxCardPath = m_FbxDirIng + cardName +  "/" + numberResult + "/Models/";
                        AnimCardPath = m_FbxDirIng + cardName +  "/" + numberResult + "/Animations/";
                        PrefabCardPath = m_PrefabDirIng + cardName  + "/";
                    }
                    
                    
                    string fbxName = GetCardNameByCardType(currentCardType, eAssetFunctionType.Model);

                    string fbxPath = LoadFbxFile(fbxName,checkResource);

                    CheckPushAnim(ref fbxPath, ref filePaths, checkResource, fbxName);

                    if (fbxPath != String.Empty)
                    {
                        filePaths.OtherPrefabPaths.Add(fbxPath);
                        if (currentCardType.IsSkin)
                        {
                            filePaths = CheckCardResourceNameAndCreatePrefab(m_FbxFile.Name, fbxPath, PrefabList, filePaths,checkResource);
                        }
                        else
                        {
                            // filePaths.
                        }
                    }
                }


                
            }

            if (!checkResource)
            {
                foreach (KeyValuePair<string,string> keyValuePair in WriteJsonDic)
                {
                    File.WriteAllText(keyValuePair.Key, keyValuePair.Value);
                }
                
                AssetDatabase.Refresh();
                WriteJsonDic.Clear();
                
            }

            for (int i = 0; i < tempGameObejct.Count; i++)
            {
                DestroyImmediate(tempGameObejct[i]);
            }
            
            tempGameObejct.Clear();

            return filePaths;
        }


        /// <summary>
        /// 检测道具卡名字是否合法,生成对应的prefab文件
        /// </summary>
        /// <param name="PrefabList"></param>
        public FilePath CheckCardResourceNameAndCreatePrefab(string name,string fbxPath,List<string> PrefabList,FilePath filePaths,bool checkResource = false)
        // public void CheckCardResourceNameAndCreatePrefab(RightTabEditor rightTabEditor)
        {
            
            if (fbxPath == String.Empty)
            {
                return filePaths;
            }
            
            if (!Directory.Exists(PrefabCardPath))
            {
                return filePaths;
            }

            if (!int.TryParse(numberResult,out currentNumberResult))
            {
                return filePaths;
            }

            
            int FileIndex = 0;
            DirectoryInfo source = new DirectoryInfo(PrefabCardPath);
            List<int> IndexList = new List<int>();
            foreach (DirectoryInfo directoryInfo in source.GetDirectories())
            {
               
                if (int.TryParse(directoryInfo.Name,out FileIndex))
                {

                    if (currentNumberResult != FileIndex) //把当前需要处理的编号排除在外
                    { 
                        IndexList.Add(FileIndex);
                    }
                    else
                    {
                        if (directoryInfo.GetFiles().Length + directoryInfo.GetDirectories().Length > 0) //如果目录内文件非空,说明是重新导入同名fbx文件
                        {
                            IndexList.Clear();
                            IndexList.Add(FileIndex);
                            break;
                        }
                    }
                }
            }


            if (IndexList.Count > 0)
            {
                IndexList.Sort();
                
                IndexFullName = IndexList[IndexList.Count - 1].ToString().PadLeft(8, '0');
                OldCardPrefabDirectory = PrefabCardPath + IndexFullName + "/";


                string[] guids = AssetDatabase.FindAssets("t:Prefab", new string[] {OldCardPrefabDirectory});

                CardConfig cardConfig = new CardConfig();
                cardConfig.OriginIndex = IndexFullName;
                cardConfig.TargetIndex = numberResult;
                cardConfig.CardName = cardName;
                cardConfig.OldAndNewNameDic = new Dictionary<string, string>();
                
                NewCardPrefabDirectory = PrefabCardPath + numberResult + "/";

                bool isFbx = false;

                Dictionary<string,List<eAssetLodLevel>> otherEffectDic = new Dictionary<string, List<eAssetLodLevel>>();
                
                for (int i = 0; i < guids.Length; i++)
                {

                    string AssetName = AssetDatabase.GUIDToAssetPath(guids[i]);
                    if (!PrefabList.Contains(AssetName))
                    {
                        GameObject MyCardPrefab =
                            AssetDatabase.LoadAssetAtPath(AssetName, typeof(GameObject)) as GameObject;
                        Transform[] MyCardPrefabList = MyCardPrefab.GetComponentsInChildren<Transform>();
                        bool isPrefabFromFbx = false;
                        for (int j = 0; j < MyCardPrefabList.Length; j++)
                        {

                            isFbx = JudgeFBX(MyCardPrefabList[j].name);
                            
                            if (PrefabUtility.IsPartOfPrefabInstance(MyCardPrefabList[j].gameObject) || isFbx)
                            {
                                if (isFbx && PrefabUtility.IsPartOfPrefabInstance(MyCardPrefabList[j].gameObject))
                                {
                                    Object rootPrefab = PrefabUtility.GetCorrespondingObjectFromOriginalSource(MyCardPrefabList[j].gameObject);
                                    string AssetPath = AssetDatabase.GetAssetPath(rootPrefab);
                                    string Filetype = Path.GetExtension(AssetPath);

                                    if (Filetype.ToLower() != ".fbx") //如果是fbx文件,才会走到下面的逻辑
                                    {
                                        continue;
                                    }
                                }
                                
                                
                                
                                string fbxNumber = System.Text.RegularExpressions.Regex.Replace(MyCardPrefabList[j].name, @"[^0-9]+", "");
                                // string newAssetPath = AssetPath.Replace(fbxNumber, numberResult);
                                
                                CardType newCardType = new CardType();
                                GetCardType(ref newCardType, MyCardPrefabList[j].name.Replace(fbxNumber, numberResult));
                                
                                if (!CompareCardType(currentCardType,newCardType))
                                {
                                    continue;
                                    // isPrefabFromFbx = true;
                                    // break;
                                }
                                
                                NewPrefabPath = PrefabCardPath + numberResult + "/";
                                if (!Directory.Exists(NewPrefabPath))
                                {
                                    Directory.CreateDirectory(NewPrefabPath);
                                }
                                
                                GameObject prefabInst = Instantiate(MyCardPrefab);
                                tempGameObejct.Add(prefabInst);

                                Transform[] prefabTransList = prefabInst.GetComponentsInChildren<Transform>();
                                List<GameObject> needDeleteGameObjects = new List<GameObject>();
                                for (int l = 0; l < prefabTransList.Length; l++)
                                {
                                    if (prefabTransList[l].name == MyCardPrefabList[j].name)
                                    {
                                        
                                        GameObject ret = AssetDatabase.LoadAssetAtPath(fbxPath, typeof(GameObject)) as GameObject;
                                        GameObject clone = PrefabUtility.InstantiatePrefab(ret) as GameObject;
                                        if (clone != null)
                                        {
                                            string newOverControllerPath =
                                                CreateOverController(prefabTransList[l], checkResource);

                                            if (newOverControllerPath != string.Empty)
                                            {
                                                if (clone.GetComponent<Animator>() == null)
                                                {
                                                    clone.AddComponent<Animator>();
                                                }

                                                Animator newAnimator = clone.GetComponent<Animator>();
                                                newAnimator.runtimeAnimatorController =
                                                    AssetDatabase.LoadAssetAtPath<AnimatorOverrideController>(
                                                        newOverControllerPath);
                                            }
                                            
                                            clone.transform.parent = prefabTransList[l].parent;
                                            needDeleteGameObjects.Add(prefabTransList[l].gameObject);
                                        }
                                        break;
                                    }
                                }


                                string NewprefabName = MyCardPrefab.name.Replace(IndexFullName, numberResult);
                                
                                string OldLogicName = MyCardPrefab.name.Split('&')[1];
                                string NewLogicName = NewprefabName.Split('&')[1];

                                AudioSource[] audioSources = prefabInst.GetComponentsInChildren<AudioSource>();
                                for (int m = 0; m < audioSources.Length; m++)
                                {
                                    string num = System.Text.RegularExpressions.Regex.Replace(audioSources[m].clip.name, @"[^0-9]+", "");
                                    if (num.Length > 0)
                                    {
                                        // EditorUtility.DisplayDialog("小提醒", $"{NewprefabName}音频不是用了通用资源,请确认一下", "好哒");
                                    }
                                }

                                needDeleteGameObjects.ForEach(child => DestroyImmediate(child));

                                if (filePaths.MainPrefabPath == null)
                                {
                                    filePaths.MainPrefabPath = new List<string>();
                                }

                                filePaths.MainPrefabPath.Add(NewPrefabPath + NewprefabName + ".prefab");

                                if (!checkResource)
                                {
                                    
                                    RecoverMatrials(MyCardPrefab.transform, prefabInst.transform);
                                    PrefabUtility.SaveAsPrefabAsset(prefabInst, NewPrefabPath + NewprefabName + ".prefab");
                                    AssetDatabase.SaveAssets();
                                    DestroyImmediate(prefabInst.gameObject);
                                    AssetDatabase.Refresh();
                                }

                                if (!cardConfig.OldAndNewNameDic.ContainsKey(OldLogicName))
                                {
                                    cardConfig.OldAndNewNameDic.Add(OldLogicName, NewLogicName);
                                }
                                
                                PrefabList.Add(MyCardPrefab.name);

                                isPrefabFromFbx = true;
                                break;
                            }
                        }


                        if (isPrefabFromFbx == false)
                        {
                            CollectOtherPrefab(otherEffectDic, Path.GetFileName(AssetName));
                            PrefabList.Add(AssetName);
                        }

                    }
                 
                }


                foreach (KeyValuePair<string,List<eAssetLodLevel>> pair in otherEffectDic)
                {
                    eAssetLodLevel lodLv = eAssetLodLevel.None;
                    if (pair.Value.Count > 0)
                    {
                        pair.Value.Sort();
                        for (int i = 0; i < pair.Value.Count; i++)
                        {
                            lodLv = pair.Value[0];
                            break;
                        }
                    }
                    
                    string oneOtherName =
                        LMNAResMapUtil.AssembleAssetName(pair.Key, eAssetFunctionType.GameObject, lodLv);
                    if (oneOtherName.Contains(IndexFullName))
                    {
                        // Debug.Log("path:" + OldCardPrefabDirectory + oneOtherName);
                        GameObject OldEffectPrefab =
                            AssetDatabase.LoadAssetAtPath(OldCardPrefabDirectory + oneOtherName, typeof(GameObject)) as GameObject;


                        string newOtherName = oneOtherName.Replace(IndexFullName, numberResult);
                        GameObject OldEffectPrefabInst = Instantiate(OldEffectPrefab);
                        tempGameObejct.Add(OldEffectPrefabInst);


                        filePaths = CollectionOtherEffectPrefab(OldCardPrefabDirectory + oneOtherName, IndexFullName,
                            numberResult,
                            OldEffectPrefabInst, filePaths,checkResource);

                        string newPrefabLogicName = pair.Key.Replace(IndexFullName, numberResult);

                        
                        if (!Directory.Exists(NewCardPrefabDirectory))
                        {
                            Directory.CreateDirectory(NewCardPrefabDirectory);
                        }
                        
                        AudioSource[] audioSources = OldEffectPrefabInst.GetComponentsInChildren<AudioSource>();
                        for (int j = 0; j < audioSources.Length; j++)
                        {
                            string num = System.Text.RegularExpressions.Regex.Replace(audioSources[j].clip.name, @"[^0-9]+", "");
                            if (num.Length > 0)
                            {
                                // EditorUtility.DisplayDialog("小提醒", $"{newPrefabLogicName}音频不是用了通用资源,请确认一下", "好哒");
                            }
                        }


                        filePaths.OtherPrefabPaths.Add(NewCardPrefabDirectory + newOtherName);

                        if (!checkResource)
                        {
                            PrefabUtility.SaveAsPrefabAsset(OldEffectPrefabInst, NewCardPrefabDirectory + newOtherName);
                            AssetDatabase.SaveAssets();
                            DestroyImmediate(OldEffectPrefabInst.gameObject);
                            AssetDatabase.Refresh();
                        }
                        

                        if (!cardConfig.OldAndNewNameDic.ContainsKey(pair.Key))
                        {
                            cardConfig.OldAndNewNameDic.Add(pair.Key,newPrefabLogicName);
                        }
                    }

                }
                
                CreateJsonFile(cardConfig,WriteJsonDic,ref filePaths);
            }

            return filePaths;
        }

        /// <summary>
        /// 把fbx文件复制到工程
        /// </summary>
        /// <returns></returns>
        string LoadFbxFile(string fbxName,bool checkResource = false)
        {
            string m_FbxPath = String.Empty;
            
            //fbx路径创建
            if (!Directory.Exists(FbxCardPath))
            {
                Directory.CreateDirectory(FbxCardPath);
            }
            
            //动画路径创建
            if (!Directory.Exists(AnimCardPath))
            {
                Directory.CreateDirectory(AnimCardPath);
            }
            

            if (fbxName == String.Empty)
            {
                return m_FbxPath;
            }

            m_FbxPath = FbxCardPath + fbxName;

            

            if (!checkResource)
            {
                if (File.Exists(m_FbxPath))
                {
                    File.Delete(m_FbxPath);
                }
                m_FbxFile.CopyTo(m_FbxPath);
                
                AssetDatabase.Refresh();
            }
            
            
            return m_FbxPath;
        }
        

        
        /// <summary>
        /// 基于源Json配置文件创建适配新prefab的Json配置文件
        /// </summary>
        /// <param name="OriginIndex"></param>
        /// <param name="TargetIndex"></param>
        /// <param name="cardName"></param>
        void CreateJsonFile(CardConfig cardConfig,Dictionary<string,string> WriteJsonDic,ref FilePath filePath)
        {
            
            string OriginFileName =  LMNAResMapUtil.AssembleAssetName(cardConfig.CardName+cardConfig.OriginIndex+".json", eAssetFunctionType.VActionConfig, eAssetLodLevel.None);
            string OriginFilePath = m_JsonDirIng + OriginFileName;
            
            string TargetFileName = LMNAResMapUtil.AssembleAssetName(cardConfig.CardName + cardConfig.TargetIndex + ".json",
                eAssetFunctionType.VActionConfig, eAssetLodLevel.None);
            string TargetFilePath = m_JsonDirIng + TargetFileName;
            

            TextAsset textAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(OriginFilePath);
            if (textAsset == null) //如果json文件命名不规则,通过编号去找
            {
                string[] guids = AssetDatabase.FindAssets( cardConfig.OriginIndex, new string[] {m_JsonDirIng});
                if (guids.Length > 1)
                {
                    EditorUtility.DisplayDialog("小提醒", $"{cardConfig.OriginIndex}对应的json配置文件编号不规则,而且存在多个相同编号配置文件,导入失败,请找程序确认一下", "好哒");
                    return;
                }
                else
                {
                    if (guids.Length > 0)
                    {
                        string AssetName = AssetDatabase.GUIDToAssetPath(guids[0]); //适配json配置文件命名不规则情况
                        textAsset =
                            AssetDatabase.LoadAssetAtPath(AssetName, typeof(TextAsset)) as TextAsset;
                        TargetFilePath = AssetName.Replace(cardConfig.OriginIndex, numberResult);
                    }
                    else
                    {
                        EditorUtility.DisplayDialog("小提醒", $"{cardConfig.OriginIndex}对应的json配置文件不存在,导入失败,请找程序确认一下", "好哒");
                        return;
                    }
                }
            }
            
            string textString;
            if (!WriteJsonDic.ContainsKey(TargetFilePath))
            {
                textString = textAsset.text;
                WriteJsonDic.Add(TargetFilePath,textString);
            }
            else
            {
                textString = WriteJsonDic[TargetFilePath];
            }

            foreach (KeyValuePair<string,string> keyValuePair in cardConfig.OldAndNewNameDic)
            {
                textString = textString.Replace(Path.GetFileNameWithoutExtension(keyValuePair.Key),
                    Path.GetFileNameWithoutExtension(keyValuePair.Value));

            }

            filePath.jsonPath = TargetFilePath;
            WriteJsonDic[TargetFilePath] = textString;


        }

        
        /// <summary>
        /// 收集道具卡之外的 其他特效的命名
        /// </summary>
        /// <param name="FileName"></param>
        /// <returns></returns>
        void CollectOtherPrefab(Dictionary<string,List<eAssetLodLevel>> dic,string FileName)
        {
            string[] splitAssetName = FileName.Split(LMNAResMapUtil.ASSET_FULL_NAME_SPLITTER_ARRAY, StringSplitOptions.RemoveEmptyEntries);
            if (splitAssetName.Length != 2)
            {
                return;
            }
            eAssetLodLevel lodLv = eAssetLodLevel.None;
            
            string prefixPart = splitAssetName[0];
            string logigPart = splitAssetName[1];
            string prefixSegment =
                prefixPart.Replace(
                    prefixPart.Substring(0, Math.Min(LMNAResMapUtil.ASSET_NAME_PREFIX_SEGMENT_SIZE, prefixPart.Length)),
                    "");
            
            bool HasLevel = LMNAResMapUtil.StrToEAssetLodLevelType(prefixSegment, out lodLv); //是否存在等级
            if (!dic.ContainsKey(logigPart))
            {
                List<eAssetLodLevel> assetLevelList = new List<eAssetLodLevel>();
                dic.Add(logigPart, assetLevelList);
            }
            
            if (HasLevel)
            {
                dic[logigPart].Add(lodLv);
            }

        }

        /// <summary>
        /// 根据预制体路径,收集子物体是否为prefab预制体 如果是 就实例化的
        /// </summary>
        /// <param name="prefabPath"></param>
        /// <param name="beforeName"></param>
        /// <param name="AfterName"></param>
        FilePath CollectionOtherEffectPrefab(string prefabPath,string beforeName,string afterName,GameObject OldEffectPrefabInst,FilePath filePaths,bool checkResource = false)
        {
            
            GameObject ret = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject)) as GameObject;
            
            List<string> partList = new List<string>();

            Transform[] transList = ret.GetComponentsInChildren<Transform>();
            for (int i = 0; i < transList.Length; i++)
            {
                if (PrefabUtility.IsPartOfPrefabInstance(transList[i].gameObject))
                {
                    GameObject value = PrefabUtility.GetCorrespondingObjectFromOriginalSource(transList[i].gameObject);
                    string rootPath = AssetDatabase.GetAssetPath(value);
                    string finalPath = rootPath.Replace(beforeName, afterName);
                    if (!partList.Contains(finalPath))
                    {
                        
                        GameObject partGameObject = AssetDatabase.LoadAssetAtPath(rootPath, typeof(GameObject)) as GameObject;
                        GameObject partGameObjectInst = Instantiate(partGameObject);
                        tempGameObejct.Add(partGameObjectInst);
                        
                        
                        string path =
                            finalPath.Substring(0, finalPath.LastIndexOf(@"/"));
                        if (!Directory.Exists(path))
                        {
                            Directory.CreateDirectory(path);
                        }


                        filePaths.OtherPrefabPaths.Add(finalPath);
                        if (!checkResource)
                        {
                            PrefabUtility.SaveAsPrefabAsset(partGameObjectInst, finalPath);
                            AssetDatabase.SaveAssets();
                            DestroyImmediate(partGameObjectInst.gameObject);
                            AssetDatabase.Refresh();
                        }

                        Transform[] OldEffectPrefabInstChildren =
                            OldEffectPrefabInst.GetComponentsInChildren<Transform>();
                        List<GameObject> needDeleteGameObjects = new List<GameObject>();

                        for (int j = 0; j < OldEffectPrefabInstChildren.Length; j++)
                        {
                            if (transList[i].gameObject.name == OldEffectPrefabInstChildren[j].name)
                            {
                                GameObject retTrans =
                                    AssetDatabase.LoadAssetAtPath(finalPath, typeof(GameObject)) as GameObject;

                                GameObject cloneTrans = PrefabUtility.InstantiatePrefab(retTrans) as GameObject;
                                if (cloneTrans != null)
                                {
                                    cloneTrans.transform.parent = OldEffectPrefabInstChildren[j].parent;
                                    needDeleteGameObjects.Add(OldEffectPrefabInstChildren[j].gameObject);
                                }
                                break;

                            }
                        }
                        
                        needDeleteGameObjects.ForEach(child => DestroyImmediate(child));
                        partList.Add(finalPath);
                    }

                }
            }

            return filePaths;
        }

        #endregion
        
        #region 奥丁插件相关组件
        private OdinMenuTree tree;
        private PropertyTree m_LogicPrefabPropertyTree;
        private GameObject[] m_LogicPrefab;
        #endregion

        #region 奥丁插件 相关逻辑变量

        private RightTabEditor AllRightTabEditorData;
        private List<RightTabEditor> RightTabEditorList;

        #endregion

        /// <summary>
        /// 恢复材质依赖关系
        /// </summary>
        /// <param name="originalGameObejct"></param>
        /// <param name="targetGameObject"></param>
        private void RecoverMatrials(Transform originalGameObejct, Transform targetGameObject)
        {
            MeshRenderer[] OriginalMeshRenderers = originalGameObejct.GetComponentsInChildren<MeshRenderer>();
            Dictionary<string,Material[]> OrignalMeshRendererName = new Dictionary<string,Material[]>();
            for (int i = 0; i < OriginalMeshRenderers.Length; i++)
            {
                OrignalMeshRendererName.Add(OriginalMeshRenderers[i].transform.name,OriginalMeshRenderers[i].sharedMaterials);
            }
            
            MeshRenderer[] TargetMeshRenderers = targetGameObject.GetComponentsInChildren<MeshRenderer>();
            for (int i = 0; i < TargetMeshRenderers.Length; i++)
            {
                if (OrignalMeshRendererName.ContainsKey(TargetMeshRenderers[i].transform.name))
                {
                    List<Material> newMaterials = new List<Material>(OrignalMeshRendererName[TargetMeshRenderers[i].transform.name]);
                    TargetMeshRenderers[i].sharedMaterials = newMaterials.ToArray();
                }
            }


            // PrefabUtility.SavePrefabAsset(targetGameObject.gameObject);

        }
        
        /// <summary>
        /// 刷新当前道具卡列表数据
        /// </summary>
        public void RefreshData()
        {
            if (AllRightTabEditorData != null)
            {
                if (AllRightTabEditorData.m_FbxFiles != null)
                {
                    Dictionary<int,List<FileInfo>> FileInfoDic = new Dictionary<int, List<FileInfo>>();
                    int number = -1;
                    for (int i = 0; i < AllRightTabEditorData.m_FbxFiles.Length; i++)
                    {
                        if (int.TryParse(System.Text.RegularExpressions.Regex.Replace(AllRightTabEditorData.m_FbxFiles[i].Name, @"[^0-9]+", ""),out number))
                        {
                            if (!FileInfoDic.ContainsKey(number))
                            {
                                List<FileInfo> FileList = new List<FileInfo>();
                                FileInfoDic.Add(number,FileList);
                            }

                            FileInfoDic[number].Add(AllRightTabEditorData.m_FbxFiles[i]);
                        }
                    }

                    RightTabEditorList.Clear();
                    foreach (KeyValuePair<int,List<FileInfo>> pair in FileInfoDic)
                    {
                        RightTabEditorList.Add(new RightTabEditor(pair.Key,pair.Value.ToArray()));
                        tree.Add(pair.Key.ToString(),RightTabEditorList[RightTabEditorList.Count-1] );
                    }
                            

                    isShow = true;
                }
            }


        }


        protected override OdinMenuTree BuildMenuTree()
        {
            tree = new OdinMenuTree();
            return tree;
        }

        private bool isShow = false;
        
        
        protected override void OnBeginDrawEditors()
        {
            // var selected = this.MenuTree.Selection.FirstOrDefault();
            // var 24 = this.MenuTree.Config.SearchToolbarHeight;

            SirenixEditorGUI.BeginHorizontalToolbar(24);
            {
                    if (isShow)
                    {
                        
                        if (SirenixEditorGUI.ToolbarButton(new GUIContent("刷新页面")))
                        {
                            RefreshData();
                        }
                        
                        if (SirenixEditorGUI.ToolbarButton(new GUIContent("全部导入")))
                        {
                            for (int i = 0; i < RightTabEditorList.Count; i++)
                            {
                                RightTabEditorList[i].GiganticButton();
                            }
                        }
                    }
                    
                    
                    // Draws a toolbar with the name of the currently selected menu item
                    if (SirenixEditorGUI.ToolbarButton(new GUIContent("选择文件夹")))
                    {
                        AllRightTabEditorData =  GetCardData();
                        RightTabEditorList = new List<RightTabEditor>();
                        RefreshData();
                        GUIUtility.ExitGUI();
                    }


            }
            SirenixEditorGUI.EndHorizontalToolbar();
        }
        



        /// <summary>
        /// 自定义右侧每个Menu对应的Editor
        /// </summary>
        /// <param name="index"></param>
        protected override void DrawEditor(int index)
        {
            GUILayout.BeginVertical();
            
            base.DrawEditor(index);
            //当前选择的Menu对应的对象
            RightTabEditor currentTarget = CurrentDrawingTargets[index] as RightTabEditor;
            // // object currentTarget = CurrentDrawingTargets[index];
            //
            // if (currentTarget.m_FbxNumber != -1)
            // {
            //     GUILayout.Label(currentTarget.m_FbxNumber.ToString());
            DrawCardSkinInfo(currentTarget);
            // }
            //
            //
            
            GUILayout.EndVertical();
        }

        private int currentId = -1;

        // private RightTabEditor _rightTabEditor;
        
        /// <summary>
        /// 绘制道具卡信息
        /// </summary>
        /// <param name="_rightTabEditor"></param>
        private void DrawCardSkinInfo(RightTabEditor _rightTabEditor)
        {
            // Debug.Log("数字序号是:" + _rightTabEditor.m_FbxNumber);

            GUILayout.Label("已导入资源路径索引:↓");
            
            _rightTabEditor.LoadAsset();
            m_LogicPrefab = _rightTabEditor.InLinePrefabPreviews;
            if (m_LogicPrefab != null && m_LogicPrefab.Length > 0 && currentId != _rightTabEditor.m_FbxNumber)
            {
                currentId = _rightTabEditor.m_FbxNumber;
                m_LogicPrefabPropertyTree = PropertyTree.Create(m_LogicPrefab);
            }

            if (m_LogicPrefab == null || m_LogicPrefab.Length <= 0)
            {
                m_LogicPrefabPropertyTree = null;
            }
            
            m_LogicPrefabPropertyTree?.Draw(false);


        }


    }
    public class RightTabEditor
    {


        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="number"></param>
        /// <param name="files"></parcam>
        public RightTabEditor(int number = -1,FileInfo[] files = null)
        {

            m_FbxNumber = number;
            m_FbxFiles = files;
            FilePath = new FilePath();


            if (m_FbxFiles != null)
            {
                FilePath = CardResourceArtToolEditor.GetCardResourceArtToolEditor.OnClickLoadButton(m_FbxFiles,true);
            }
            
        }

        #region 道具卡右侧列表需要 属性

        [HideInEditorMode]  
        public int m_FbxNumber; //FBX对应的编号
        
        [HideInEditorMode]
        public FileInfo[] m_FbxFiles; //FBX文件信息
        
        [HideInEditorMode]
        public FilePath FilePath; //导入文件相关路径
        
        
        #endregion
        
        
        
        [Button("点击导入资源",ButtonSizes.Gigantic)]
        public void GiganticButton()
        {
            if (m_FbxFiles != null)
            {
                FilePath = CardResourceArtToolEditor.GetCardResourceArtToolEditor.OnClickLoadButton(m_FbxFiles);
                // CardResourceArtToolEditor.GetCardResourceArtToolEditor.RefreshData();
            }
        }


        [Button("点击编辑json文件")]
        public void EditJsonButton()
        {
            if (FilePath != null && FilePath.jsonPath != String.Empty)
            {
                CardDataCtrlEditor.OpenByPath(FilePath.jsonPath);
            }
        }
        

        /// <summary>
        /// 加载预制体
        /// </summary>
        public void LoadAsset()
        {
            if (FilePath != null && FilePath.MainPrefabPath != null)
            {
                List<GameObject> prefabGameObjects = new List<GameObject>();
                for (int i = 0; i < FilePath.MainPrefabPath.Count; i++)
                {
                    prefabGameObjects.Add(AssetDatabase.LoadAssetAtPath(FilePath.MainPrefabPath[i], typeof(GameObject)) as GameObject);
                }


                bool isNullPrefab = false;
                for (int i = 0; i < prefabGameObjects.Count; i++)
                {
                    if (prefabGameObjects[i] == null)
                    {
                        isNullPrefab = true;
                        break;
                    }
                }

                if (isNullPrefab == false)
                {
                    InLinePrefabPreviews = prefabGameObjects.ToArray() ;
                }

                FilePath.MainPrefabPath = null;

            }

            if (FilePath != null && FilePath.OtherPrefabPaths != null)
            {
                bool isGameObjectNullOther = false;
                
                List<Object> otherGameObjects = new List<Object>();
                
                
                if (FilePath.OtherPrefabPaths != null)
                {
                    for (int i = 0; i < FilePath.OtherPrefabPaths.Count; i++)
                    {
                        otherGameObjects.Add(AssetDatabase.LoadAssetAtPath(FilePath.OtherPrefabPaths[i], typeof(GameObject)));
                    }
                    
                }

                if (FilePath.OtherAnimPaths != null)
                {
                    for (int i = 0; i < FilePath.OtherAnimPaths.Count; i++)
                    {
                        otherGameObjects.Add(AssetDatabase.LoadAssetAtPath(FilePath.OtherAnimPaths[i], typeof(AnimationClip)));
                    }
                }
                
                for (int i = 0; i < otherGameObjects.Count; i++)
                {
                    if (otherGameObjects[i] == null)
                    {
                        isGameObjectNullOther = true;
                        break;
                    }
                }

                if (isGameObjectNullOther == false)
                {
                    InLineOtherPreviews = otherGameObjects.ToArray() ;
                }
                FilePath.OtherPrefabPaths = null;
                FilePath.OtherAnimPaths = null;
                
            }
        }
        
        [LabelText("已导入Prefab资源")] //预览模型
        [InlineEditor(InlineEditorModes.LargePreview)]
        public GameObject[] InLinePrefabPreviews;
        
        [LabelText("其余附带导入资源")] //预览其他资源
        [InlineEditor(InlineEditorModes.LargePreview)]
        public Object[] InLineOtherPreviews;
        
        




    }
}