Spaces:
Sleeping
Sleeping
| using UnityEngine; | |
| using UnityEditor; | |
| using System; | |
| using System.IO; | |
| using System.Linq; | |
| using System.Reflection; | |
| using UnityMeshSimplifier; | |
| public class TestBuilder | |
| { | |
| // ========================================== | |
| // FASE 1: MINIFY MESH | |
| // ========================================== | |
| public static void ManualConvert() | |
| { | |
| try | |
| { | |
| // --- WORKER LIMIT --- | |
| Unity.Jobs.LowLevel.Unsafe.JobsUtility.JobWorkerCount = 4; | |
| Debug.Log($"βοΈ [CLI] Job Worker Count: {Unity.Jobs.LowLevel.Unsafe.JobsUtility.JobWorkerCount}"); | |
| // --- BACKEND FIX --- | |
| PlayerSettings.SetScriptingBackend(BuildTargetGroup.Standalone, ScriptingImplementation.Mono2x); | |
| PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android, ScriptingImplementation.Mono2x); | |
| PlayerSettings.SetScriptingBackend(BuildTargetGroup.iOS, ScriptingImplementation.IL2CPP); | |
| // --- PROSES PERAMPINGAN MESH --- | |
| string inputPath = "Assets/InputRaw"; | |
| if (Directory.Exists(inputPath)) | |
| { | |
| string[] prefabs = Directory.GetFiles(inputPath, "*.prefab", SearchOption.AllDirectories); | |
| foreach (string path in prefabs) | |
| { | |
| GameObject go = PrefabUtility.LoadPrefabContents(path); | |
| if (go != null) | |
| { | |
| Debug.Log($"π¦ Merampingkan Mesh: {path}"); | |
| SimplifyMesh(go, path); | |
| PrefabUtility.SaveAsPrefabAsset(go, path); | |
| PrefabUtility.UnloadPrefabContents(go); | |
| } | |
| } | |
| } | |
| AssetDatabase.SaveAssets(); | |
| AssetDatabase.Refresh(); | |
| Debug.Log("β [CLI] Fase 1 (Minify) selesai dengan sukses. Menutup instance untuk masuk Fase Upload."); | |
| EditorApplication.Exit(0); | |
| } | |
| catch (Exception e) | |
| { | |
| Debug.LogError($"π [ERROR FATAL FASE 1] {e.ToString()}"); | |
| EditorApplication.Exit(1); | |
| } | |
| } | |
| // ========================================== | |
| // FASE 2: UPLOAD ZEPETO | |
| // ========================================== | |
| public static void ZepetoUploadPhase() | |
| { | |
| try | |
| { | |
| Debug.Log("π [CLI] Memulai Fase 2: Eksekusi Pengepakan & Upload ZEPETO..."); | |
| Type zepetoType = null; | |
| // Pencarian Aman (Safe Reflection) | |
| foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) | |
| { | |
| try | |
| { | |
| var types = assembly.GetTypes(); | |
| var foundType = types.FirstOrDefault(t => t != null && t.Name == "ZepetoPackageCliBuilder"); | |
| if (foundType != null) | |
| { | |
| zepetoType = foundType; | |
| break; | |
| } | |
| } | |
| catch (ReflectionTypeLoadException e) | |
| { | |
| var foundType = e.Types.FirstOrDefault(t => t != null && t.Name == "ZepetoPackageCliBuilder"); | |
| if (foundType != null) | |
| { | |
| zepetoType = foundType; | |
| break; | |
| } | |
| } | |
| catch (Exception) {} | |
| } | |
| if (zepetoType != null) | |
| { | |
| MethodInfo buildMethod = zepetoType.GetMethod("BuildWithArgs", BindingFlags.Public | BindingFlags.Static); | |
| if (buildMethod != null) | |
| { | |
| Debug.Log("β [CLI] Memanggil ZepetoPackageCliBuilder.BuildWithArgs()..."); | |
| buildMethod.Invoke(null, null); | |
| // Dibiarkan tanpa Exit(0) agar thread asinkron ZEPETO bisa berjalan untuk Upload | |
| } | |
| else | |
| { | |
| Debug.LogError("π [ERROR FASE 2] Method BuildWithArgs tidak ditemukan di class ZepetoPackageCliBuilder!"); | |
| EditorApplication.Exit(1); | |
| } | |
| } | |
| else | |
| { | |
| Debug.LogError("π [ERROR FASE 2] Class ZepetoPackageCliBuilder tidak ditemukan! Pastikan library Zepeto sudah ter-load di Fase 2."); | |
| EditorApplication.Exit(1); | |
| } | |
| } | |
| catch (Exception e) | |
| { | |
| Debug.LogError($"π [ERROR FATAL FASE 2 ASLI] {e.ToString()}"); | |
| EditorApplication.Exit(1); | |
| } | |
| } | |
| static void SimplifyMesh(GameObject go, string path) | |
| { | |
| var renderers = go.GetComponentsInChildren<Renderer>(); | |
| foreach (var ren in renderers) | |
| { | |
| Mesh src = (ren is MeshRenderer mr) ? ren.GetComponent<MeshFilter>()?.sharedMesh : | |
| (ren is SkinnedMeshRenderer smr) ? smr.sharedMesh : null; | |
| if (src != null && !src.name.Contains("_Internal")) | |
| { | |
| string assetPath = AssetDatabase.GetAssetPath(src); | |
| if (!string.IsNullOrEmpty(assetPath)) | |
| { | |
| ModelImporter importer = AssetImporter.GetAtPath(assetPath) as ModelImporter; | |
| if (importer != null && !importer.isReadable) | |
| { | |
| importer.isReadable = true; | |
| importer.SaveAndReimport(); | |
| } | |
| } | |
| var simplifier = new MeshSimplifier(); | |
| simplifier.Initialize(src); | |
| simplifier.SimplifyMesh(0.05f); // Sisa 5% poligon | |
| Mesh newMesh = simplifier.ToMesh(); | |
| newMesh.name = src.name + "_Internal"; | |
| string directory = Path.GetDirectoryName(path); | |
| string newMeshPath = Path.Combine(directory, newMesh.name + "_" + Guid.NewGuid().ToString().Substring(0, 5) + ".asset"); | |
| newMeshPath = newMeshPath.Replace("\\", "/"); | |
| AssetDatabase.CreateAsset(newMesh, newMeshPath); | |
| if (ren is MeshRenderer) ren.GetComponent<MeshFilter>().sharedMesh = newMesh; | |
| else if (ren is SkinnedMeshRenderer s) s.sharedMesh = newMesh; | |
| } | |
| } | |
| } | |
| } |