using System; using System.Collections.Generic; using System.Linq; using RootMotion.FinalIK; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; namespace NBF { public class RF4FixPrefab : Editor { #region 圈 [MenuItem("Assets/Fix/修复圈", false, 1)] private static void FixRings() { var rods = GetSelectPrefab(); foreach (var rod in rods) { try { FixRing(rod); EditorUtility.SetDirty(rod); } catch (Exception e) { Debug.LogError($"修复鱼圈失败,name={rod.name} e={e}"); } } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } private static void FixRing(GameObject prefab) { var rings = prefab.GetComponent(); if (rings == null) { rings = prefab.AddComponent(); } List list = new List(); // 遍历所有直接子对象 for (int i = 0; i < prefab.transform.childCount; i++) { Transform child = prefab.transform.GetChild(i); list.Add(child); } // rings.rings = list.ToArray(); List points = new List(); foreach (var tran in list) { for (int i = 0; i < tran.childCount; i++) { Transform c = tran.GetChild(i); if (c.name.Contains("Collider")) { points.Add(c); break; } } } // rings.points = points.ToArray(); List saveList = new List(); foreach (var node in list) { RodRingNode ringNode = new RodRingNode { ring = node }; foreach (var point in points) { if (point.parent != node) continue; ringNode.point = point; var rig = point.GetComponent(); if (rig == null) { rig = point.gameObject.AddComponent(); } if (rig != null) { rig.useGravity = false; rig.isKinematic = true; rig.mass = 1; } break; } saveList.Add(ringNode); } rings.rings = saveList.ToArray(); EditorUtility.SetDirty(prefab); } #endregion #region 鱼竿 //joint_root [MenuItem("Assets/Fix/修复鱼竿", false, 2)] private static void FixRods() { var rods = GetSelectPrefab(); foreach (var rod in rods) { try { FixRod(rod); EditorUtility.SetDirty(rod); } catch (Exception e) { Debug.LogError($"修复鱼竿失败,name={rod.name} e={e}"); } } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } private static void FixRod(GameObject prefab) { RemoveMissingScriptsFrom(prefab); var lineRenderer = prefab.GetComponent(); if (lineRenderer == null) { lineRenderer = prefab.AddComponent(); } lineRenderer.startWidth = 0.001f; lineRenderer.endWidth = 0.001f; var rod = prefab.GetComponent(); if (rod == null) { rod = prefab.AddComponent(); } rod.lineRenderer = lineRenderer; rod.root = FindTransformsByNameContainsOnes(prefab.transform, "joint_root"); rod.LeftHandConnector = FindTransformsByNameContainsOnes(prefab.transform, "l_hand_connector"); rod.RightHandConnector = FindTransformsByNameContainsOnes(prefab.transform, "r_hand_connector"); rod.ReelConnector = FindTransformsByNameContainsOnes(prefab.transform, "reel_connector"); rod.gripEnd = FindTransformsByNameContainsOnes(prefab.transform, "grip_end"); var trans = prefab.GetComponentsInChildren(true); List joints = new List(); List rings = new List(); foreach (var tran in trans) { if (tran == null) continue; if (tran == rod.root) continue; if (tran.name.Contains("_RING_")) { rings.Add(tran); } else if (tran.name.Contains("_joint_")) { joints.Add(tran); } } var blancEnd = FindTransformByName(prefab.transform, "blanc_end"); if (blancEnd == null) { Debug.LogError($"blanc_end 为空,name={prefab.name}"); } else { joints.Add(blancEnd); } rod.rings = rings.ToArray(); rod.joints = joints.ToArray(); var ccdIK = prefab.GetComponent(); if (ccdIK == null) { ccdIK = prefab.AddComponent(); } var solver = ccdIK.solver; if (solver != null) { solver.maxIterations = 3; var rootField = solver.GetType().GetField("root", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (rootField != null) { rootField.SetValue(solver, prefab.transform); } solver.bones = Array.Empty(); for (var i = 1; i < rod.joints.Length; i++) { solver.AddBone(rod.joints[i]); } } EditorUtility.SetDirty(rod); EditorUtility.SetDirty(ccdIK); EditorUtility.SetDirty(prefab); } #endregion #region 线轴 private static List _animationClips; [MenuItem("Assets/Fix/修复线轴", false, 3)] private static void FixReels() { _animationClips = GetAllClips(); var rods = GetSelectPrefab(); foreach (var rod in rods) { try { FixReel(rod); EditorUtility.SetDirty(rod); } catch (Exception e) { Debug.LogError($"修复线轴失败,name={rod.name} e={e}"); } } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } private static void FixReel(GameObject prefab) { RemoveMissingScriptsFrom(prefab); var reel = prefab.GetComponent(); if (reel == null) { reel = prefab.AddComponent(); } reel.rootConnector = FindTransformsByNameContainsOnes(prefab.transform, "reel_root_connector"); reel.rootCompensator = FindTransformsByNameContainsOnes(prefab.transform, "reel_root_compensator"); reel.lineConnector = FindTransformsByNameContainsOnes(prefab.transform, "line_connector"); reel.lineIntersect = FindTransformsByNameContainsOnes(prefab.transform, "line_intersect"); reel.lineIntersectHelper = reel.lineIntersect.parent; reel.handle = FindTransformsByNameContainsOnes(prefab.transform, "ik_locator_handle"); reel.handleEnd = reel.handle.parent; var anim = reel.rootConnector.parent.GetComponent(); if (anim == null) { anim = reel.rootConnector.parent.gameObject.AddComponent(); } reel.animator = anim; // var anim = reel.rootConnector.parent.GetComponent(); // if (anim == null) // { // anim = reel.rootConnector.parent.gameObject.AddComponent(); // } // List clips = _animationClips.Where(clip => clip.name.Contains(prefab.name)).ToList(); // foreach (var clip in clips) // { // anim.AddClip(clip, clip.name); // var lowName = clip.name.ToLower(); // if (lowName.Contains("open")) // { // reel.openAnimation = clip; // } // else if (lowName.Contains("close")) // { // reel.closeAnimation = clip; // } // else if (lowName.Contains("handle_roll")) // { // reel.rollHandleAnimation = clip; // } // } // anim.playAutomatically = true; // reel.anim = anim; } #endregion #region 浮漂 [MenuItem("Assets/Fix/修复浮漂", false, 4)] private static void FixBobbers() { _animationClips = GetAllClips(); var rods = GetSelectPrefab(); foreach (var rod in rods) { try { FixBobber(rod); EditorUtility.SetDirty(rod); } catch (Exception e) { Debug.LogError($"修复鱼漂失败,name={rod.name} e={e}"); } } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } private static void FixBobber(GameObject prefab) { // RemoveMissingScriptsFrom(prefab); var bobber = prefab.GetComponent(); if (bobber == null) { bobber = prefab.AddComponent(); } bobber.body = FindTransformsByNameContainsOnes(prefab.transform, "_body"); bobber.stick = FindTransformsByNameContainsOnes(prefab.transform, "_stick"); bobber.topConnector = FindTransformsByNameContainsOnes(prefab.transform, "_topConnector"); bobber.bottomConnector = FindTransformsByNameContainsOnes(prefab.transform, "_bottomConnector"); bobber.waterline = FindTransformsByNameContainsOnes(prefab.transform, "_waterline"); // var boxCollider = prefab.GetComponent(); // if (boxCollider != null) // { // DestroyImmediate(boxCollider); // // boxCollider = prefab.AddComponent(); // } // // boxCollider.center = new Vector3(0, -0.01f, 0); // boxCollider.size = new Vector3(0.005f, 0.005f, 0.005f); var rigidbody = prefab.GetComponent(); if (rigidbody == null) { rigidbody = prefab.AddComponent(); } rigidbody.useGravity = false; var configurableJoint = prefab.GetComponent(); if (configurableJoint == null) { configurableJoint = prefab.AddComponent(); } configurableJoint.xMotion = ConfigurableJointMotion.Locked; configurableJoint.yMotion = ConfigurableJointMotion.Locked; configurableJoint.zMotion = ConfigurableJointMotion.Locked; } #endregion #region 钩 [MenuItem("Assets/Fix/修复鱼钩", false, 5)] private static void FixHooks() { _animationClips = GetAllClips(); var rods = GetSelectPrefab(); foreach (var rod in rods) { try { FixHook(rod); EditorUtility.SetDirty(rod); } catch (Exception e) { Debug.LogError($"修复鱼钩失败,name={rod.name} e={e}"); } } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } private static void FixHook(GameObject prefab) { // RemoveMissingScriptsFrom(prefab); var hook = prefab.GetComponent(); if (hook == null) { hook = prefab.AddComponent(); } hook.baitConnector = FindTransformsByNameContainsOnes(prefab.transform, "bait_connector"); var boxCollider = prefab.GetComponent(); if (boxCollider == null) { boxCollider = prefab.AddComponent(); } boxCollider.center = new Vector3(0, -0.01f, 0); boxCollider.size = new Vector3(0.005f, 0.005f, 0.005f); var rigidbody = prefab.GetComponent(); if (rigidbody == null) { rigidbody = prefab.AddComponent(); } rigidbody.useGravity = false; var configurableJoint = prefab.GetComponent(); if (configurableJoint == null) { configurableJoint = prefab.AddComponent(); } configurableJoint.xMotion = ConfigurableJointMotion.Locked; configurableJoint.yMotion = ConfigurableJointMotion.Locked; configurableJoint.zMotion = ConfigurableJointMotion.Locked; } #endregion #region 鱼饵 [MenuItem("Assets/Fix/修复鱼饵", false, 6)] private static void FixBaits() { _animationClips = GetAllClips(); var rods = GetSelectPrefab(); foreach (var rod in rods) { try { FixBait(rod); EditorUtility.SetDirty(rod); } catch (Exception e) { Debug.LogError($"修复鱼钩失败,name={rod.name} e={e}"); } } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } private static void FixBait(GameObject prefab) { var bait = prefab.GetComponent(); if (bait == null) { bait = prefab.AddComponent(); } bait.hook = FindTransformsByNameContainsOnes(prefab.transform, "_hook"); } #endregion #region 仿生饵 [MenuItem("Assets/Fix/修复路亚饵", false, 6)] private static void FixLures() { _animationClips = GetAllClips(); var rods = GetSelectPrefab(); foreach (var rod in rods) { try { FixLure(rod); EditorUtility.SetDirty(rod); } catch (Exception e) { Debug.LogError($"修复鱼钩失败,name={rod.name} e={e}"); } } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } private static void FixLure(GameObject prefab) { RemoveMissingScriptsFrom(prefab); var lure = prefab.GetComponent(); if (lure == null) { lure = prefab.AddComponent(); } List hookPoints = new List(); for (int i = 1; i < 5; i++) { var hook = FindTransformByName(prefab.transform, $"hook_0{i}"); if (hook == null) break; hookPoints.Add(hook); } lure.hookPoints = hookPoints.ToArray(); // hook_01 } #endregion #region 鱼 [MenuItem("Assets/Fix/修复鱼", false, 7)] private static void FixFishs() { _animationClips = GetAllClips(); var rods = GetSelectPrefab(); foreach (var rod in rods) { try { FixFish(rod); EditorUtility.SetDirty(rod); } catch (Exception e) { Debug.LogError($"修复鱼钩失败,name={rod.name} e={e}"); } } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } private static void FixFish(GameObject prefab) { var bait = prefab.GetComponent(); if (bait == null) { bait = prefab.AddComponent(); } } #endregion #region 工具类 private static List GetAllClips() { List list = new List(); // 获取项目中所有的AnimationClip string[] guids = AssetDatabase.FindAssets("t:AnimationClip"); foreach (string guid in guids) { string path = AssetDatabase.GUIDToAssetPath(guid); AnimationClip clip = AssetDatabase.LoadAssetAtPath(path); if (clip != null) { list.Add(clip); } } return list; } private static string GetPathToParent(Transform currentTransform) { if (currentTransform == null || currentTransform.parent == null) { return string.Empty; // 如果没有父级,返回空字符串 } // 递归调用,先获取父级的路径,然后加上当前Transform的名字 return GetPathToParent(currentTransform.parent) + "/" + currentTransform.name; } private static T FindFirstComponentInChildren(GameObject parent) where T : Component { // 检查当前对象 T component = parent.GetComponent(); if (component != null) { return component; } // 递归检查子对象 foreach (Transform child in parent.transform) { T result = FindFirstComponentInChildren(child.gameObject); if (result != null) { return result; } } return null; } private static Transform FindTransformByName(Transform parent, string name) { // 检查当前对象 if (parent.name == name) { return parent; } // 递归检查子对象 foreach (Transform child in parent) { Transform result = FindTransformByName(child, name); if (result != null) { return result; } } return null; } /// /// /// /// /// /// private static List FindTransformsByNamePrefix(Transform parent, string namePrefix) { List result = new List(); // 检查当前对象 if (parent.name.StartsWith(namePrefix)) { result.Add(parent); } // 递归检查子对象 foreach (Transform child in parent) { result.AddRange(FindTransformsByNamePrefix(child, namePrefix)); } return result; } private static Transform FindTransformsByNameContainsOnes(Transform parent, string nameContains) { var trans = FindTransformsByNameContains(parent, nameContains); if (trans != null && trans.Count > 0) { return trans.First(); } return null; } /// /// 获取首个包含制定名字的tran /// /// /// /// private static List FindTransformsByNameContains(Transform parent, string nameContains) { List result = new List(); // 检查当前对象 if (parent.name.Contains(nameContains)) { result.Add(parent); } // 递归检查子对象 foreach (Transform child in parent) { result.AddRange(FindTransformsByNameContains(child, nameContains)); } return result; } private static T[] GetSelectPrefab(string ext = ".prefab") where T : Object { // 获取当前选中的路径 string selectedPath = GetSelectedFolderPath(); if (string.IsNullOrEmpty(selectedPath)) { Debug.LogWarning("No folder selected."); return Array.Empty(); } List list = new List(); // 获取该文件夹中的所有资产路径 string[] assetGuids = AssetDatabase.FindAssets("", new[] { selectedPath }); foreach (string guid in assetGuids) { string path = AssetDatabase.GUIDToAssetPath(guid); // 检查路径是否以 ".prefab" 结尾 if (path.EndsWith(ext)) { var prefab = AssetDatabase.LoadAssetAtPath(path); if (prefab != null) { list.Add(prefab); } } } return list.ToArray(); } /// /// 移除missing的脚步 /// /// /// private static int RemoveMissingScriptsFrom(params GameObject[] objects) { List forceSave = new(); int removedCounter = 0; foreach (GameObject current in objects) { if (current == null) continue; int missingCount = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(current); if (missingCount == 0) continue; GameObjectUtility.RemoveMonoBehavioursWithMissingScript(current); EditorUtility.SetDirty(current); if (EditorUtility.IsPersistent(current) && PrefabUtility.IsAnyPrefabInstanceRoot(current)) forceSave.Add(current); Debug.Log($"Removed {missingCount} Missing Scripts from {current.gameObject.name}", current); removedCounter += missingCount; } foreach (GameObject o in forceSave) PrefabUtility.SavePrefabAsset(o); return removedCounter; } /// /// 获取选中的文件夹路径 /// /// private static string GetSelectedFolderPath() { // 获取当前选中的对象 Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.Assets); if (selection.Length > 0) { string path = AssetDatabase.GetAssetPath(selection[0]); if (AssetDatabase.IsValidFolder(path)) { return path; } } return null; } /// /// 在所有子对象中查找名字为childName的对象 /// /// /// /// public static Transform FindDeepChild(Transform parent, string childName) { Transform result = parent.Find(childName); if (result != null) return result; foreach (Transform child in parent) { result = FindDeepChild(child, childName); if (result != null) return result; } return null; } #endregion } }