Skip to content

Instantly share code, notes, and snippets.

@shane-harper
Last active March 9, 2019 13:00
Show Gist options
  • Save shane-harper/fe41b20c70db0420cbd65ab7443f337b to your computer and use it in GitHub Desktop.
Save shane-harper/fe41b20c70db0420cbd65ab7443f337b to your computer and use it in GitHub Desktop.
Asset Bundler - A simple tool for handling asset bundles and testing in editor without building.
/// NOTE
/// After creating this script, I discovered Addressables. Which does a similar thing, but has many more features!
/// Check them out here: https://forum.unity.com/threads/addressables-are-here.536304/
//#define USE_BUNDLES
using System.Collections;
using UnityEngine;
#if UNITY_EDITOR && !USE_BUNDLES
using UnityEditor;
using System.IO;
#endif
public class AssetBundler : MonoBehaviour
{
public delegate void OnLoadComplete<T>(T asset);
#if UNITY_EDITOR
public const string RootBundlesPath = "Assets/AssetBundles/Bundles";
#endif
private static MonoBehaviour _coroutineHandler;
private static MonoBehaviour CoroutineHandler
{
get
{
if (_coroutineHandler != null) return _coroutineHandler;
var go = new GameObject("AssetBundler") {hideFlags = HideFlags.HideInHierarchy};
_coroutineHandler = go.AddComponent<AssetBundler>();
DontDestroyOnLoad(go);
return _coroutineHandler;
}
}
public static void GetAsset<T>(string path, string id, out T asset) where T : Object
{
#if UNITY_EDITOR && !USE_BUNDLES
path = $"{RootBundlesPath}/{path}/";
var fileEntries = Directory.GetFiles(path);
asset = null;
foreach(var fileName in fileEntries)
{
var t = AssetDatabase.LoadAssetAtPath<T>(fileName);
if (t.name != id) continue;
asset = t;
break;
}
#else
path = $"{Application.streamingAssetsPath}/{path}";
var bundle = AssetBundle.LoadFromFile(path.ToLower());
asset = bundle.LoadAsset<T>(id);
bundle.Unload(false);
#endif
}
public static Coroutine GetAssetAsync<T>(string path, string id, OnLoadComplete<T> onComplete) where T : Object
{
return CoroutineHandler.StartCoroutine(LoadAsset(path, id, onComplete));
}
public static void CancelRequest(Coroutine coroutine)
{
CoroutineHandler.StopCoroutine(coroutine);
}
private static IEnumerator LoadAsset<T>(string path, string id, OnLoadComplete<T> onComplete) where T : Object
{
if (onComplete == null) yield break;
#if UNITY_EDITOR && !USE_BUNDLES
GetAsset(path, id, out T asset);
onComplete(asset);
#else
path = $"{Application.streamingAssetsPath}/{path}";
var load = AssetBundle.LoadFromFileAsync(path.ToLower());
yield return load;
var bundle = load.assetBundle;
// Get asset and return
var asset = bundle.LoadAsset<T>(id);
onComplete(asset);
// Cleanup
bundle.Unload(false);
#endif
}
}
using System.IO;
using UnityEditor;
public static class AssetBundlerEditor
{
private const string StreamingAssets = "Assets/StreamingAssets";
private const BuildAssetBundleOptions BuildOptions = BuildAssetBundleOptions.ChunkBasedCompression;
[MenuItem("Assets/Asset Bundles/Build Android")]
public static void Build_Android()
{
Build(BuildTarget.Android);
}
[MenuItem("Assets/Asset Bundles/Build iOS")]
public static void Build_iOS()
{
Build(BuildTarget.iOS);
}
private static void Build(BuildTarget platform)
{
if (Directory.Exists(StreamingAssets)) Directory.Delete(StreamingAssets, true);
Directory.CreateDirectory(StreamingAssets);
UpdateBundlePaths();
BuildPipeline.BuildAssetBundles(StreamingAssets, BuildOptions, platform);
}
private static void UpdateBundlePaths()
{
void UpdateSubDirectories(string directory)
{
var subDirectories = Directory.GetDirectories(directory);
foreach (var subDirectory in subDirectories)
{
var assetImporter = AssetImporter.GetAtPath(subDirectory);
assetImporter.assetBundleName = subDirectory.Substring(AssetBundler.RootBundlesPath.Length + 1);
assetImporter.SaveAndReimport();
UpdateSubDirectories(subDirectory);
}
}
UpdateSubDirectories(AssetBundler.RootBundlesPath);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment