293 lines
9.9 KiB
C#
293 lines
9.9 KiB
C#
using UnityEditor;
|
|
using UnityEngine;
|
|
using System.IO;
|
|
using System.Collections.Generic;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using CustomAssetBundleSystem;
|
|
|
|
/// <summary>
|
|
/// Unity Editor tool to build AssetBundles and generate catalog.json
|
|
/// Menu: Tools > AssetBundles > Build for Android
|
|
/// </summary>
|
|
public class AssetBundleBuilder : EditorWindow
|
|
{
|
|
private static string outputPath = "ServerData/AssetBundles/Android";
|
|
private static BuildTarget buildTarget = BuildTarget.Android;
|
|
|
|
[MenuItem("Tools/AssetBundles/Build for Android")]
|
|
public static void BuildAssetBundles()
|
|
{
|
|
Debug.Log("=== Custom AssetBundle Builder ===");
|
|
|
|
// Create output directory
|
|
string fullOutputPath = Path.Combine(Application.dataPath, "..", outputPath);
|
|
if (!Directory.Exists(fullOutputPath))
|
|
{
|
|
Directory.CreateDirectory(fullOutputPath);
|
|
Debug.Log($"Created output directory: {fullOutputPath}");
|
|
}
|
|
|
|
// Build options
|
|
BuildAssetBundleOptions options = BuildAssetBundleOptions.ChunkBasedCompression |
|
|
BuildAssetBundleOptions.StrictMode;
|
|
|
|
// Build the bundles
|
|
Debug.Log($"Building AssetBundles to: {fullOutputPath}");
|
|
Debug.Log($"Target platform: {buildTarget}");
|
|
|
|
AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(
|
|
fullOutputPath,
|
|
options,
|
|
buildTarget
|
|
);
|
|
|
|
if (manifest == null)
|
|
{
|
|
Debug.LogError("✗ AssetBundle build failed!");
|
|
EditorUtility.DisplayDialog("Build Failed", "AssetBundle build failed! Check console for errors.", "OK");
|
|
return;
|
|
}
|
|
|
|
Debug.Log("✓ AssetBundles built successfully!");
|
|
|
|
// Generate the JSON catalog
|
|
GenerateCatalog(fullOutputPath, manifest);
|
|
|
|
Debug.Log("=== Build Complete ===");
|
|
EditorUtility.DisplayDialog("Build Complete",
|
|
$"AssetBundles built successfully!\n\nOutput: {fullOutputPath}\n\nNext: Upload to VPS",
|
|
"OK");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generate catalog.json from built AssetBundles
|
|
/// </summary>
|
|
private static void GenerateCatalog(string outputPath, AssetBundleManifest manifest)
|
|
{
|
|
Debug.Log("Generating catalog.json...");
|
|
|
|
var catalog = new RemoteAssetCatalog
|
|
{
|
|
version = Application.version,
|
|
timestamp = System.DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
|
|
baseUrl = "https://assetbundle.uncaptured.co",
|
|
bundles = new List<RemoteAssetCatalog.BundleEntry>()
|
|
};
|
|
|
|
// Get all bundle names
|
|
string[] allBundles = manifest.GetAllAssetBundles();
|
|
|
|
foreach (string bundleName in allBundles)
|
|
{
|
|
string bundlePath = Path.Combine(outputPath, bundleName);
|
|
|
|
if (!File.Exists(bundlePath))
|
|
{
|
|
Debug.LogWarning($"Bundle file not found: {bundlePath}");
|
|
continue;
|
|
}
|
|
|
|
// Get file info
|
|
FileInfo fileInfo = new FileInfo(bundlePath);
|
|
|
|
// Calculate hash
|
|
string hash = CalculateMD5(bundlePath);
|
|
|
|
// Get scenes in this bundle
|
|
var scenePaths = AssetDatabase.GetAssetPathsFromAssetBundle(bundleName);
|
|
var sceneNames = new List<string>();
|
|
|
|
foreach (var scenePath in scenePaths)
|
|
{
|
|
if (scenePath.EndsWith(".unity"))
|
|
{
|
|
string sceneName = Path.GetFileNameWithoutExtension(scenePath);
|
|
sceneNames.Add(sceneName);
|
|
}
|
|
}
|
|
|
|
// Get dependencies
|
|
var dependencies = new List<string>();
|
|
string[] bundleDeps = manifest.GetAllDependencies(bundleName);
|
|
dependencies.AddRange(bundleDeps);
|
|
|
|
// Create bundle entry
|
|
var entry = new RemoteAssetCatalog.BundleEntry
|
|
{
|
|
bundleName = Path.GetFileNameWithoutExtension(bundleName),
|
|
fileName = bundleName,
|
|
hash = hash,
|
|
size = fileInfo.Length,
|
|
scenes = sceneNames,
|
|
dependencies = dependencies
|
|
};
|
|
|
|
catalog.bundles.Add(entry);
|
|
|
|
Debug.Log($" ✓ Added bundle: {bundleName}");
|
|
Debug.Log($" - Size: {fileInfo.Length / 1024f / 1024f:F2} MB");
|
|
Debug.Log($" - Hash: {hash}");
|
|
Debug.Log($" - Scenes: {sceneNames.Count}");
|
|
Debug.Log($" - Dependencies: {dependencies.Count}");
|
|
}
|
|
|
|
// Save catalog as JSON
|
|
string catalogPath = Path.Combine(outputPath, "catalog.json");
|
|
string json = JsonUtility.ToJson(catalog, true);
|
|
File.WriteAllText(catalogPath, json);
|
|
|
|
Debug.Log($"✓ Catalog generated: {catalogPath}");
|
|
Debug.Log($" Total bundles: {catalog.bundles.Count}");
|
|
Debug.Log($" Catalog size: {json.Length / 1024f:F2} KB");
|
|
|
|
// Also save a pretty-printed version for debugging
|
|
string prettyPath = Path.Combine(outputPath, "catalog_readable.json");
|
|
File.WriteAllText(prettyPath, json);
|
|
Debug.Log($"✓ Readable catalog: {prettyPath}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculate MD5 hash of a file
|
|
/// </summary>
|
|
private static string CalculateMD5(string filePath)
|
|
{
|
|
using (var md5 = MD5.Create())
|
|
using (var stream = File.OpenRead(filePath))
|
|
{
|
|
byte[] hash = md5.ComputeHash(stream);
|
|
StringBuilder sb = new StringBuilder();
|
|
foreach (byte b in hash)
|
|
{
|
|
sb.Append(b.ToString("x2"));
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
}
|
|
|
|
[MenuItem("Tools/AssetBundles/Open Output Folder")]
|
|
public static void OpenOutputFolder()
|
|
{
|
|
string fullPath = Path.Combine(Application.dataPath, "..", outputPath);
|
|
if (Directory.Exists(fullPath))
|
|
{
|
|
EditorUtility.RevealInFinder(fullPath);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"Output folder doesn't exist: {fullPath}");
|
|
}
|
|
}
|
|
|
|
[MenuItem("Tools/AssetBundles/Clear Cache")]
|
|
public static void ClearCache()
|
|
{
|
|
if (EditorUtility.DisplayDialog("Clear AssetBundle Cache?",
|
|
"This will delete all cached AssetBundles. Continue?",
|
|
"Yes", "Cancel"))
|
|
{
|
|
Caching.ClearCache();
|
|
Debug.Log("✓ AssetBundle cache cleared");
|
|
}
|
|
}
|
|
|
|
[MenuItem("Tools/AssetBundles/Settings")]
|
|
public static void ShowSettings()
|
|
{
|
|
var window = GetWindow<AssetBundleBuilder>("AssetBundle Builder");
|
|
window.Show();
|
|
}
|
|
|
|
// Editor Window GUI
|
|
void OnGUI()
|
|
{
|
|
GUILayout.Label("Custom AssetBundle Builder", EditorStyles.boldLabel);
|
|
GUILayout.Space(10);
|
|
|
|
EditorGUILayout.HelpBox(
|
|
"This tool builds AssetBundles and generates a JSON catalog for remote loading.\n\n" +
|
|
"1. Mark your scenes/assets with AssetBundle names\n" +
|
|
"2. Click 'Build for Android'\n" +
|
|
"3. Upload ServerData/AssetBundles/Android/ to your VPS",
|
|
MessageType.Info);
|
|
|
|
GUILayout.Space(10);
|
|
|
|
// Output path
|
|
GUILayout.Label("Output Path:", EditorStyles.boldLabel);
|
|
outputPath = EditorGUILayout.TextField(outputPath);
|
|
|
|
GUILayout.Space(5);
|
|
|
|
// Build target
|
|
GUILayout.Label("Build Target:", EditorStyles.boldLabel);
|
|
buildTarget = (BuildTarget)EditorGUILayout.EnumPopup(buildTarget);
|
|
|
|
GUILayout.Space(10);
|
|
|
|
// Build button
|
|
if (GUILayout.Button("Build AssetBundles", GUILayout.Height(40)))
|
|
{
|
|
BuildAssetBundles();
|
|
}
|
|
|
|
GUILayout.Space(5);
|
|
|
|
// Utility buttons
|
|
using (new EditorGUILayout.HorizontalScope())
|
|
{
|
|
if (GUILayout.Button("Open Output Folder"))
|
|
{
|
|
OpenOutputFolder();
|
|
}
|
|
|
|
if (GUILayout.Button("Clear Cache"))
|
|
{
|
|
ClearCache();
|
|
}
|
|
}
|
|
|
|
GUILayout.Space(20);
|
|
|
|
// Info section
|
|
GUILayout.Label("Current Settings:", EditorStyles.boldLabel);
|
|
EditorGUILayout.LabelField("Unity Version:", Application.unityVersion);
|
|
EditorGUILayout.LabelField("App Version:", Application.version);
|
|
EditorGUILayout.LabelField("Company:", Application.companyName);
|
|
|
|
GUILayout.Space(10);
|
|
|
|
// Quick guide
|
|
if (GUILayout.Button("Show Quick Guide"))
|
|
{
|
|
ShowQuickGuide();
|
|
}
|
|
}
|
|
|
|
private static void ShowQuickGuide()
|
|
{
|
|
EditorUtility.DisplayDialog("AssetBundle Quick Guide",
|
|
"STEP 1: Mark Assets for Bundling\n" +
|
|
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" +
|
|
"• Select your Game scene in Project window\n" +
|
|
"• In Inspector, find 'AssetBundle' dropdown (bottom)\n" +
|
|
"• Select 'New...' and name it 'gamescene'\n\n" +
|
|
|
|
"STEP 2: Build AssetBundles\n" +
|
|
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" +
|
|
"• Tools → AssetBundles → Build for Android\n" +
|
|
"• Wait for build to complete\n" +
|
|
"• Files created in ServerData/AssetBundles/Android/\n\n" +
|
|
|
|
"STEP 3: Upload to VPS\n" +
|
|
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" +
|
|
"• scp -r ServerData/AssetBundles/Android/* user@server:/var/www/AssetBundles/Android/\n\n" +
|
|
|
|
"STEP 4: Update Your Code\n" +
|
|
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" +
|
|
"• Replace Addressables calls with CustomAssetBundleSceneLoader\n" +
|
|
"• Build APK and test!",
|
|
"Got it!");
|
|
}
|
|
}
|