Created
April 20, 2017 07:38
-
-
Save twsiyuan/b919031bd50f1b9bc7aa9cd06762079f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
[Serializable] | |
class AssetBundleLoadConfigs | |
{ | |
public AssetBundleLoadData[] AssetBundles; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using UnityEngine; | |
[Serializable] | |
struct AssetBundleLoadData | |
{ | |
public string Name; | |
public string Hash; | |
public uint CRC; | |
public Hash128 Hash128 | |
{ | |
get | |
{ | |
return Hash128.Parse(this.Hash); | |
} | |
set | |
{ | |
this.Hash = value.ToString(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static class BuildExample | |
{ | |
[MenuItem("Tools/Build Windows64")] | |
static void BuildWindows64() | |
{ | |
var path = Path.GetFullPath(Application.dataPath + "/../Builds/Windows64/" + Application.productName + ".exe"); | |
BuildProject(path, BuildTarget.StandaloneWindows64); | |
} | |
[MenuItem("Tools/Build Android")] | |
static void BuildAndroid() | |
{ | |
var path = Path.GetFullPath(Application.dataPath + "/../Builds/Android/" + Application.productName + ".apk"); | |
BuildProject(path, BuildTarget.Android); | |
} | |
const string AssetBundleExtension = ".assetbundle"; | |
const string DefaultAssetBundleName = "base"; | |
const string ScenesAssetBundleName = "scenes"; | |
static string[] CollectScenesPathWithoutEntry() | |
{ | |
var paths = new List<string>(EditorBuildSettings.scenes.Where(v => v.enabled).Select(v => v.path)); | |
paths.RemoveAt(0); | |
return paths.ToArray(); | |
} | |
static AssetBundleManifest BuildAssetBundles(string outputPath, BuildTarget buildTarget, BuildAssetBundleOptions buildAssetBundleOptions = BuildAssetBundleOptions.None) | |
{ | |
// Data strcuture & function define | |
var buildAssetBundles = new Dictionary<string, List<string>>(); | |
var isAssetCollected = (Func<string, bool>)((assetPath) => { | |
foreach (var assetBundle in buildAssetBundles) | |
{ | |
if (assetBundle.Value.Contains(assetPath)) | |
{ | |
return true; | |
} | |
} | |
return false; | |
}); | |
var collectAsset = (Action<string, string>)((assetPath, assetBundleName) => | |
{ | |
if (!isAssetCollected(assetPath)) | |
{ | |
var assetsList = (List<string>)null; | |
if (!buildAssetBundles.TryGetValue(assetBundleName, out assetsList)) | |
{ | |
assetsList = new List<string>(); | |
buildAssetBundles.Add(assetBundleName, assetsList); | |
} | |
assetsList.Add(assetPath); | |
} | |
}); | |
var toAssetBundleBuilds = (Func<AssetBundleBuild[]>)(() => | |
{ | |
var builds = new AssetBundleBuild[buildAssetBundles.Count]; | |
var i = 0; | |
foreach (var itr in buildAssetBundles) | |
{ | |
builds[i] = new AssetBundleBuild() | |
{ | |
assetBundleName = itr.Key, | |
assetNames = itr.Value.ToArray(), | |
}; | |
i += 1; | |
} | |
return builds; | |
}); | |
// For each dependencies assets | |
var scenePaths = CollectScenesPathWithoutEntry(); | |
foreach (var assetPath in AssetDatabase.GetDependencies(scenePaths)) | |
{ | |
if (assetPath.StartsWith("Assets/") && Path.GetExtension(assetPath) != ".cs") | |
{ | |
var importer = AssetImporter.GetAtPath(assetPath); | |
var bundleName = string.IsNullOrEmpty(importer.assetBundleName) ? DefaultAssetBundleName : importer.assetBundleName; | |
collectAsset(assetPath, bundleName + AssetBundleExtension); | |
} | |
} | |
var assetBundleBuilds = new List<AssetBundleBuild>(toAssetBundleBuilds()); | |
assetBundleBuilds.Add(new AssetBundleBuild | |
{ | |
assetBundleName = ScenesAssetBundleName + AssetBundleExtension, | |
assetNames = CollectScenesPathWithoutEntry(), | |
}); | |
return BuildPipeline.BuildAssetBundles(outputPath, assetBundleBuilds.ToArray(), buildAssetBundleOptions, buildTarget); | |
} | |
static string[] GetAssetBundleNamesInLoadOrder(AssetBundleManifest manifest) | |
{ | |
var assetBundleRefs = new Dictionary<string, int>(); | |
foreach (var assetBundle in manifest.GetAllAssetBundles()) | |
{ | |
assetBundleRefs.Add(assetBundle, 0); | |
} | |
foreach (var assetBundle in manifest.GetAllAssetBundles()) | |
{ | |
foreach (var depAssetBundle in manifest.GetAllDependencies(assetBundle)) | |
{ | |
assetBundleRefs[depAssetBundle] += 1; | |
} | |
} | |
return assetBundleRefs.OrderByDescending(kp => kp.Value).Select(v => v.Key).ToArray(); | |
} | |
static bool GetAssetBundleHashAndCRC(string outputPath, string assetBundleName, out Hash128 hash, out uint crc) | |
{ | |
var assetBundlePath = Path.GetFullPath(outputPath) + Path.DirectorySeparatorChar + assetBundleName; | |
if (!BuildPipeline.GetHashForAssetBundle(assetBundlePath, out hash)) | |
{ | |
crc = 0; | |
return false; | |
} | |
if (!BuildPipeline.GetCRCForAssetBundle(assetBundlePath, out crc)) | |
{ | |
return false; | |
} | |
return true; | |
} | |
static AssetBundleLoadConfigs GenerateLoadConfigs(string manifestDir, AssetBundleManifest manifest, string configsName = "configs.json") | |
{ | |
var assetBundleNames = GetAssetBundleNamesInLoadOrder(manifest); | |
var assetBundleLoads = new List<AssetBundleLoadData>(assetBundleNames.Length); | |
foreach (var assetBundleName in assetBundleNames) | |
{ | |
Hash128 hash; | |
uint crc; | |
if (!GetAssetBundleHashAndCRC(manifestDir, assetBundleName, out hash, out crc)) | |
{ | |
throw new Exception("Cannot find assetBundle - " + assetBundleName); | |
} | |
assetBundleLoads.Add(new AssetBundleLoadData() | |
{ | |
Name = assetBundleName, | |
Hash128 = hash, | |
CRC = crc, | |
}); | |
} | |
var configs = new AssetBundleLoadConfigs() | |
{ | |
AssetBundles = assetBundleLoads.ToArray(), | |
}; | |
var configsPath = Path.GetFullPath(manifestDir) + Path.DirectorySeparatorChar + configsName; | |
File.WriteAllText(configsPath, JsonUtility.ToJson(configs)); | |
return configs; | |
} | |
static void BuildProject(string outputPath, BuildTarget buildTarget = BuildTarget.Android, BuildOptions buildOptions = BuildOptions.None, BuildAssetBundleOptions buildAssetBundleOptions = BuildAssetBundleOptions.None) | |
{ | |
// Check output path | |
var bundleOutputDir = Path.GetFullPath(Path.GetDirectoryName(outputPath)); | |
var playerOutputPath = outputPath; | |
if (!Directory.Exists(bundleOutputDir)) | |
{ | |
Directory.CreateDirectory(bundleOutputDir); | |
} | |
// Build assetbundles | |
var manifest = BuildAssetBundles(bundleOutputDir, buildTarget, buildAssetBundleOptions); | |
GenerateLoadConfigs(bundleOutputDir, manifest); | |
// Build Player | |
var bundleManifestPath = bundleOutputDir + Path.DirectorySeparatorChar + Path.GetFileName(bundleOutputDir) + ".manifest"; | |
var buildPlayerOptions = new BuildPlayerOptions() | |
{ | |
target = buildTarget, | |
scenes = new string[] { EditorBuildSettings.scenes.Where(v => v.enabled).Select(v => v.path).First() }, | |
options = buildOptions, | |
locationPathName = playerOutputPath, | |
assetBundleManifestPath = bundleManifestPath, | |
}; | |
var result = BuildPipeline.BuildPlayer(buildPlayerOptions); | |
if (!string.IsNullOrEmpty(result)) | |
{ | |
throw new Exception(result); | |
} | |
// Open folder if not batch mode | |
if (!UnityEditorInternal.InternalEditorUtility.inBatchMode) | |
{ | |
System.Diagnostics.Process.Start(bundleOutputDir); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment