using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; using UnityEngine.AI; public static class MyEditorUtil { struct TransformData { public Vector3 localPosition; public Quaternion localRotation; public Vector3 localScale; public TransformData(Vector3 localPosition, Quaternion localRotation, Vector3 localScale) { this.localPosition = localPosition; this.localRotation = localRotation; this.localScale = localScale; } } private static TransformData _data; [MenuItem("Edit/Copy Transform Values &c", false, -101)] public static void CopyTransformValues() { if (Selection.gameObjects.Length == 0) return; var selectionTr = Selection.gameObjects[0].transform; _data = new TransformData(selectionTr.localPosition, selectionTr.localRotation, selectionTr.localScale); } [MenuItem("Edit/Paste Transform Values &v", false, -101)] public static void PasteTransformValues() { foreach (var selection in Selection.gameObjects) { Transform selectionTr = selection.transform; Undo.RecordObject(selectionTr, "Paste Transform Values"); selectionTr.localPosition = _data.localPosition; selectionTr.localRotation = _data.localRotation; selectionTr.localScale = _data.localScale; } } [MenuItem("Edit/Del All Child", false, -102)] public static void DelAllChild() { foreach (var selection in Selection.gameObjects) { Transform selectionTr = selection.transform; for (int i = 0; i < selectionTr.childCount; i++) { GameObject.DestroyImmediate(selectionTr.GetChild(i).gameObject); --i; } } } [MenuItem("Edit/Set Mob Data", false, -103)] public static void SetMobData() { // 설정된 몹 프리팹을 지우고 몹 데이터만 남긴다. 해당 데이터로 게임 내에서 몹을 동적 로딩한다. foreach (var selection in Selection.gameObjects) { var mobs = selection.GetComponentsInChildren(); var dic_wave = new Dictionary(); for (int i = 0; i < mobs.Length; i++) { var parent = mobs[i].transform.parent; if (!dic_wave.ContainsKey(parent.name)) { var loaddata = parent.GetComponent(); if (loaddata == null) loaddata = parent.gameObject.AddComponent(); dic_wave.Add(parent.name, loaddata); } var detaildata = new LoadMobDetailData { m_Position = mobs[i].transform.position, m_Rotation = mobs[i].transform.rotation, m_Role = mobs[i].m_Role, m_SubRole = mobs[i].m_SubRole, m_MagicID = (mobs[i] as MobActor).MagicID, }; if (mobs[i].name.Contains("(")) { var split = mobs[i].name.Split(' '); detaildata.m_PrefabName = ""; if (split.Length == 2) detaildata.m_PrefabName = split[0]; else for (int j = 0; j < split.Length - 1; j++) { if (j == split.Length - 2) detaildata.m_PrefabName += split[j]; else detaildata.m_PrefabName += split[j] + " "; } } else detaildata.m_PrefabName = mobs[i].name; var witch = mobs[i] as WitchEnemyActor; if (witch != null) detaildata.list_MagicID = witch.list_MagicID; dic_wave[parent.name].list_mobdata.Add(detaildata); GameObject.DestroyImmediate(mobs[i].gameObject); } } } [MenuItem("Edit/Optimize Mesh", false, -104)] public static void OptimizeMesh() { // 메쉬 렌더러를 찾아서 최적화 한다. if (Selection.activeObject) { var meshrenderer = (Selection.activeObject as GameObject).GetComponentsInChildren(); for (int i = 0; i < meshrenderer.Length; i++) { if (meshrenderer[i].tag.Equals("Untagged")) { var om = meshrenderer[i].GetComponent(); if (om == null) om = meshrenderer[i].gameObject.AddComponent(); om.Start(); om.DecimateMesh_byPath(); om.SaveMesh("Assets/ResWork/Optimized/"); GameObject.DestroyImmediate(om); } } EditorUtility.DisplayDialog("메시 최적화", "완료", "알았다"); } } [MenuItem("Edit/GetFolderFileNames", false, -105)] public static void GetFolderFileNames() { DirectoryInfo di = new DirectoryInfo("Assets/ResWork/UIPrefabs/Title"); var ext = ".prefab"; // ".mat"; var filenames = ""; foreach (FileInfo file in di.GetFiles("*" + ext)) filenames += file.Name.Replace(ext, "") + "\n"; Debug.Log(filenames); } private static List objectSettingsList = new List(); [MenuItem("Edit/MobSetting &s", false, -1001)] static void MobSetting() { var selectedObjects = Selection.gameObjects; foreach (var go in selectedObjects) { var ma = go.GetComponent(); if (ma == null) ma = go.AddComponent(); var m_bc = go.GetComponent(); if (m_bc == null) m_bc = go.AddComponent(); var longd = go.GetComponent(); if (longd == null) go.AddComponent(); CommonSetting(go, ObstacleAvoidanceType.LowQualityObstacleAvoidance, 0, "Actor"); } } [MenuItem("Edit/PetSetting", false, -1002)] static void PetSetting() { var selectedObjects = Selection.gameObjects; foreach (var go in selectedObjects) { var ma = go.GetComponent(); if (ma == null) ma = go.AddComponent(); ma.m_Role = eRole.Pet; CommonSetting(go, ObstacleAvoidanceType.NoObstacleAvoidance, 99, "Actor"); } } [MenuItem("Edit/PCSetting", false, -1003)] static void PCSetting() { var selectedObjects = Selection.gameObjects; foreach (var go in selectedObjects) { // 프리팹 에셋 경로 가져오기 string prefabPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(go); // Prefab인지 확인 if (!string.IsNullOrEmpty(prefabPath)) { // Prefab Asset 가져오기 var prefabAsset = PrefabUtility.LoadPrefabContents(prefabPath); var ma = prefabAsset.GetComponent(); if (ma == null) ma = prefabAsset.AddComponent(); ma.m_Role = eRole.PC; var navmesh = prefabAsset.GetComponent(); if (navmesh == null) navmesh = prefabAsset.AddComponent(); navmesh.speed = 6f; navmesh.angularSpeed = 300f; navmesh.acceleration = 140f; navmesh.stoppingDistance = 4f; navmesh.autoBraking = true; navmesh.radius = 0.4f; navmesh.height = 2f; navmesh.avoidancePriority = 50; navmesh.obstacleAvoidanceType = ObstacleAvoidanceType.LowQualityObstacleAvoidance; Set_CommonRigidBody(prefabAsset, "Actor"); var cc = prefabAsset.GetComponent(); if (cc == null) cc = prefabAsset.AddComponent(); cc.center = Vector3.up * 0.79f; cc.radius = 0.55f; cc.height = 1.58f; cc.direction = 1; var pcactor = prefabAsset.GetComponent(); List list_tr = new List(); // 프리팹 내부 수정 var wristL = FindDeepChild(prefabAsset.transform, "Wrist_L"); var wristR = FindDeepChild(prefabAsset.transform, "Wrist_R"); if (wristL != null) { var strName = "w_shield"; var shield = FindDeepChild(prefabAsset.transform, strName); if (shield == null) shield = new GameObject(strName).transform; shield.parent = wristL; shield.localPosition = new Vector3(0.0184f, -0.0158f, 0.0261f); shield.localEulerAngles = new Vector3(-21.84897f, 162.9937f, -171.4406f); shield.localScale = Vector3.one * 0.6f; list_tr.Add(shield); } if (wristR != null) { var strName = "w_righthand"; var mace = FindDeepChild(prefabAsset.transform, strName); if (mace == null) mace = new GameObject(strName).transform; mace.parent = wristR; mace.localPosition = new Vector3(-0.0749f, 0.1431f, -0.024f); mace.localEulerAngles = new Vector3(0, 0, 10.6f); mace.localScale = new Vector3(1f, 0.7f, 1f); list_tr.Add(mace); } if (wristR != null) { var strName = "w_onehand"; var onehand = FindDeepChild(prefabAsset.transform, strName); if (onehand == null) onehand = new GameObject(strName).transform; onehand.parent = wristR; onehand.localPosition = new Vector3(-0.0546f, -0.001f, -0.0271f); onehand.localEulerAngles = new Vector3(0f, 107.83f, 0f); onehand.localScale = Vector3.one * 0.8f; list_tr.Add(onehand); } if (wristL != null) { var strName = "w_bladedancer_l"; var bd_l = FindDeepChild(prefabAsset.transform, strName); if (bd_l == null) bd_l = new GameObject(strName).transform; bd_l.parent = wristL; bd_l.localPosition = new Vector3(0.0413f, 0.015f, 0.0255f); bd_l.localEulerAngles = new Vector3(6.747354f, -168.0254f, 157.2563f); bd_l.localScale = Vector3.one; list_tr.Add(bd_l); } if (wristR != null) { var strName = "w_bladedancer_r"; var bd_r = FindDeepChild(prefabAsset.transform, strName); if (bd_r == null) bd_r = new GameObject(strName).transform; bd_r.parent = wristR; bd_r.localPosition = new Vector3(-0.0546f, -0.001f, -0.0271f); bd_r.localEulerAngles = new Vector3(0f, 107.83f, 0f); bd_r.localScale = Vector3.one * 0.8f; list_tr.Add(bd_r); } if (wristR != null) { var strName = "w_orb"; var bd_r = FindDeepChild(prefabAsset.transform, strName); if (bd_r == null) bd_r = new GameObject(strName).transform; bd_r.parent = wristR; bd_r.localPosition = new Vector3(-0.05439695f, -0.00136376f, -0.02748983f); bd_r.localEulerAngles = new Vector3(-1.791351f, 107.4387f, 1.349683f); bd_r.localScale = Vector3.one * 0.1f; list_tr.Add(bd_r); } if (wristL != null) { var strName = "w_archer_l"; var bow_l = FindDeepChild(prefabAsset.transform, strName); if (bow_l == null) bow_l = new GameObject(strName).transform; bow_l.parent = wristL; bow_l.localPosition = new Vector3(0.069f, -0.01f, 0.034f); bow_l.localEulerAngles = new Vector3(-2.139496f, 0f, -3.480011f); bow_l.localScale = Vector3.one * 1.3f; list_tr.Add(bow_l); } pcactor.tfs_weapon = list_tr.ToArray(); // 수정한 프리팹 저장 PrefabUtility.SaveAsPrefabAsset(prefabAsset, prefabPath); PrefabUtility.UnloadPrefabContents(prefabAsset); } else { Debug.LogError($"{go.name}은(는) 프리팹 인스턴스가 아닙니다!"); } } } static Transform FindDeepChild(Transform parent, string name) { foreach (Transform child in parent) { if (child.name == name) return child; var result = FindDeepChild(child, name); if (result != null) return result; } return null; } static void CommonSetting(GameObject go, ObstacleAvoidanceType avoid, int avoidancePriority, string layer) { Set_Collideer(go); var navmesh = go.GetComponent(); if (navmesh == null) navmesh = go.AddComponent(); navmesh.speed = 4.5f; navmesh.angularSpeed = 300f; navmesh.acceleration = 140f; navmesh.stoppingDistance = 0.1f; navmesh.autoBraking = true; navmesh.radius = 0.25f; navmesh.avoidancePriority = avoidancePriority; navmesh.obstacleAvoidanceType = avoid; Set_CommonRigidBody(go, layer); } static void Set_CommonRigidBody(GameObject go, string layer) { go.layer = LayerMask.NameToLayer(layer); var rigidbody = go.GetComponent(); if (rigidbody == null) rigidbody = go.AddComponent(); rigidbody.useGravity = false; rigidbody.mass = 1; rigidbody.drag = 0; rigidbody.angularDrag = 0.05f; rigidbody.automaticCenterOfMass = true; rigidbody.automaticInertiaTensor = true; rigidbody.collisionDetectionMode = CollisionDetectionMode.Discrete; rigidbody.constraints = RigidbodyConstraints.FreezeAll; } private static void UpdateAllObjects() { for (int i = objectSettingsList.Count - 1; i >= 0; i--) { var settings = objectSettingsList[i]; if (settings.tick < 0) { var bounds = settings.m_smr.bounds; settings.m_bc.center = bounds.center; settings.m_bc.size = bounds.size + Vector3.up; settings.m_smr.updateWhenOffscreen = false; settings.go.transform.localScale = settings.m_Scale; objectSettingsList.RemoveAt(i); } else { settings.tick--; } } if (objectSettingsList.Count == 0) { EditorApplication.update -= UpdateAllObjects; } } private class ObjectSettings { public GameObject go; public Vector3 m_Scale; public BoxCollider m_bc; public SkinnedMeshRenderer m_smr; public int tick; } [MenuItem("Edit/WorkerSetting", false, -1000)] static void WorkerSetting() { foreach (var selectedObject in Selection.objects) { var go = selectedObject as GameObject; if (go == null) continue; var wa = go.GetComponent(); if (wa == null) wa = go.AddComponent(); CommonSetting(go, ObstacleAvoidanceType.NoObstacleAvoidance, 99, "Default"); } } [MenuItem("Edit/SetCollider", false, -2000)] static void SetCollider() { foreach (var go in Selection.gameObjects) Set_Collideer(go); } static void Set_Collideer(GameObject go) { var objData = new ObjectSettings { go = go, m_Scale = go.transform.localScale, tick = 10 }; go.transform.localScale = Vector3.one; var m_bc = go.GetComponent(); if (m_bc == null) m_bc = go.AddComponent(); objData.m_bc = m_bc; var rds = go.GetComponentsInChildren(); SkinnedMeshRenderer m_smr = null; if (rds.Length == 1) m_smr = rds[0]; else { for (int i = 0; i < rds.Length; i++) { if (rds[i].name.ToLower().Contains("skin")) { m_smr = rds[i]; break; } } if (m_smr == null) m_smr = rds[0]; } m_smr.updateWhenOffscreen = true; objData.m_smr = m_smr; objectSettingsList.Add(objData); EditorApplication.update += UpdateAllObjects; } [MenuItem("Tools/Del_AddrResource")] static void Del_AddrResource() { bool result = EditorUtility.DisplayDialog( "경고!", // 제목 "모든 어드레서블 데이터를 삭제하시겠습니까?", // 메시지 "확인", // 확인 버튼 "취소" // 취소 버튼 ); if (result) { Caching.ClearCache(); EditorUtility.DisplayDialog("알림", "삭제 완료", "확인"); } } //[MenuItem("Edit/Find All Particle", false, -103)] //public static void FindAllParticle() //{ // foreach (var selection in Selection.gameObjects) // { // var pats = selection.transform.GetComponentsInChildren(); // for (int i = 0; i < pats.Length; i++) // Debug.Log(pats[i].name); // } //} //[MenuItem("Ino/Test %g")] //static void Ino_Test() //{ // ModelImporter modelImporter = (ModelImporter)AssetImporter.GetAtPath("Assets/ResWork/Quirky Series Vol.1 [v1.3]/Arctic Vol.1/Animations/Penguin_Animations.fbx"); // for (int i = 0; i < modelImporter.clipAnimations.Length; i++) // { // switch(modelImporter.clipAnimations[i].name) // { // case "Attack": // break; // } // } //} //[MenuItem("Ino/Test")] //static void FindHUD() //{ // Debug.Log("시작"); // for (int i = 0; i < Selection.gameObjects.Length; i++) // { // var hud = Selection.gameObjects[i].transform.Find("HUD"); // if (hud == null) Debug.Log(Selection.gameObjects[i]); // } // Debug.Log("끝"); //} //[MenuItem("Ino/Bip001 to Bip002")] //static void ChangeBip01Bip02() //{ // var tf = Selection.activeGameObject.transform; // ChangeName(tf); //} // 자식까지 포함해서 레이어를 재귀적으로 설정하는 함수 }