Сценарій експорту Asset Bundle для простого створення DLC

Оновлення від 6.11.2015

Цей сценарій актуальний для Unity 4. Unity 5 має нову функцію для створення пакетів активів.

 

Я написав простий сценарій редактора для легкого створення AssetBundle.

Автор: Сергій Тарабан

:ad:

Цей сценарій редактора я використовував як частину моєї ігрової системи DLC.

Функції

Поточна версія 1.0. Він має:
  • додавання змагань за допомогою перетягування
  • збереження та завантаження списку вмісту
  • автоматичне розділення AssetBundle із використанням максимального розміру
  • вибір цільової платформи
  • додавання папки вмісту
  • Створення файлу дампа вмісту AssetBundle
  • Перевірка AssetBundle (тільки для нестиснених пакетів активів)

Сценарій

Цей сценарій є сценарієм редактора, тому він має бути в папці Assets/Scripts/Editor. Сценарій розповсюджується за ліцензією Массачусетського технологічного інституту, тож ви можете робити все, що забажаєте, окрім зміни моїх авторських прав. Найближчим часом я збираюся додати деякі додаткові функції, якщо у мене буде вільний час.  Не соромтеся писати мені про помилки, які ви знайдете, або про функції, які вам потрібні.

AssetBundleExporter

Завантажити сценарій: AssetBundleExporter.cs

// AssetBundle Exporter v.1.0
// Copyright (C) 2013 Сергій Тарабан 
//
// Цим надається безкоштовний дозвіл будь-якій особі, яка отримує копію цього програмного забезпечення та пов’язаних файлів документації («Програмне забезпечення»), працювати з Програмним забезпеченням без обмежень, включаючи, без обмежень, права на використання, копіювання, зміну, об’єднання, публікацію, розповсюдження, субліцензування та/або продаж копій Програмного забезпечення, а також дозволяти особам, яким надано Програмне забезпечення, робити це за таких умов:
// Наведене вище повідомлення про авторські права та це повідомлення про дозвіл мають бути включені до всіх копій або значних частин Програмного забезпечення.
// ПРОГРАМНЕ ЗАБЕЗПЕЧЕННЯ НАДАЄТЬСЯ «ЯК Є», БЕЗ БУДЬ-ЯКИХ ГАРАНТІЙ, ЯВНИХ АБО НЕПРЯМИХ, ВКЛЮЧАЮЧИ, АРЕМЕ ОБМЕЖУЮЧИСЬ, ГАРАНТІЇ ПРИДАТНОСТІ ДЛЯ ПРОДАЖУ, ВІДПОВІДНОСТІ ДЛЯ КОНКРЕТНОЇ МЕТИ ТА ВІДСУМНОСТІ ПРАВ. АВТОРИ АБО ВЛАСНИКИ АВТОРСЬКИХ ПРАВ НЕ НЕСУТЬ ВІДПОВІДАЛЬНОСТІ ЗА БУДЬ-ЯКІ ПРЕТЕНЗІЇ, ЗБИТКИ АБО ІНШУ ВІДПОВІДАЛЬНІСТЬ В наслідок КОНТРАКТНОЇ ДІЇ, ДЕЛІКТУ ЧИ В ІНШОМУ ВИПАДКУ, ЩО ВИНИКАЄ ПРОГРАМНЕ ЗАБЕЗПЕЧЕННЯ, ВИКОРИСТАННЯ АБО ІНШИМИ ОПЕРАЦІЯМИ, ЧИ У ЗВ’ЯЗКУ З НИМ ПРОГРАМНЕ ЗАБЕЗПЕЧЕННЯ.
//

за допомогою UnityEngine;
за допомогою UnityEditor;
використання System.Collections;
використання System.Collections.Generic;
за допомогою System.IO;
за допомогою System.IO.Compression;

