#unity/白日梦/代码缓存 ``` cs 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 { /// /// 导入的文件路径相关 /// public class FilePath { public List MainPrefabPath; public List OtherPrefabPaths; public List OtherAnimPaths; public string jsonPath; } /// /// 道具卡配置类 /// public class CardConfig { public string OriginIndex; public string TargetIndex; public string CardName; public Dictionary 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 InGameCardList = new List(); //局内道具卡列表 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 WriteJsonDic; //写入Json文件列表 public List tempGameObejct; //临时变量 #endregion #region 道具卡合入界面 private static CardResourceArtToolEditor _CardResourceArtToolEditorUI; public static CardResourceArtToolEditor GetCardResourceArtToolEditor { get { return _CardResourceArtToolEditorUI; } } [MenuItem("GameObject/美术道具卡合入")] private static void OpenWindow() { _CardResourceArtToolEditorUI = GetWindow(); _CardResourceArtToolEditorUI.position = GUIHelper.GetEditorWindowRect().AlignCenter(1000, 600); InitData(); } #endregion #region 道具卡功能逻辑 /// /// 判断节点是否为fbx模型 (之前没绑定的前提下) /// /// /// 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; } /// /// 通过道具卡名字获得道具卡类型 /// /// /// 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; } /// /// 根据道具卡类型和物品属性 获得对应的道具卡名字 /// /// /// /// 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; } /// /// 如果参照物是有OverController的 新物体也创建一个OverControlller /// /// /// /// private string CreateOverController(Transform trans,bool checkResource) { string newOverControllerPath = String.Empty; if (!checkResource) { Animator originalAnimator = trans.GetComponent(); 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; } /// /// 检测是否存在动画(导入) /// /// /// /// /// 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; } } /// /// 初始化数据 /// 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; } /// /// 导入资源 检测资源是否已有 /// /// /// /// public FilePath OnClickLoadButton(FileInfo[] fbxFiles,bool checkResource = false) { tempGameObejct = new List(); FilePath filePaths = new FilePath(); List PrefabList = new List(); //已处理预制体名称 for (int i = 0; i < fbxFiles.Length; i++) { if (filePaths.OtherPrefabPaths == null) { filePaths.OtherPrefabPaths = new List(); } if (filePaths.OtherAnimPaths == null) { filePaths.OtherAnimPaths = new List(); } m_FbxFile = fbxFiles[i];// 当前fbx文件 string[] nameList = GetCardType(ref currentCardType, m_FbxFile.Name); WriteJsonDic = new Dictionary(); // 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 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; } /// /// 检测道具卡名字是否合法,生成对应的prefab文件 /// /// public FilePath CheckCardResourceNameAndCreatePrefab(string name,string fbxPath,List 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 IndexList = new List(); 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(); NewCardPrefabDirectory = PrefabCardPath + numberResult + "/"; bool isFbx = false; Dictionary> otherEffectDic = new Dictionary>(); 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(); 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(); List needDeleteGameObjects = new List(); 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() == null) { clone.AddComponent(); } Animator newAnimator = clone.GetComponent(); newAnimator.runtimeAnimatorController = AssetDatabase.LoadAssetAtPath( 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(); 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(); } 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> 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(); 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; } /// /// 把fbx文件复制到工程 /// /// 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; } /// /// 基于源Json配置文件创建适配新prefab的Json配置文件 /// /// /// /// void CreateJsonFile(CardConfig cardConfig,Dictionary 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(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 keyValuePair in cardConfig.OldAndNewNameDic) { textString = textString.Replace(Path.GetFileNameWithoutExtension(keyValuePair.Key), Path.GetFileNameWithoutExtension(keyValuePair.Value)); } filePath.jsonPath = TargetFilePath; WriteJsonDic[TargetFilePath] = textString; } /// /// 收集道具卡之外的 其他特效的命名 /// /// /// void CollectOtherPrefab(Dictionary> 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 assetLevelList = new List(); dic.Add(logigPart, assetLevelList); } if (HasLevel) { dic[logigPart].Add(lodLv); } } /// /// 根据预制体路径,收集子物体是否为prefab预制体 如果是 就实例化的 /// /// /// /// 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 partList = new List(); Transform[] transList = ret.GetComponentsInChildren(); 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(); List needDeleteGameObjects = new List(); 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 RightTabEditorList; #endregion /// /// 恢复材质依赖关系 /// /// /// private void RecoverMatrials(Transform originalGameObejct, Transform targetGameObject) { MeshRenderer[] OriginalMeshRenderers = originalGameObejct.GetComponentsInChildren(); Dictionary OrignalMeshRendererName = new Dictionary(); for (int i = 0; i < OriginalMeshRenderers.Length; i++) { OrignalMeshRendererName.Add(OriginalMeshRenderers[i].transform.name,OriginalMeshRenderers[i].sharedMaterials); } MeshRenderer[] TargetMeshRenderers = targetGameObject.GetComponentsInChildren(); for (int i = 0; i < TargetMeshRenderers.Length; i++) { if (OrignalMeshRendererName.ContainsKey(TargetMeshRenderers[i].transform.name)) { List newMaterials = new List(OrignalMeshRendererName[TargetMeshRenderers[i].transform.name]); TargetMeshRenderers[i].sharedMaterials = newMaterials.ToArray(); } } // PrefabUtility.SavePrefabAsset(targetGameObject.gameObject); } /// /// 刷新当前道具卡列表数据 /// public void RefreshData() { if (AllRightTabEditorData != null) { if (AllRightTabEditorData.m_FbxFiles != null) { Dictionary> FileInfoDic = new Dictionary>(); 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 FileList = new List(); FileInfoDic.Add(number,FileList); } FileInfoDic[number].Add(AllRightTabEditorData.m_FbxFiles[i]); } } RightTabEditorList.Clear(); foreach (KeyValuePair> 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(); RefreshData(); GUIUtility.ExitGUI(); } } SirenixEditorGUI.EndHorizontalToolbar(); } /// /// 自定义右侧每个Menu对应的Editor /// /// 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; /// /// 绘制道具卡信息 /// /// 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 { /// /// 构造函数 /// /// /// 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); } } /// /// 加载预制体 /// public void LoadAsset() { if (FilePath != null && FilePath.MainPrefabPath != null) { List prefabGameObjects = new List(); 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 otherGameObjects = new List(); 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; } } ```