zepeto / UnityProject /Assets /Editor /TestBuilder.cs
webzepetoku's picture
Update UnityProject/Assets/Editor/TestBuilder.cs
7dc9f14 verified
Raw
History Blame Contribute Delete
11.3 kB
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using ZEPETO.Asset;
using UnityMeshSimplifier; // Pastikan library ada di folder Assets
public class TestBuilder
{
public static void ManualConvert()
{
EditorApplication.LockReloadAssemblies();
Debug.Log("===============================================================");
Debug.Log("๐Ÿ› ๏ธ [ZEPETO BUILDER] Smart Minifier & Texture (Original Material Guard)");
Debug.Log("===============================================================");
try
{
// --- KUNCI PENYELESAIAN FATAL ERROR (CRASH) ---
string[] badPackages = Directory.GetFiles("Assets", "package.json", SearchOption.AllDirectories);
foreach (string badPkg in badPackages)
{
File.Delete(badPkg);
if (File.Exists(badPkg + ".meta")) File.Delete(badPkg + ".meta");
Debug.Log($"๐Ÿ—‘๏ธ [FIX] Menghapus package.json nyasar: {badPkg}");
}
// 1. Parsing Argumen Command Line
string[] args = Environment.GetCommandLineArgs();
string z_id = "";
string z_pw = "";
int targetTris = 9900;
for (int i = 0; i < args.Length; i++)
{
if (args[i] == "-id" && i + 1 < args.Length) z_id = args[i + 1];
if (args[i] == "-password" && i + 1 < args.Length) z_pw = args[i + 1];
if (args[i] == "-maxtris" && i + 1 < args.Length) targetTris = int.Parse(args[i + 1]);
}
// 2. Tentukan Path
string inputPath = "Assets/InputRaw";
string outputPath = "Assets/OptimizedOutput";
if (!Directory.Exists(inputPath))
{
Debug.LogError($"โŒ [BUILDER] Folder tidak ditemukan: {inputPath}");
EditorApplication.UnlockReloadAssemblies();
EditorApplication.Exit(1);
return;
}
string[] prefabs = Directory.GetFiles(inputPath, "*.prefab", SearchOption.AllDirectories);
if (prefabs.Length == 0)
{
Debug.LogError("โŒ [BUILDER] Tidak ada file .prefab ditemukan.");
EditorApplication.UnlockReloadAssemblies();
EditorApplication.Exit(1);
return;
}
string targetPrefabPath = prefabs[0];
string prefabFileName = Path.GetFileName(targetPrefabPath);
// 3. Buat Folder Output yang Bersih
if (Directory.Exists(outputPath)) Directory.Delete(outputPath, true);
Directory.CreateDirectory(outputPath);
AssetDatabase.Refresh();
// 4. Muat Prefab Asli dan Instansiasi ke Memori Scene
GameObject originalPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(targetPrefabPath);
GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(originalPrefab);
// ====================================================================
// --- TAHAP PERSIAPAN MEGA PREFAB (WADAH) ---
// ====================================================================
string finalPrefabPath = $"{outputPath}/{prefabFileName}";
GameObject tempObj = new GameObject("TempContainer");
PrefabUtility.SaveAsPrefabAsset(tempObj, finalPrefabPath);
UnityEngine.Object.DestroyImmediate(tempObj);
// ====================================================================
// --- TAHAP SMART TEXTURE SCALER (Target Max 950 KB) ---
// ====================================================================
Debug.Log("๐Ÿ–ผ๏ธ [TEXTURE] Memulai Kalkulasi Smart Texture Scaler (Target: 950KB)...");
var allRenderers = instance.GetComponentsInChildren<Renderer>(true);
HashSet<Texture2D> uniqueTextures = new HashSet<Texture2D>();
foreach (var rend in allRenderers)
{
foreach (var mat in rend.sharedMaterials)
{
if (mat == null) continue;
string[] texNames = mat.GetTexturePropertyNames();
foreach (var tName in texNames)
{
Texture tex = mat.GetTexture(tName);
if (tex is Texture2D t2d) uniqueTextures.Add(t2d);
}
}
}
long totalPixels = 0;
foreach (var tex in uniqueTextures)
{
totalPixels += (tex.width * tex.height);
}
long maxSafePixels = 950 * 1024;
float textureScaleRatio = 1.0f;
if (totalPixels > maxSafePixels)
{
textureScaleRatio = Mathf.Sqrt((float)maxSafePixels / (float)totalPixels);
Debug.Log($"๐Ÿ“‰ [TEXTURE MATH] Menerapkan Smart Scale Ratio: {textureScaleRatio:P2}");
}
foreach (var tex in uniqueTextures)
{
string texPath = AssetDatabase.GetAssetPath(tex);
if (string.IsNullOrEmpty(texPath)) continue;
TextureImporter importer = AssetImporter.GetAtPath(texPath) as TextureImporter;
if (importer != null)
{
int currentMaxDim = Mathf.Max(tex.width, tex.height);
importer.mipmapEnabled = false;
importer.textureCompression = TextureImporterCompression.CompressedLQ;
if (textureScaleRatio < 1.0f)
{
int targetDim = (int)(currentMaxDim * textureScaleRatio);
int powerOf2 = 32;
while (powerOf2 * 2 <= targetDim && powerOf2 < 2048)
{
powerOf2 *= 2;
}
importer.maxTextureSize = powerOf2;
}
else
{
importer.maxTextureSize = Mathf.NextPowerOfTwo(currentMaxDim);
}
importer.SaveAndReimport();
Debug.Log($"โœ… [TEXTURE] {tex.name} divalidasi pada resolusi: {importer.maxTextureSize}px");
}
}
// ====================================================================
// --- TAHAP PENJAGAAN MATERIAL BAWAAN ---
// Kita biarkan material terhubung ke file .mat aslinya. Tidak ada kloning!
// ====================================================================
Debug.Log("๐ŸŽจ [MATERIAL] Material bawaan & Custom Shader dipertahankan sepenuhnya.");
// ====================================================================
// --- TAHAP SMART MINIFIER POLIGON + EMBEDDING MESH ---
// ====================================================================
var skinnedRenderers = instance.GetComponentsInChildren<SkinnedMeshRenderer>(true);
var meshFilters = instance.GetComponentsInChildren<MeshFilter>(true);
int totalOriginalTris = 0;
// BYPASS DRM ZEPETO: Menghitung poligon dengan GetIndexCount
foreach (var smr in skinnedRenderers)
{
if (smr.sharedMesh != null)
{
for (int i = 0; i < smr.sharedMesh.subMeshCount; i++)
{
totalOriginalTris += (int)(smr.sharedMesh.GetIndexCount(i) / 3);
}
}
}
foreach (var mf in meshFilters)
{
if (mf.sharedMesh != null)
{
for (int i = 0; i < mf.sharedMesh.subMeshCount; i++)
{
totalOriginalTris += (int)(mf.sharedMesh.GetIndexCount(i) / 3);
}
}
}
float quality = (totalOriginalTris > targetTris) ? (float)targetTris / (float)totalOriginalTris : 1.0f;
Debug.Log($"๐Ÿ“Š [MESH] Poligon Asli: {totalOriginalTris} tris | Target: {targetTris} | Rasio: {quality}");
foreach (var smr in skinnedRenderers)
{
if (smr.sharedMesh == null) continue;
var meshSimplifier = new UnityMeshSimplifier.MeshSimplifier();
meshSimplifier.Initialize(smr.sharedMesh);
meshSimplifier.SimplifyMesh(quality);
Mesh optimizedMesh = meshSimplifier.ToMesh();
if (optimizedMesh != null)
{
optimizedMesh.name = smr.sharedMesh.name + "_embedded";
AssetDatabase.AddObjectToAsset(optimizedMesh, finalPrefabPath);
smr.sharedMesh = optimizedMesh;
}
}
foreach (var mf in meshFilters)
{
if (mf.sharedMesh == null) continue;
var meshSimplifier = new UnityMeshSimplifier.MeshSimplifier();
meshSimplifier.Initialize(mf.sharedMesh);
meshSimplifier.SimplifyMesh(quality);
Mesh optimizedMesh = meshSimplifier.ToMesh();
if (optimizedMesh != null)
{
optimizedMesh.name = mf.sharedMesh.name + "_embedded";
AssetDatabase.AddObjectToAsset(optimizedMesh, finalPrefabPath);
mf.sharedMesh = optimizedMesh;
}
}
// ====================================================================
// --- FINALISASI & PACKING ---
// ====================================================================
GameObject optimizedPrefab = PrefabUtility.SaveAsPrefabAsset(instance, finalPrefabPath);
UnityEngine.Object.DestroyImmediate(instance);
AssetDatabase.SaveAssets();
Debug.Log($"โœ… [BUILDER] Prefab siap dengan mesh terpadatkan dan material bawaan utuh!");
Debug.Log("๐Ÿš€ [PACKING] Menjalankan ZepetoAssetPackage.Pack...");
var result = new StringBuilder();
var statistics = ZepetoAssetBundleInfo.Create(optimizedPrefab);
if (statistics != null)
{
result.AppendLine("[ZEPETO STUDIO ARCHIVE RESULT]");
result.AppendLine(JsonUtility.ToJson(statistics, true));
}
var packResult = ZepetoAssetPackage.Pack(optimizedPrefab);
result.Append(packResult);
Debug.Log(result.ToString());
Debug.Log("โœ… [BUILDER] Seluruh proses konversi sukses sempurna.");
EditorApplication.UnlockReloadAssemblies();
EditorApplication.Exit(0);
}
catch (Exception e)
{
Debug.LogError($"๐Ÿ”ฅ [BUILDER] Error: {e.Message}");
Debug.LogError($"StackTrace: {e.StackTrace}");
EditorApplication.UnlockReloadAssemblies();
EditorApplication.Exit(1);
}
}
}