відкритий клас AssetBundleExporter : EditorWindow 
{
	static int FileVersion = 1;
	static string[] ForbidenExtensions = {".meta"};
	bool mMakeCompressedAsset = false;
	bool mSplitPacksGroup = true;
	bool mDumpExportedFilesInFile = істина;
	bool mVerifyAssetBundleAfterBuild = істина;
	float mSplitPacksSize = 2.0f; //2 мбenum ETARGET_PLATFORM { 
		Поточний = 0, 
		iOS = BuildTarget.iPhone, 
		Android = BuildTarget.Android,
		WindowsPhone = BuildTarget.WP8Player,
		WebPlayer = BuildTarget.WebPlayer,
		MacOS = BuildTarget.StandaloneOSXUniversal,
		Windows = BuildTarget.StandaloneWindows,
		Linux = BuildTarget.StandaloneLinuxUniversal
	}
	ETARGET_PLATFORM mTargetPlatform;

	рядок splitPacksSizeStr = "2.0";
	статичне вікно AssetBundleExporter = null;
	Vector2 scrollPosition = Vector2.zero;
	рядок mStatusText = "";

	List mObjectsPathList = new List();
	static List mExcludeFileExt = new List();

	// Додати меню під назвою «Моє вікно» до меню «Вікно».
	[Пункт меню ("Експортер Window/AssetBundle")]
	static void Init () 
	{
		mExcludeFileExt.AddRange(ForbidenExtensions);

		// Отримати існуюче відкрите вікно або, якщо немає, створити нове:
		window = (AssetBundleExporter)EditorWindow.GetWindow (typeof (AssetBundleExporter));
	}

	недійсний OnGUI () 
	{
		ProcessDragAndDrop();

		//область параметрів
		mMakeCompressedAsset = EditorGUILayout.Toggle("Зробити стиснутий ресурс", mMakeCompressedAsset);
		mDumpExportedFilesInFile = EditorGUILayout.Toggle("Виводити імена файлів у файл", mDumpExportedFilesInFile);
		mVerifyAssetBundleAfterBuild = EditorGUILayout.Toggle("Перевірити пакети ресурсів", mVerifyAssetBundleAfterBuild);
		mTargetPlatform = (ETARGET_PLATFORM)EditorGUILayout.EnumPopup("Цільова платформа", mTargetPlatform);
		mSplitPacksGroup = EditorGUILayout.BeginToggleGroup ("Розмір розділених пакетів (.mb)", mSplitPacksGroup);
		splitPacksSizeStr = EditorGUILayout.TextArea(splitPacksSizeStr);
		mSplitPacksSize = float.Parse(splitPacksSizeStr);
		mSplitPacksSize *= 1000000.0f;
		EditorGUILayout.EndToggleGroup ();

		// область списку шляху до файлу
		GUILayout.BeginHorizontal();
		scrollPosition = GUILayout.BeginScrollView(scrollPosition, GUILayout.Width( window.position.width), GUILayout.Height( window.position.height-150 ));
		рядок objPathList = "";
		foreach(вар. obj у mObjectsPathList) 
		{
			objPathList += obj + "\n";
		}
		GUILayout.Label(objPathList);

		GUILayout.EndScrollView();
		GUILayout.EndVertical();

		//область кнопки
		GUILayout.BeginHorizontal();
		if(GUILayout.Button("Зберегти")) 
		{
			string fileListPath = EditorUtility.SaveFilePanel ("Зберегти список файлів", "", "dlc_file_list", "txt");
			using(StreamWriter writer = new StreamWriter(fileListPath, false))
			{
				writer.WriteLine(FileVersion.ToString());
				foreach(вар. objPath у mObjectsPathList)
				{
					writer.WriteLine(objPath);
				}
			}

		}
		if(GUILayout.Button("Завантажити")) 
		{
			mObjectsPathList.Clear();
			string fileListPath = EditorUtility.OpenFilePanel ("Завантажити список файлів", "", "txt");
			using(StreamReader reader = new StreamReader(fileListPath, false))
			{
				string fileVersion = reader.ReadLine();
				if(fileVersion != FileVersion.ToString()) {
					LogToWindow("Файл має невідомий формат. Не вдалося завантажити");
					повернення;
				}
				while(!reader.EndOfStream)
				{
					mObjectsPathList.Add(reader.ReadLine());
				}
			}
		}
		if(GUILayout.Button("Очистити")) 
		{
			mObjectsPathList.Clear();
		}
		if(GUILayout.Button("Створити")) 
		{
			string assetBundleFileName = EditorUtility.SaveFilePanel ("Зберегти AssetBundle", "", "AssetBundle", "unity3d");
			якщо (mSplitPacksGroup) 
			{
				GenerateAssetBundles(assetBundleFileName);
			}
			інше
			{
				BuildAssetBundle(assetBundleFileName, mObjectsPathList);
			}
		}

		GUILayout.EndHorizontal();

	}

	void LogToWindow(строковий текст) {
		mStatusText = текст;
		Debug.Log(текст);
	}//Генеруйте багато пакетів ресурсів за допомогою mObjectsList і mSplitPacksSize
	void GenerateAssetBundles(рядок assetFileName) 
	{
		float sizeCounter = 0;
		int bundleCounter = 0;
		int counter = 0;
		List filesForBundle = new List();
		foreach (змінна filepath у mObjectsPathList) 
		{
			лічильник++;
			рядок fullFilePath = GetFullPath(шлях до файлу);
			FileInfo finfo = new FileInfo(fullFilePath);
			sizeCounter += finfo.Length;
			filesForBundle.Add(шлях до файлу);
			bool isLastAsset = counter == mObjectsPathList.Count;
			if(sizeCounter >= mSplitPacksSize || isLastAsset)
			{
				рядок assetBundleFileName = Path.Combine(Path.GetDirectoryName(assetFileName), Path.GetFileNameWithoutExtension(assetFileName));
				assetBundleFileName = assetBundleFileName + "_" + bundleCounter.ToString() + Path.GetExtension(assetFileName);

				RemoveOldAssetBundle(assetBundleFileName);
				BuildAssetBundle(assetBundleFileName, filesForBundle);
				filesForBundle.Clear();
				bundleCounter++;
				sizeCounter = 0;
			}
		}
	}

	//
	void BuildAssetBundle(string assetFilePath, List filesForAsset)
	{
		if(filesForAsset.Count == 0) {
			LogToWindow("Помилка створення набору активів. Немає файлів для включення");
			повернення;
		}

		//створення списку об'єктів
		List objList = new List();
		foreach (змінна filepath у filesForAsset) 
		{
			Object obj = AssetDatabase.LoadMainAssetAtPath(шлях до файлу);
			if(obj != null)
			{
				objList.Add(obj);
			}
		}

		//будуємо AssetBundle
		спробувати {
			Параметри BuildAssetBundleOptions = BuildAssetBundleOptions.CompleteAssets;
			параметри |= BuildAssetBundleOptions.CollectDependencies;
			if(!mMakeCompressedAsset) {
				параметри |= BuildAssetBundleOptions.UncompressedAssetBundle;
			}
			if(mTargetPlatform != ETARGET_PLATFORM.Current) {
				BuildPipeline.BuildAssetBundle(objList[0], objList.ToArray(), assetFilePath, параметри, (BuildTarget)mTargetPlatform);
			}
			інше
			{
				BuildPipeline.BuildAssetBundle(objList[0], objList.ToArray(), assetFilePath, параметри);
			}
		}
		catch (System.Exception ex) 
		{
			LogToWindow("Не вдалося створити пакет активів із помилкою: " + ex.Message);
			повернення;
		}

		//скинути у файл
		якщо (mDumpExportedFilesInFile) 
		{
			using(StreamWriter writer = new StreamWriter(assetFilePath + ".txt", false))
			{
				foreach(перемінна obj у списку obj)
				{
					шлях до рядка = AssetDatabase.GetAssetPath(obj);
					string nameWithExt = Path.GetFileName(path);
					writer.WriteLine(nameWithExt);
				}
			}
		}

		// перевірка набору активів
		if(mVerifyAssetBundleAfterBuild && !mMakeCompressedAsset) 
		{
			bool res = TestAssetBundle(assetFilePath, objList.ToArray());
			if(res) {
				//LogToWindow("Пакет активів пройшов перевірки");
			}
			інше 
			{
				LogToWindow("Подано перевірку Asset Bundle. Asset Bundle може бути недійсним");
			}
		}

		LogToWindow("Пакет активів створено");
	}

	//
	void RemoveOldAssetBundle(рядок assetFilePath)
	{
		File.Delete(assetFilePath);
	}

	//
	void ProcessDragAndDrop() 
	{
		Подія evt = Event.current;
		перемикач (тип EVT) 
		{
		case EventType.DragUpdated:
		case EventType.DragPerform:
			DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
			якщо (evt.type == EventType.DragPerform) 
			{
				DragAndDrop.AcceptDrag ();

				//розпакувати каталоги
				foreach(змінний шлях у DragAndDrop.paths) 
				{
					// Побудувати системний шлях папки активів
					string dataPath = Application.dataPath; 
					string fullPath = GetFullPath(path);

					if(mObjectsPathList.Contains(path)) 
					{
						продовжити;
					}if(!IsDirectory(fullPath)) 
					{
						mObjectsPathList.Add(шлях);
						продовжити;
					}

					// отримати шляхи системних файлів до всіх файлів у папці активів
					string[] filePaths = Directory.GetFiles(fullPath);

					// перераховувати список файлів, завантажуючи активи, які вони представляють, і отримувати їх тип
					foreach (рядок filepath у filePaths) 
					{
						if(IsForbidenExtension(filepath)) {
							продовжити;
						}

						якщо (mObjectsPathList.Contains(шлях до файлу)) 
						{
							продовжити;
						}

						string relPath = filepath.Substring(dataPath.Length-6);
						mObjectsPathList.Add(relPath);
					}
				}
			}
			розрив;
		}
	}

	bool TestAssetBundle(рядок assetPath, Object[] objList){
		// Зачекайте, поки система кешування буде готова
		Комплект AssetBundle = AssetBundle.CreateFromFile(assetPath);
		if(bundle == null) {
			Debug.Log("Не вдалося завантажити пакет активів для тестування.");
			повернути false;
		}

		int errorObjects = 0;
		foreach(перемінна obj у списку obj)
		{
			шлях до рядка = AssetDatabase.GetAssetPath(obj);
			string nameWithoutExt = Path.GetFileNameWithoutExtension(path);
			Об’єкт testobj = bundle.Load(nameWithoutExt);
			if(testobj == null) {
				errorObjects++;
			}
		}
		if(errorObjects > 0) {
			Debug.Log("Набір активів містить недійсні об'єкти: " + errorObjects.ToString() );
			повернути false;
		}

		повернути істину;
	}

	bool IsForbidenExtension(рядковий шлях) 
	{
		string fileExt = Path.GetExtension(path);
		return mExcludeFileExt.Contains(fileExt);
	}

	bool IsDirectory (рядковий шлях)
	{
		System.IO.FileAttributes fa = System.IO.File.GetAttributes(шлях);
		bool isDirectory = false;
		if ((fa & FileAttributes.Directory) != 0)
		{
			isDirectory = true;
		}
		return isDirectory;
	}

	string GetFullPath(string relPath)
	{
		string dataPath = Application.dataPath; 
		string fullPath = Path.Combine(dataPath.Substring(0, dataPath.Length - 6), relPath);
		повернути fullPath;
	}
}

Як використовувати

  1. Перетягніть папку або кілька вибраних файлів із вікна проекту у вікно редактора сценаріїв
  2. Натисніть кнопку «Створити», щоб створити пакет ресурсів
  3. Виберіть розташування та назву AssetBundle, а потім натисніть «Зберегти»
Натисніть кнопку «Зберегти», щоб зберегти список файлів у текстовий файл. Натисніть кнопку Завантажити, щоб завантажити інший список файлів із текстового файлу. Ви також можете змінити текстовий файл вручну.

Пов’язані публікації