[官方文档] AssetBundles
[官方文档] BuildPipeline
[官方文档] BuildOptions
导资源工具 (Unity 2019)
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEditor;
/// <summary>
/// 资源工具
/// 放到Assets/Editor文件夹下
/// </summary>
public class AssetsToolEditor : Editor
{
[MenuItem("Assets/Build/Build Model")]
public static void BuildModelItem()
{
string export_folder = Application.streamingAssetsPath + "/models";
Object[] objects = Selection.objects;
for (int i = 0; i < objects.Length; i++)
BuildModel(export_folder, objects[i]);
}
[MenuItem("Assets/Build/Build Texture")]
public static void BuildTextureItem()
{
string export_folder = Application.streamingAssetsPath + "/textures";
Object[] objects = Selection.objects;
for (int i = 0; i < objects.Length; i++)
BuildTexture(export_folder, objects[i]);
}
[MenuItem("Assets/Build/Build Prefab")]
public static void BuildPrefabItem()
{
string export_folder = Application.streamingAssetsPath + "/prefabs";
Object[] objects = Selection.objects;
for (int i = 0; i < objects.Length; i++)
BuildPrefab(export_folder, objects[i]);
}
[MenuItem("Assets/Build/Build Scriptable")]
public static void BuildScriptableItem()
{
string export_folder = Application.streamingAssetsPath + "/assets";
Object[] objects = Selection.objects;
for (int i = 0; i < objects.Length; i++)
BuildScriptableObject(export_folder, objects[i]);
}
[MenuItem("Assets/Build/Build SpriteAtlas")]
public static void BuildSpriteAtlasItem()
{
string export_folder = Application.streamingAssetsPath + "/atlas";
Object[] objects = Selection.objects;
for (int i = 0; i < objects.Length; i++)
BuildSpriteAtlas(export_folder, objects[i]);
}
[MenuItem("Assets/Build/Build TextAsset")]
public static void BuildTextAssetItem()
{
string export_folder = Application.streamingAssetsPath + "/text";
Object[] objects = Selection.objects;
for (int i = 0; i < objects.Length; i++)
BuildTextAsset(export_folder, objects[i]);
}
[MenuItem("Assets/Build/Build Lua")]
public static void BuildLuaTextAssetItem()
{
string export_folder = Application.streamingAssetsPath + "/lua";
Object[] objects = Selection.objects;
BuildLuaTextAsset(export_folder, objects);
}
[MenuItem("Assets/Build/Build Scene")]
public static void BuildSceneItem()
{
string export_folder = Application.streamingAssetsPath + "/scene";
Object[] objects = Selection.objects;
BuildSceneAsset(export_folder, objects);
}
// Build Model
public static void BuildModel(string export_folder, Object asset)
{
BuildAsset(export_folder, asset, "model");
}
// Build Texture
public static void BuildTexture(string export_folder, Object asset)
{
BuildAsset(export_folder, asset, "tex");
}
// Build Prefab
public static void BuildPrefab(string export_folder, Object asset)
{
BuildAsset(export_folder, asset, "prefab");
}
// Build ScriptableObject
public static void BuildScriptableObject(string export_folder, Object asset)
{
string[] assetNames = AssetDatabase.GetDependencies(AssetDatabase.GetAssetPath(asset));
string[] assetNames1 = new string[assetNames.Length - 1];
int j = 0;
for (int i = 0; i < assetNames.Length; i++)
//删除依赖资源中的同名脚本,否则打包会报错。
//报错信息: Script asset "Assets/XXX/XXXX/XXXX.cs" cannot be included into AssetBundle "XXX".
if (!assetNames[i].EndsWith(asset.name + ".cs"))
assetNames1[j++] = assetNames[i];
BuildAsset(export_folder, asset, "asset", assetNames1);
}
// Build SpriteAtlas
public static void BuildSpriteAtlas(string export_folder, Object asset)
{
BuildAsset(export_folder, asset, "atlas");
}
// Build TextAsset
public static void BuildTextAsset(string export_folder, Object asset)
{
asset.name = TrimPostfix(asset.name);
BuildAsset(export_folder, asset, "txt");
}
// Build Lua File
public static void BuildLuaTextAsset(string export_folder, Object[] assets)
{
BuildAsset(export_folder, assets, "app", "lua");
}
// Build Scene
public static void BuildSceneAsset(string export_folder, Object[] assets)
{
string[] scenes = new string[assets.Length];
for (int i = 0; i < assets.Length; i++)
scenes[i] = AssetDatabase.GetAssetPath(assets[i]);
BuildScene(export_folder, scenes);
}
// 去掉文件名后缀
public static string TrimPostfix(string name)
{
if (string.IsNullOrEmpty(name))
return name;
int index = name.IndexOf('.');
if (index == -1)
return name;
return name.Substring(0, index);
}
// 设置资源的AssetBundle信息
public static void SetAssetBundleNameAndVariant(Object asset, string bundle_name, string bundle_variant)
{
AssetImporter importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(asset));
if (importer == null)
return;
importer.SetAssetBundleNameAndVariant(bundle_name, bundle_variant);
}
// 将单个资源打成一个包
public static void BuildAsset(string export_folder, Object asset, string variant, string[] assetNames = null)
{
string bundleName = TrimPostfix(asset.name);
Object[] assets = new Object[] { asset };
BuildAsset(export_folder, assets, bundleName, variant);
}
// 将一组资源打成一个包
public static void BuildAsset(string export_folder, Object[] assets, string bundleName, string variant)
{
if (!Directory.Exists(export_folder))
{
Directory.CreateDirectory(export_folder);
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
}
List<string> assetNames = new List<string>();
List<string> addressableNames = new List<string>();
for (int i=0; i<assets.Length; i++)
{
Object asset = assets[i];
string assetName = AssetDatabase.GetAssetPath(assets[i]);
string addressableName = Path.GetFileNameWithoutExtension(assetName);
assetNames.Add(assetName);
addressableNames.Add(addressableName);
SetAssetBundleNameAndVariant(asset, TrimPostfix(asset.name), variant);
}
AssetBundleBuild abb = new AssetBundleBuild();
abb.assetBundleName = bundleName;
abb.assetBundleVariant = variant;
//要打包到当前AB包中的资源path
//加载: bundle.LoadAsset(assetNames[0]);
abb.assetNames = assetNames.ToArray();
//为AB中每个资源设置昵称,方便加载
//加载:bundle.LoadAsset(addressableNames[0]);
abb.addressableNames = addressableNames.ToArray();
BuildAssetBundleOptions options = BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.DeterministicAssetBundle;
BuildPipeline.BuildAssetBundles(export_folder, new AssetBundleBuild[] { abb }, options, EditorUserBuildSettings.activeBuildTarget);
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
Debug.LogFormat("{0}/{1}.{2}", export_folder, abb.assetBundleName, abb.assetBundleVariant);
DeleteManifest(export_folder, abb.assetBundleName, abb.assetBundleVariant);
}
// 删除生成的manifest文件
public static void DeleteManifest(string export_folder, string assetBundleName, string assetBundleVariant)
{
export_folder = export_folder.Substring(export_folder.LastIndexOf("/Assets/") + 1);
AssetDatabase.DeleteAsset(string.Format("{0}/{1}.{2}.manifest", export_folder, assetBundleName.ToLower(), assetBundleVariant));
string folder_name = export_folder.Substring(export_folder.LastIndexOf("/") + 1);
AssetDatabase.DeleteAsset(string.Format("{0}/{1}.manifest", export_folder, folder_name));
AssetDatabase.DeleteAsset(string.Format("{0}/{1}", export_folder, folder_name));
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
}
// 打包多个场景
public static void BuildScene(string export_folder, string[] scenes)
{
if (!Directory.Exists(export_folder))
{
Directory.CreateDirectory(export_folder);
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
}
foreach (string scene in scenes)
BuildScene(export_folder, scene);
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
}
// 打包单个场景
private static void BuildScene(string export_folder, string scene)
{
string assetName = Path.GetFileNameWithoutExtension(scene);
string locationPathName = string.Format("{0}/{1}.scene", export_folder, assetName);
BuildPlayerOptions option = new BuildPlayerOptions();
//例如 ["Assets/Scenes/Sample.unity",...]
option.scenes = new string[] { scene };
option.locationPathName = locationPathName;
option.target = EditorUserBuildSettings.activeBuildTarget;
option.options = BuildOptions.BuildAdditionalStreamedScenes;
BuildPipeline.BuildPlayer(option);
Debug.Log(locationPathName);
}
}