using System.Collections.Generic; using System.Linq; using Superlazy; using UnityEditor; using UnityEditor.Animations; using UnityEngine; public interface IPostProcessorModel { void OnCreatePrefab(string path, GameObject model); } public static class SLAssetPostprocessorModel { private static readonly HashSet targetPaths = new HashSet(); private static string GetDestPath(string path) { return SLFileUtility.FolderPath(path).Replace("/Raw/", "/Addressables/") + ".prefab"; } private static string GetPrefabPath(string path) { var targetName = SLFileUtility.FolderName(path); var targetPath = SLFileUtility.FolderPath(path); if (SLFileUtility.FolderName(path) == "Materials") { targetName = SLFileUtility.FolderName(targetPath); targetPath = SLFileUtility.FolderPath(targetPath); } return targetPath + "/" + targetName + ".prefab"; } private static string GetTargetFBX(string path) { var targetName = SLFileUtility.FolderName(path); var targetPath = SLFileUtility.FolderPath(path); if (SLFileUtility.FolderName(path) == "Materials") { targetName = SLFileUtility.FolderName(targetPath); targetPath = SLFileUtility.FolderPath(targetPath); } return targetPath + "/" + targetName + ".FBX"; } public static void OnPreprocessModel(ModelImporter importer) { importer.materialImportMode = ModelImporterMaterialImportMode.None; importer.generateSecondaryUV = false; importer.importAnimation = false; importer.animationType = ModelImporterAnimationType.Generic; importer.avatarSetup = ModelImporterAvatarSetup.CreateFromThisModel; } public static void OnRemove(string path) { var upperPath = path.ToUpper(); if (upperPath.IsLeft("ASSETS/RAW/UNITS/") && (upperPath.Contains(".FBX") || upperPath.Contains(".MAT"))) { if (SLFileUtility.FolderName(path) != SLFileUtility.FileName(path)) return; var newPath = GetDestPath(path); AssetDatabase.DeleteAsset(newPath); var prefabPath = GetPrefabPath(path); AssetDatabase.DeleteAsset(prefabPath); targetPaths.Add(GetTargetFBX(path)); // 삭제되어도 리빌드 } } public static void OnAdd(string path) { var upperPath = path.ToUpper(); if (upperPath.IsLeft("ASSETS/RAW/UNITS/") && (upperPath.Contains(".FBX") || upperPath.Contains(".MAT"))) { if (SLFileUtility.FolderName(path) != SLFileUtility.FileName(path)) return; targetPaths.Add(GetTargetFBX(path)); } else if (upperPath.IsLeft("ASSETS/RAW/UNITS/") && upperPath.Contains("_PREFAB.PREFAB")) { targetPaths.Add(GetPrefabPath(path).Replace(".prefab", "_Prefab.prefab")); } } public static void CreatePrefab(string path, string destPath) { try { var modelCreateComponents = new List(); modelCreateComponents.CreateInstanceList(); var go = AssetDatabase.LoadAssetAtPath(path); if (go == null) return; var prefab = new GameObject(go.name); var model = Object.Instantiate(go); model.name = "Model"; model.transform.SetParent(prefab.transform); model.AddComponent(); var guids = AssetDatabase.FindAssets("t:Material", new string[] { SLFileUtility.FolderPath(path) }); var materials = guids.Select(guid => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid))).ToDictionary(m => m.name); foreach (var renderer in model.GetComponentsInChildren()) { var sharedMaterials = new Material[renderer.sharedMaterials.Length]; // Material을 직접 엘리먼트로 대입하면 안되고 배열을 통으로 넣어야함 for (var i = 0; i < renderer.sharedMaterials.Length; ++i) { if (materials.TryGetValue($"{renderer.name}_{i + 1}", out var numMat)) { sharedMaterials[i] = numMat; } else if (materials.TryGetValue(renderer.name, out var mat)) { sharedMaterials[i] = mat; } else if (materials.TryGetValue(go.name, out var defaultMat)) { sharedMaterials[i] = defaultMat; } else { sharedMaterials[i] = renderer.sharedMaterials[i]; // 에러인가? 잠깐 파일 안갖다놨을뿐인가? } } renderer.sharedMaterials = sharedMaterials; } var res = prefab.AddComponent(); foreach (var comp in modelCreateComponents) { comp.OnCreatePrefab(destPath, model); } res.Init(); SLFileUtility.MakeFolderFromFilePath(destPath); { // Make Duumy(for test) var dummyObj = Object.Instantiate(model); var anim = dummyObj.GetComponentInChildren(); var controller = AnimatorController.CreateAnimatorControllerAtPath(GetPrefabPath(path).Replace(".prefab", ".controller")); anim.runtimeAnimatorController = controller; var rootStateMachine = controller.layers[0].stateMachine; var clipids = AssetDatabase.FindAssets("t:AnimationClip", new string[] { SLFileUtility.FolderPath(path) }); foreach (var guid in clipids) { var clip = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid)); if (clip != null) { var state = rootStateMachine.AddState(clip.name); state.motion = clip; } } var dummy = PrefabUtility.SaveAsPrefabAssetAndConnect(dummyObj, GetPrefabPath(path), InteractionMode.AutomatedAction); Object.DestroyImmediate(dummyObj, false); } AssetDatabase.DeleteAsset(destPath); var newPreafb = PrefabUtility.SaveAsPrefabAssetAndConnect(prefab, destPath, InteractionMode.AutomatedAction); Object.DestroyImmediate(prefab, false); Debug.Log("Build : " + destPath, newPreafb); } catch (System.Exception e) { Debug.LogError("Cant build " + destPath + "\n" + e); } } public static void BuildTarget() { foreach (var path in targetPaths) { CreatePrefab(path, GetDestPath(path)); } targetPaths.Clear(); } internal static void OnPreprocessTexture(TextureImporter importer) { importer.sRGBTexture = true; importer.mipmapEnabled = false; importer.streamingMipmaps = false; importer.wrapMode = TextureWrapMode.Clamp; importer.filterMode = FilterMode.Bilinear; } }