initial commit
This commit is contained in:
parent
6715289efe
commit
788c3389af
37645 changed files with 2526849 additions and 80 deletions
|
@ -0,0 +1,8 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Unity.ScriptableBuildPipeline.Editor.Tests")]
|
||||
[assembly: InternalsVisibleTo("Unity.ScriptableBuildPipeline.Test.Fixtures")]
|
||||
[assembly: InternalsVisibleTo("PerformanceTests.Editor")]
|
||||
[assembly: InternalsVisibleTo("SBPDebug.Editor")]
|
||||
[assembly: InternalsVisibleTo("SBPDebug.Editor.Tests")]
|
||||
[assembly: InternalsVisibleTo("Unity.Addressables.Editor")]
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f13538c0e661bcc4c979c0f336830337
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: af24b50f4a1bf85459001d38afa5850e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,130 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Build.CacheServer
|
||||
{
|
||||
/// <summary>
|
||||
/// The CacheServerUploader is responsible for uploading assets to a given Cache Server.
|
||||
/// </summary>
|
||||
public static class CacheServerUploader
|
||||
{
|
||||
private struct Transaction
|
||||
{
|
||||
public struct FileInfo
|
||||
{
|
||||
public readonly FileType type;
|
||||
public readonly string path;
|
||||
|
||||
public FileInfo(FileType type, string path)
|
||||
{
|
||||
this.type = type;
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly FileId fileId;
|
||||
public readonly FileInfo[] files;
|
||||
|
||||
private Transaction(FileId fileId, FileInfo[] files)
|
||||
{
|
||||
this.fileId = fileId;
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
public static Transaction CreateForAssetPath(string assetPath)
|
||||
{
|
||||
var projectRoot = Directory.GetParent(Application.dataPath).FullName;
|
||||
|
||||
var guid = AssetDatabase.AssetPathToGUID(assetPath);
|
||||
var hash = AssetDatabase.GetAssetDependencyHash(assetPath);
|
||||
|
||||
var libPath =
|
||||
new[] { projectRoot, "Library", "metadata", guid.Substring(0, 2), guid }
|
||||
.Aggregate(string.Empty, Path.Combine);
|
||||
|
||||
if (!File.Exists(libPath))
|
||||
{
|
||||
throw new Exception("Cannot find Library representation for GUID " + guid);
|
||||
}
|
||||
|
||||
var files = new List<FileInfo>
|
||||
{
|
||||
new FileInfo(FileType.Asset, libPath)
|
||||
};
|
||||
|
||||
var infoLibPath = libPath + ".info";
|
||||
if (File.Exists(infoLibPath))
|
||||
{
|
||||
files.Add(new FileInfo(FileType.Info, infoLibPath));
|
||||
}
|
||||
|
||||
var resLibPath = libPath + ".resource";
|
||||
if (File.Exists(resLibPath))
|
||||
{
|
||||
files.Add(new FileInfo(FileType.Resource, resLibPath));
|
||||
}
|
||||
|
||||
return new Transaction(FileId.From(guid, hash.ToString()), files.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Synchronize project library with the configured Cache Server.
|
||||
/// </summary>
|
||||
public static void UploadAllFilesToCacheServer()
|
||||
{
|
||||
string host;
|
||||
int port;
|
||||
Util.ParseCacheServerIpAddress(Util.ConfigCacheServerAddress, out host, out port);
|
||||
UploadAllFilesToCacheServer(host, port);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Synchronize project library folder with a remote Cache Server.
|
||||
/// </summary>
|
||||
/// <param name="host">Host name or IP or remote Cache Server</param>
|
||||
/// <param name="port">Port number for remote Cache Server</param>
|
||||
public static void UploadAllFilesToCacheServer(string host, int port)
|
||||
{
|
||||
var client = new Client(host, port);
|
||||
client.Connect();
|
||||
|
||||
var assetPaths = AssetDatabase.GetAllAssetPaths();
|
||||
var len = assetPaths.Length;
|
||||
|
||||
for (var i = 0; i < len; i++)
|
||||
{
|
||||
var path = assetPaths[i];
|
||||
if (!File.Exists(path))
|
||||
continue;
|
||||
|
||||
var progress = (float)(i + 1) / (len + 1);
|
||||
|
||||
if (EditorUtility.DisplayCancelableProgressBar("Uploading to Cache Server", path, progress)) break;
|
||||
|
||||
try
|
||||
{
|
||||
var trx = Transaction.CreateForAssetPath(path);
|
||||
client.BeginTransaction(trx.fileId);
|
||||
|
||||
foreach (var file in trx.files)
|
||||
using (var stream = new FileStream(file.path, FileMode.Open, FileAccess.Read))
|
||||
client.Upload(file.type, stream);
|
||||
|
||||
client.EndTransaction();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
client.Close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e766efa9ccaf441728f810262e5ca359
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,90 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Build.CacheServer
|
||||
{
|
||||
/// <summary>
|
||||
/// The Cache Server Uploader window. This interface will upload your assets to a the given address of a Cache Server.
|
||||
/// </summary>
|
||||
public class CacheServerUploaderWindow : EditorWindow
|
||||
{
|
||||
private string m_address;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
m_address = Util.ConfigCacheServerAddress;
|
||||
titleContent = new GUIContent("CS Upload");
|
||||
}
|
||||
|
||||
private bool ValidateAddress()
|
||||
{
|
||||
string host;
|
||||
int port;
|
||||
Util.ParseCacheServerIpAddress(m_address, out host, out port);
|
||||
|
||||
var c = new Client(host, port);
|
||||
try
|
||||
{
|
||||
c.Connect();
|
||||
c.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Cache Server Address: ");
|
||||
m_address = GUILayout.TextField(m_address);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (GUILayout.Button("Upload") && EditorUtility.DisplayDialog("Upload to Cache Server",
|
||||
"This will upload all assets in your Library folder to the specified Cache Server.", "Continue", "Cancel"))
|
||||
{
|
||||
GetWindow<CacheServerUploaderWindow>().Close();
|
||||
if (!ValidateAddress())
|
||||
{
|
||||
Debug.LogError("Could not connect to Cache Server");
|
||||
return;
|
||||
}
|
||||
|
||||
string host;
|
||||
int port;
|
||||
Util.ParseCacheServerIpAddress(m_address, out host, out port);
|
||||
CacheServerUploader.UploadAllFilesToCacheServer(host, port);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Cancel"))
|
||||
{
|
||||
GetWindow<CacheServerUploaderWindow>().Close();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private void OnInspectorUpdate()
|
||||
{
|
||||
Repaint();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uploads all assets to the cache server.
|
||||
/// </summary>
|
||||
[MenuItem("Assets/Cache Server/Upload All Assets")]
|
||||
public static void UploadAllFilesToCacheServerMenuItem()
|
||||
{
|
||||
var window = GetWindow<CacheServerUploaderWindow>();
|
||||
window.ShowUtility();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c18f0df0496b5418bbb5a34c4c30d6e8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,541 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using UnityEngine;
|
||||
using System.Threading;
|
||||
|
||||
namespace UnityEditor.Build.CacheServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Options for the type of a particular file.
|
||||
/// </summary>
|
||||
public enum FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Use to indicate that the file is an asset.
|
||||
/// </summary>
|
||||
Asset = 'a',
|
||||
/// <summary>
|
||||
/// Use to indicate that the file holds information for an asset/resource.
|
||||
/// </summary>
|
||||
Info = 'i',
|
||||
/// <summary>
|
||||
/// Use to indicate that the file is a resource.
|
||||
/// </summary>
|
||||
Resource = 'r'
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Options for the result returned by a download operation.
|
||||
/// </summary>
|
||||
public enum DownloadResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Use to indicate that the operation failed.
|
||||
/// </summary>
|
||||
Failure = 0,
|
||||
/// <summary>
|
||||
/// Use to indicate that the operation failed because it could not locate the specified file.
|
||||
/// </summary>
|
||||
FileNotFound = 1,
|
||||
/// <summary>
|
||||
/// Use to indicate that the operation succedeed.
|
||||
/// </summary>
|
||||
Success = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A GUID/Hash pair that uniquely identifies a particular file. For each FileId, the Cache Server can store a separate
|
||||
/// binary stream for each FileType.
|
||||
/// </summary>
|
||||
public struct FileId : IEqualityComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// The guid byte array.
|
||||
/// </summary>
|
||||
public readonly byte[] guid;
|
||||
|
||||
/// <summary>
|
||||
/// The hash code byte array.
|
||||
/// </summary>
|
||||
public readonly byte[] hash;
|
||||
|
||||
/// <summary>
|
||||
/// A structure used to identify a file by guid and hash code.
|
||||
/// </summary>
|
||||
/// <param name="guid">File GUID.</param>
|
||||
/// <param name="hash">File hash code.</param>
|
||||
private FileId(byte[] guid, byte[] hash)
|
||||
{
|
||||
this.guid = guid;
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a FileId given a string guid and string hash code representation.
|
||||
/// </summary>
|
||||
/// <param name="guidStr">GUID string representation.</param>
|
||||
/// <param name="hashStr">Hash code string representation.</param>
|
||||
/// <returns></returns>
|
||||
public static FileId From(string guidStr, string hashStr)
|
||||
{
|
||||
if (guidStr.Length != 32)
|
||||
throw new ArgumentException("Length != 32", "guidStr");
|
||||
|
||||
if (hashStr.Length != 32)
|
||||
throw new ArgumentException("Length != 32", "hashStr");
|
||||
|
||||
return new FileId(Util.StringToGuid(guidStr), Util.StringToHash(hashStr));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a FileId given a byte array guid and byte array hash code.
|
||||
/// </summary>
|
||||
/// <param name="guid">GUID byte array.</param>
|
||||
/// <param name="hash">Hash code byte array.</param>
|
||||
/// <returns></returns>
|
||||
public static FileId From(byte[] guid, byte[] hash)
|
||||
{
|
||||
if (guid.Length != 16)
|
||||
throw new ArgumentException("Length != 32", "guid");
|
||||
|
||||
if (hash.Length != 16)
|
||||
throw new ArgumentException("Length != 32", "hash");
|
||||
|
||||
return new FileId(guid, hash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check equality of two objects given their guid and hash code.
|
||||
/// </summary>
|
||||
/// <param name="x">lhs object.</param>
|
||||
/// <param name="y">rhs object.</param>
|
||||
/// <returns></returns>
|
||||
public new bool Equals(object x, object y)
|
||||
{
|
||||
var hash1 = (byte[])x;
|
||||
var hash2 = (byte[])y;
|
||||
|
||||
if (hash1.Length != hash2.Length)
|
||||
return false;
|
||||
|
||||
for (var i = 0; i < hash1.Length; i++)
|
||||
if (hash1[i] != hash2[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the hash code for a specific object.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object you want the hash code for.</param>
|
||||
/// <returns></returns>
|
||||
public int GetHashCode(object obj)
|
||||
{
|
||||
var hc = 17;
|
||||
hc = hc * 23 + guid.GetHashCode();
|
||||
hc = hc * 23 + hash.GetHashCode();
|
||||
return hc;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exception thrown when an upload operation is not properly isolated within a begin/end transaction
|
||||
/// </summary>
|
||||
public class TransactionIsolationException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new exception for when an upload operation is not properly isolated within a begin/end transaction.
|
||||
/// </summary>
|
||||
/// <param name="msg">The text containing information to display.</param>
|
||||
public TransactionIsolationException(string msg) : base(msg) {}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EventArgs passed to the DownloadFinished event handler
|
||||
/// </summary>
|
||||
public class DownloadFinishedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// EventArgs download result code.
|
||||
/// </summary>
|
||||
public DownloadResult Result { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The downloaded item.
|
||||
/// </summary>
|
||||
public IDownloadItem DownloadItem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The size of the downloaded item.
|
||||
/// </summary>
|
||||
public long Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The length of the download queue.
|
||||
/// </summary>
|
||||
public long DownloadQueueLength { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A client API for uploading and downloading files from a Cache Server
|
||||
/// </summary>
|
||||
public class Client
|
||||
{
|
||||
private enum StreamReadState
|
||||
{
|
||||
Response,
|
||||
Size,
|
||||
Id
|
||||
}
|
||||
|
||||
private const int ProtocolVersion = 254;
|
||||
private const string CmdTrxBegin = "ts";
|
||||
private const string CmdTrxEnd = "te";
|
||||
private const string CmdGet = "g";
|
||||
private const string CmdPut = "p";
|
||||
private const string CmdQuit = "q";
|
||||
|
||||
private const int ResponseLen = 2;
|
||||
private const int SizeLen = 16;
|
||||
private const int GuidLen = 16;
|
||||
private const int HashLen = 16;
|
||||
private const int IdLen = GuidLen + HashLen;
|
||||
private const int ReadBufferLen = 64 * 1024;
|
||||
|
||||
private readonly Queue<IDownloadItem> m_downloadQueue;
|
||||
private readonly TcpClient m_tcpClient;
|
||||
private readonly string m_host;
|
||||
private readonly int m_port;
|
||||
internal Stream m_stream;
|
||||
private Mutex m_mutex;
|
||||
private readonly byte[] m_streamReadBuffer;
|
||||
private int m_streamBytesRead;
|
||||
private int m_streamBytesNeeded;
|
||||
private StreamReadState m_streamReadState = StreamReadState.Response;
|
||||
private DownloadFinishedEventArgs m_nextFileCompleteEventArgs;
|
||||
private Stream m_nextWriteStream;
|
||||
private bool m_inTrx;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of items in the download queue
|
||||
/// </summary>
|
||||
public int DownloadQueueLength
|
||||
{
|
||||
get { return m_downloadQueue.Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when a queued download request finishes.
|
||||
/// </summary>
|
||||
public event EventHandler<DownloadFinishedEventArgs> DownloadFinished;
|
||||
|
||||
/// <summary>
|
||||
/// Remove all listeners from the DownloadFinished event
|
||||
/// </summary>
|
||||
public void ResetDownloadFinishedEventHandler()
|
||||
{
|
||||
DownloadFinished = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new Cache Server client
|
||||
/// </summary>
|
||||
/// <param name="host">The host name or IP of the Cache Server.</param>
|
||||
/// <param name="port">The port number of the Cache Server. Default port is 8126.</param>
|
||||
public Client(string host, int port = 8126)
|
||||
{
|
||||
m_streamReadBuffer = new byte[ReadBufferLen];
|
||||
m_downloadQueue = new Queue<IDownloadItem>();
|
||||
m_tcpClient = new TcpClient();
|
||||
m_host = host;
|
||||
m_port = port;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the Cache Server and sends a protocol version handshake.
|
||||
/// </summary>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void Connect()
|
||||
{
|
||||
var client = m_tcpClient;
|
||||
client.Connect(m_host, m_port);
|
||||
m_stream = client.GetStream();
|
||||
m_stream.ReadTimeout = 10000;
|
||||
m_stream.WriteTimeout = 10000;
|
||||
SendVersion();
|
||||
m_mutex = new Mutex();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the Cache Server and sends a protocol version handshake. A TimeoutException is thrown if the connection cannot
|
||||
/// be established within <paramref name="timeoutMs"/> milliseconds.
|
||||
/// </summary>
|
||||
/// <param name="timeoutMs"></param>
|
||||
/// <exception cref="TimeoutException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void Connect(int timeoutMs)
|
||||
{
|
||||
var client = m_tcpClient;
|
||||
var op = client.BeginConnect(m_host, m_port, null, null);
|
||||
|
||||
var connected = op.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(timeoutMs));
|
||||
|
||||
if (!connected)
|
||||
throw new TimeoutException();
|
||||
|
||||
m_stream = client.GetStream();
|
||||
SendVersion();
|
||||
m_mutex = new Mutex();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begin an upload transaction for an asset. Transactions in process can be interupted by calling BeginTransaction
|
||||
/// again before calling EndTransaction.
|
||||
/// </summary>
|
||||
/// <param name="fileId"></param>
|
||||
public void BeginTransaction(FileId fileId)
|
||||
{
|
||||
m_inTrx = true;
|
||||
m_stream.Write(Encoding.ASCII.GetBytes(CmdTrxBegin), 0, 2);
|
||||
m_stream.Write(fileId.guid, 0, GuidLen);
|
||||
m_stream.Write(fileId.hash, 0, HashLen);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upload from the given stream for the given FileType. Will throw an exception if not preceeded by BeginTransaction.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="readStream"></param>
|
||||
/// <exception cref="TransactionIsolationException"></exception>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public void Upload(FileType type, Stream readStream)
|
||||
{
|
||||
if (!m_inTrx)
|
||||
throw new TransactionIsolationException("Upload without BeginTransaction");
|
||||
|
||||
if (!readStream.CanRead || !readStream.CanSeek)
|
||||
throw new ArgumentException();
|
||||
|
||||
m_stream.Write(Encoding.ASCII.GetBytes(CmdPut + (char)type), 0, 2);
|
||||
m_stream.Write(Util.EncodeInt64(readStream.Length), 0, SizeLen);
|
||||
|
||||
var buf = new byte[ReadBufferLen];
|
||||
while (readStream.Position < readStream.Length - 1)
|
||||
{
|
||||
var len = readStream.Read(buf, 0, ReadBufferLen);
|
||||
m_stream.Write(buf, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Commit the uploaded files to the Cache Server. Will throw an exception if not preceeded by BeginTransaction.
|
||||
/// </summary>
|
||||
/// <exception cref="TransactionIsolationException"></exception>
|
||||
public void EndTransaction()
|
||||
{
|
||||
if (!m_inTrx)
|
||||
throw new TransactionIsolationException("EndTransaction without BeginTransaction");
|
||||
|
||||
m_inTrx = false;
|
||||
m_stream.Write(Encoding.ASCII.GetBytes(CmdTrxEnd), 0, 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a download request to the Cache Server. Listen to the DownloadComplete event to read the results.
|
||||
/// </summary>
|
||||
/// <param name="downloadItem">The IDownloadItem that specifies which file to download</param>
|
||||
public void QueueDownload(IDownloadItem downloadItem)
|
||||
{
|
||||
m_stream.Write(Encoding.ASCII.GetBytes(CmdGet + (char)downloadItem.Type), 0, 2);
|
||||
m_stream.Write(downloadItem.Id.guid, 0, GuidLen);
|
||||
m_stream.Write(downloadItem.Id.hash, 0, HashLen);
|
||||
|
||||
m_mutex.WaitOne();
|
||||
m_downloadQueue.Enqueue(downloadItem);
|
||||
int count = m_downloadQueue.Count;
|
||||
m_mutex.ReleaseMutex();
|
||||
|
||||
if (count == 1)
|
||||
ReadNextDownloadResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the connection to the Cache Server. Sends the 'quit' command and closes the network stream.
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
if (m_stream != null)
|
||||
m_stream.Write(Encoding.ASCII.GetBytes(CmdQuit), 0, 1);
|
||||
|
||||
if (m_tcpClient != null)
|
||||
m_tcpClient.Close();
|
||||
|
||||
if (m_mutex != null)
|
||||
{
|
||||
m_mutex.Dispose();
|
||||
m_mutex = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void SendVersion()
|
||||
{
|
||||
var encodedVersion = Util.EncodeInt32(ProtocolVersion, true);
|
||||
m_stream.Write(encodedVersion, 0, encodedVersion.Length);
|
||||
|
||||
var versionBuf = new byte[8];
|
||||
var pos = 0;
|
||||
while (pos < versionBuf.Length - 1)
|
||||
{
|
||||
pos += m_stream.Read(versionBuf, 0, versionBuf.Length);
|
||||
}
|
||||
|
||||
if (Util.ReadUInt32(versionBuf, 0) != ProtocolVersion)
|
||||
throw new Exception("Server version mismatch");
|
||||
}
|
||||
|
||||
private void OnDownloadFinished(DownloadFinishedEventArgs e)
|
||||
{
|
||||
m_mutex.WaitOne();
|
||||
m_downloadQueue.Dequeue();
|
||||
int count = m_downloadQueue.Count;
|
||||
m_mutex.ReleaseMutex();
|
||||
|
||||
e.DownloadQueueLength = count;
|
||||
if (DownloadFinished != null)
|
||||
DownloadFinished(this, e);
|
||||
|
||||
if (count > 0)
|
||||
ReadNextDownloadResult();
|
||||
}
|
||||
|
||||
internal void ReadNextDownloadResult()
|
||||
{
|
||||
m_streamReadState = StreamReadState.Response;
|
||||
m_streamBytesNeeded = ResponseLen;
|
||||
m_streamBytesRead = 0;
|
||||
m_nextFileCompleteEventArgs = new DownloadFinishedEventArgs { Result = DownloadResult.Failure };
|
||||
BeginReadHeader();
|
||||
}
|
||||
|
||||
private void BeginReadHeader()
|
||||
{
|
||||
m_stream.BeginRead(m_streamReadBuffer,
|
||||
m_streamBytesRead,
|
||||
m_streamBytesNeeded - m_streamBytesRead,
|
||||
EndReadHeader,
|
||||
m_stream);
|
||||
}
|
||||
|
||||
internal Action<int, byte[]> OnReadHeader;
|
||||
|
||||
private void EndReadHeader(IAsyncResult r)
|
||||
{
|
||||
var bytesRead = m_stream.EndRead(r);
|
||||
if (bytesRead <= 0) return;
|
||||
|
||||
m_streamBytesRead += bytesRead;
|
||||
|
||||
if (OnReadHeader != null)
|
||||
OnReadHeader(m_streamBytesRead, m_streamReadBuffer);
|
||||
|
||||
if (m_streamBytesRead < m_streamBytesNeeded)
|
||||
{
|
||||
BeginReadHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_streamReadState)
|
||||
{
|
||||
case StreamReadState.Response:
|
||||
if (Convert.ToChar(m_streamReadBuffer[0]) == '+')
|
||||
{
|
||||
m_streamReadState = StreamReadState.Size;
|
||||
m_streamBytesNeeded = SizeLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nextFileCompleteEventArgs.Result = DownloadResult.FileNotFound;
|
||||
m_streamReadState = StreamReadState.Id;
|
||||
m_streamBytesNeeded = IdLen;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case StreamReadState.Size:
|
||||
m_nextFileCompleteEventArgs.Size = Util.ReadUInt64(m_streamReadBuffer, 0);
|
||||
m_streamReadState = StreamReadState.Id;
|
||||
m_streamBytesNeeded = IdLen;
|
||||
break;
|
||||
|
||||
case StreamReadState.Id:
|
||||
m_mutex.WaitOne();
|
||||
var next = m_downloadQueue.Peek();
|
||||
m_mutex.ReleaseMutex();
|
||||
m_nextFileCompleteEventArgs.DownloadItem = next;
|
||||
|
||||
var match =
|
||||
Util.ByteArraysAreEqual(next.Id.guid, 0, m_streamReadBuffer, 0, GuidLen) &&
|
||||
Util.ByteArraysAreEqual(next.Id.hash, 0, m_streamReadBuffer, GuidLen, HashLen);
|
||||
|
||||
if (!match)
|
||||
{
|
||||
Close();
|
||||
throw new InvalidDataException();
|
||||
}
|
||||
|
||||
if (m_nextFileCompleteEventArgs.Result == DownloadResult.FileNotFound)
|
||||
{
|
||||
OnDownloadFinished(m_nextFileCompleteEventArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
var size = m_nextFileCompleteEventArgs.Size;
|
||||
m_nextWriteStream = next.GetWriteStream(size);
|
||||
m_streamBytesNeeded = (int)size;
|
||||
m_streamBytesRead = 0;
|
||||
BeginReadData();
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
m_streamBytesRead = 0;
|
||||
BeginReadHeader();
|
||||
}
|
||||
|
||||
private void BeginReadData()
|
||||
{
|
||||
var len = Math.Min(ReadBufferLen, m_streamBytesNeeded - m_streamBytesRead);
|
||||
m_stream.BeginRead(m_streamReadBuffer, 0, len, EndReadData, null);
|
||||
}
|
||||
|
||||
private void EndReadData(IAsyncResult readResult)
|
||||
{
|
||||
var bytesRead = m_stream.EndRead(readResult);
|
||||
Debug.Assert(bytesRead > 0);
|
||||
m_streamBytesRead += bytesRead;
|
||||
|
||||
var writeResult = m_nextWriteStream.BeginWrite(m_streamReadBuffer, 0, bytesRead, null, null);
|
||||
m_nextWriteStream.EndWrite(writeResult);
|
||||
|
||||
if (m_streamBytesRead < m_streamBytesNeeded)
|
||||
{
|
||||
BeginReadData();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nextFileCompleteEventArgs.DownloadItem.Finish();
|
||||
m_nextFileCompleteEventArgs.Result = DownloadResult.Success;
|
||||
OnDownloadFinished(m_nextFileCompleteEventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 02aa99c7f5d8f4c77810419ebddad96d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,82 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Build.CacheServer
|
||||
{
|
||||
/// <summary>
|
||||
/// IDownloadItem implementation for downloading to a file specified by path.
|
||||
/// </summary>
|
||||
public class FileDownloadItem : IDownloadItem
|
||||
{
|
||||
private Stream m_writeStream;
|
||||
private string m_tmpPath;
|
||||
|
||||
/// <summary>
|
||||
/// The FileId for the FileDownloadItem. FileId consists of an assets guid and hash code.
|
||||
/// </summary>
|
||||
public FileId Id { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of the FileDownloadItems desired item.
|
||||
/// </summary>
|
||||
public FileType Type { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// File path where downloaded file data is saved. Data is first written to a temporary file location, and moved
|
||||
/// into place when the Finish() method is called by the Cache Server Client.
|
||||
/// </summary>
|
||||
public string FilePath { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the write stream for a given FileDownloadItem. If one does not exist, it will be created.
|
||||
/// </summary>
|
||||
/// <param name="size"></param>
|
||||
/// <returns></returns>
|
||||
public Stream GetWriteStream(long size)
|
||||
{
|
||||
if (m_writeStream == null)
|
||||
{
|
||||
m_tmpPath = Path.GetTempFileName();
|
||||
m_writeStream = new FileStream(m_tmpPath, FileMode.Create, FileAccess.Write);
|
||||
}
|
||||
|
||||
return m_writeStream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new FileDownloadItem
|
||||
/// </summary>
|
||||
/// <param name="fileId">The FileId of the desired item.</param>
|
||||
/// <param name="fileType">The FileType of the desired item.</param>
|
||||
/// <param name="path">The path of the desired item.</param>
|
||||
public FileDownloadItem(FileId fileId, FileType fileType, string path)
|
||||
{
|
||||
Id = fileId;
|
||||
Type = fileType;
|
||||
FilePath = path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose the FileDownloadItems write stream and move the data from the temporary path to its final destination.
|
||||
/// </summary>
|
||||
public void Finish()
|
||||
{
|
||||
if (m_writeStream == null)
|
||||
return;
|
||||
|
||||
m_writeStream.Dispose();
|
||||
try
|
||||
{
|
||||
if (File.Exists(FilePath))
|
||||
File.Delete(FilePath);
|
||||
|
||||
File.Move(m_tmpPath, FilePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e253c6be7d9134114a9b533965c2b45f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,33 @@
|
|||
using System.IO;
|
||||
|
||||
namespace UnityEditor.Build.CacheServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single file download request from a Cache Server.
|
||||
/// </summary>
|
||||
public interface IDownloadItem
|
||||
{
|
||||
/// <summary>
|
||||
/// the FileId (guid/hash pair) of the file to download
|
||||
/// </summary>
|
||||
FileId Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// the FileType for the given FileId to download
|
||||
/// </summary>
|
||||
FileType Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Provides a writable stream for saving downloaded file bytes
|
||||
/// </summary>
|
||||
/// <param name="size">Size of file to download</param>
|
||||
/// <returns>A writable stream</returns>
|
||||
Stream GetWriteStream(long size);
|
||||
|
||||
/// <summary>
|
||||
/// Method called when a download is finished. Used to finalize and cleanup a single file download. e.g. to move
|
||||
/// a temporary file into place.
|
||||
/// </summary>
|
||||
void Finish();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 31314932afa7e4ce3ab642bfbc2dd8ff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "UnityEditor.CacheServer",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": []
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 27fb11404301449859aa664f4cb020e0
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,163 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
[assembly: InternalsVisibleTo("UnityEditor.CacheServerTests")]
|
||||
|
||||
namespace UnityEditor.Build.CacheServer
|
||||
{
|
||||
internal static class Util
|
||||
{
|
||||
private const string IpAddressKey = "CacheServerIPAddress";
|
||||
|
||||
private static int ReverseByte(int b)
|
||||
{
|
||||
return ((b & 0x0F) << 4) | ((b >> 4) & 0x0F);
|
||||
}
|
||||
|
||||
private static byte[] StringToByteArray(string input, bool asGuid)
|
||||
{
|
||||
var bytes = new byte[input.Length / 2];
|
||||
for (var i = 0; i < input.Length; i += 2)
|
||||
{
|
||||
var b = Convert.ToByte(input.Substring(i, 2), 16);
|
||||
bytes[i / 2] = asGuid ? (byte)ReverseByte(b) : b;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a hex string to a byte array that represents an Asset Hash
|
||||
/// </summary>
|
||||
/// <param name="hashStr">32 character hex string</param>
|
||||
/// <returns>byte array</returns>
|
||||
public static byte[] StringToHash(string hashStr)
|
||||
{
|
||||
Debug.Assert(hashStr.Length == 32);
|
||||
return StringToByteArray(hashStr, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a hex string to a byte array that represents an Asset GUID
|
||||
/// </summary>
|
||||
/// <param name="guidStr">32 character hex string</param>
|
||||
/// <returns>byte array</returns>
|
||||
public static byte[] StringToGuid(string guidStr)
|
||||
{
|
||||
Debug.Assert(guidStr.Length == 32);
|
||||
return StringToByteArray(guidStr, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an ascii byte array at <paramref name="index"/>start as an int value
|
||||
/// </summary>
|
||||
/// <param name="bytes">byte array</param>
|
||||
/// <param name="index">offset</param>
|
||||
/// <returns></returns>
|
||||
public static int ReadUInt32(byte[] bytes, int index)
|
||||
{
|
||||
Debug.Assert(bytes.Length + index >= 8);
|
||||
return Int32.Parse(Encoding.ASCII.GetString(bytes, index, 8), NumberStyles.HexNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode an integer as an ascii byte array
|
||||
/// </summary>
|
||||
/// <param name="input">integer</param>
|
||||
/// <param name="minLength">true ensure the byte array is as short as possible; false to pad to 8 bytes</param>
|
||||
/// <returns></returns>
|
||||
public static byte[] EncodeInt32(int input, bool minLength = false)
|
||||
{
|
||||
return Encoding.ASCII.GetBytes(input.ToString(minLength ? "X" : "X8"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a subset of an ascii byte array as a long value
|
||||
/// </summary>
|
||||
/// <param name="bytes">byte array</param>
|
||||
/// <param name="index">offset within <paramref name="bytes"/> to read from</param>
|
||||
/// <returns></returns>
|
||||
public static long ReadUInt64(byte[] bytes, int index)
|
||||
{
|
||||
Debug.Assert(bytes.Length + index >= 16);
|
||||
return Int64.Parse(Encoding.ASCII.GetString(bytes, index, 16), NumberStyles.HexNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode a long value into an ascii byte array
|
||||
/// </summary>
|
||||
/// <param name="input">long value</param>
|
||||
/// <returns></returns>
|
||||
public static byte[] EncodeInt64(long input)
|
||||
{
|
||||
return Encoding.ASCII.GetBytes(input.ToString("X16"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two byte arrays for value equality
|
||||
/// </summary>
|
||||
/// <param name="ar1">first array</param>
|
||||
/// <param name="ar2">second array</param>
|
||||
/// <returns></returns>
|
||||
public static bool ByteArraysAreEqual(byte[] ar1, byte[] ar2)
|
||||
{
|
||||
return ar1.Length == ar2.Length && ByteArraysAreEqual(ar1, 0, ar2, 0, ar1.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two byte arrays for value equality at specific offsets and length
|
||||
/// </summary>
|
||||
/// <param name="ar1">first array</param>
|
||||
/// <param name="start1">offset within first array</param>
|
||||
/// <param name="ar2">second array</param>
|
||||
/// <param name="start2">offset within second array</param>
|
||||
/// <param name="count">number of bytes to compare</param>
|
||||
/// <returns></returns>
|
||||
public static bool ByteArraysAreEqual(byte[] ar1, int start1, byte[] ar2, int start2, int count)
|
||||
{
|
||||
Debug.Assert(start1 >= 0 && start2 >= 0 && count >= 0);
|
||||
if (start1 + count > ar1.Length)
|
||||
return false;
|
||||
|
||||
if (start2 + count > ar2.Length)
|
||||
return false;
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
if (ar1[start1 + i] != ar2[start2 + i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the configured cache server address for the Unity Editor
|
||||
/// </summary>
|
||||
public static string ConfigCacheServerAddress
|
||||
{
|
||||
get { return EditorPrefs.GetString(IpAddressKey); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an address string in the format of 'address:port' to a string address and integer port number
|
||||
/// </summary>
|
||||
/// <param name="address">combined address string</param>
|
||||
/// <param name="host">address part</param>
|
||||
/// <param name="port">port part</param>
|
||||
public static void ParseCacheServerIpAddress(string address, out string host, out int port)
|
||||
{
|
||||
host = null;
|
||||
port = 8126;
|
||||
|
||||
var parts = address.Split(':');
|
||||
|
||||
if (parts.Length > 0)
|
||||
host = parts[0];
|
||||
|
||||
if (parts.Length > 1)
|
||||
port = int.Parse(parts[1]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a0c7d049419ae46f19ead59b45d622fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,101 @@
|
|||
using System.IO;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Build.Pipeline;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
using BuildCompression = UnityEngine.BuildCompression;
|
||||
#else
|
||||
using BuildCompression = UnityEditor.Build.Content.BuildCompression;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Static class exposing convenient methods that match the BuildPipeline <seealso cref="BuildPipeline.BuildAssetBundles"/> method, suitable
|
||||
/// for porting existing projects to the Scriptable Build Pipeline quickly.
|
||||
/// New projects could consider calling <see cref="ContentPipeline.BuildAssetBundles"/> directly.
|
||||
/// </summary>
|
||||
public static class CompatibilityBuildPipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper API to match BuildPipeline API but use the Scriptable Build Pipeline to build Asset Bundles.
|
||||
/// <seealso cref="BuildPipeline.BuildAssetBundles(string, BuildAssetBundleOptions, BuildTarget)"/>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Not all BuildAssetBundleOptions are supported in the Scriptable Build Pipeline.
|
||||
/// Supported options are: ForceRebuildAssetBundle, AppendHashToAssetBundleName, ChunkBasedCompression, UncompressedAssetBundle, and DisableWriteTypeTree.
|
||||
/// In addition, existing BuildPipeline callbacks are not yet supported.
|
||||
/// </remarks>
|
||||
/// <param name="outputPath">Output path for the AssetBundles.</param>
|
||||
/// <param name="assetBundleOptions">AssetBundle building options.</param>
|
||||
/// <param name="targetPlatform">Chosen target build platform.</param>
|
||||
/// <returns>CompatibilityAssetBundleManifest object exposing information about the generated asset bundles.</returns>
|
||||
public static CompatibilityAssetBundleManifest BuildAssetBundles(string outputPath, BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform)
|
||||
{
|
||||
// Retrieve the AssetBundle definitions as defined through the Inspector and saved in the AssetDatabase
|
||||
var buildInput = ContentBuildInterface.GenerateAssetBundleBuilds();
|
||||
return BuildAssetBundles_Internal(outputPath, new BundleBuildContent(buildInput), assetBundleOptions, targetPlatform);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper API to match BuildPipeline API but use the Scriptable Build Pipeline to build Asset Bundles.
|
||||
/// <seealso cref="BuildPipeline.BuildAssetBundles(string, AssetBundleBuild[], BuildAssetBundleOptions, BuildTarget)"/>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Not all BuildAssetBundleOptions are supported in the Scriptable Build Pipeline.
|
||||
/// Supported options are: ForceRebuildAssetBundle, AppendHashToAssetBundleName, ChunkBasedCompression, UncompressedAssetBundle, and DisableWriteTypeTree.
|
||||
/// In addition, existing BuildPipeline callbacks are not yet supported.
|
||||
/// </remarks>
|
||||
/// <param name="outputPath">Output path for the AssetBundles.</param>
|
||||
/// <param name="builds">AssetBundle building map.</param>
|
||||
/// <param name="assetBundleOptions">AssetBundle building options.</param>
|
||||
/// <param name="targetPlatform">Chosen target build platform.</param>
|
||||
/// <returns>CompatibilityAssetBundleManifest object exposing information about the generated asset bundles.</returns>
|
||||
public static CompatibilityAssetBundleManifest BuildAssetBundles(string outputPath, AssetBundleBuild[] builds, BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform)
|
||||
{
|
||||
return BuildAssetBundles_Internal(outputPath, new BundleBuildContent(builds), assetBundleOptions, targetPlatform);
|
||||
}
|
||||
|
||||
internal static CompatibilityAssetBundleManifest BuildAssetBundles_Internal(string outputPath, IBundleBuildContent content, BuildAssetBundleOptions options, BuildTarget targetPlatform)
|
||||
{
|
||||
var group = BuildPipeline.GetBuildTargetGroup(targetPlatform);
|
||||
var parameters = new BundleBuildParameters(targetPlatform, group, outputPath);
|
||||
if ((options & BuildAssetBundleOptions.ForceRebuildAssetBundle) != 0)
|
||||
parameters.UseCache = false;
|
||||
|
||||
if ((options & BuildAssetBundleOptions.AppendHashToAssetBundleName) != 0)
|
||||
parameters.AppendHash = true;
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
if ((options & BuildAssetBundleOptions.ChunkBasedCompression) != 0)
|
||||
parameters.BundleCompression = BuildCompression.LZ4;
|
||||
else if ((options & BuildAssetBundleOptions.UncompressedAssetBundle) != 0)
|
||||
parameters.BundleCompression = BuildCompression.Uncompressed;
|
||||
else
|
||||
parameters.BundleCompression = BuildCompression.LZMA;
|
||||
#else
|
||||
if ((options & BuildAssetBundleOptions.ChunkBasedCompression) != 0)
|
||||
parameters.BundleCompression = BuildCompression.DefaultLZ4;
|
||||
else if ((options & BuildAssetBundleOptions.UncompressedAssetBundle) != 0)
|
||||
parameters.BundleCompression = BuildCompression.DefaultUncompressed;
|
||||
else
|
||||
parameters.BundleCompression = BuildCompression.DefaultLZMA;
|
||||
#endif
|
||||
|
||||
if ((options & BuildAssetBundleOptions.DisableWriteTypeTree) != 0)
|
||||
parameters.ContentBuildFlags |= ContentBuildFlags.DisableWriteTypeTree;
|
||||
|
||||
IBundleBuildResults results;
|
||||
ReturnCode exitCode = ContentPipeline.BuildAssetBundles(parameters, content, out results);
|
||||
if (exitCode < ReturnCode.Success)
|
||||
return null;
|
||||
|
||||
var manifest = ScriptableObject.CreateInstance<CompatibilityAssetBundleManifest>();
|
||||
manifest.SetResults(results.BundleInfos);
|
||||
File.WriteAllText(parameters.GetOutputFilePathForIdentifier(Path.GetFileName(outputPath) + ".manifest"), manifest.ToString());
|
||||
return manifest;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e4a7ddc0ee0cb5e47b5c53fb53a97808
|
||||
timeCreated: 1504709534
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,189 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEditor.Build.Utilities;
|
||||
using UnityEditor.Modules;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class containing the main content building entry points into the Scriptable Build Pipeline.
|
||||
/// </summary>
|
||||
public static class ContentPipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Default temporary path used for building content data.
|
||||
/// </summary>
|
||||
public const string kTempBuildPath = "Temp/ContentBuildData";
|
||||
|
||||
/// <summary>
|
||||
/// Default temporary path used for building script data.
|
||||
/// </summary>
|
||||
public const string kScriptBuildPath = "Library/PlayerScriptAssemblies";
|
||||
|
||||
/// <summary>
|
||||
/// Default callback implementation.
|
||||
/// </summary>
|
||||
public static BuildCallbacks BuildCallbacks = new BuildCallbacks();
|
||||
|
||||
/// <summary>
|
||||
/// Default implementation of generating Asset Bundles using the Scriptable Build Pipeline.
|
||||
/// </summary>
|
||||
/// <param name="parameters">Set of parameters used for building asset bundles.</param>
|
||||
/// <param name="content">Set of content and explicit asset bundle layout to build.</param>
|
||||
/// <param name="result">Results from building the content and explicit asset bundle layout.</param>
|
||||
/// <returns>Return code with status information about success or failure causes.</returns>
|
||||
public static ReturnCode BuildAssetBundles(IBundleBuildParameters parameters, IBundleBuildContent content, out IBundleBuildResults result)
|
||||
{
|
||||
var taskList = DefaultBuildTasks.Create(DefaultBuildTasks.Preset.AssetBundleCompatible);
|
||||
return BuildAssetBundles(parameters, content, out result, taskList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default implementation of generating Asset Bundles using the Scriptable Build Pipeline.
|
||||
/// </summary>
|
||||
/// <param name="parameters">Set of parameters used for building asset bundles.</param>
|
||||
/// <param name="content">Set of content and explicit asset bundle layout to build.</param>
|
||||
/// <param name="result">Results from building the content and explicit asset bundle layout.</param>
|
||||
/// <param name="taskList">Custom task list for building asset bundles.</param>
|
||||
/// <param name="contextObjects">Additional context objects to make available to the build.</param>
|
||||
/// <returns>Return code with status information about success or failure causes.</returns>
|
||||
public static ReturnCode BuildAssetBundles(IBundleBuildParameters parameters, IBundleBuildContent content, out IBundleBuildResults result, IList<IBuildTask> taskList, params IContextObject[] contextObjects)
|
||||
{
|
||||
if (BuildPipeline.isBuildingPlayer)
|
||||
{
|
||||
result = null;
|
||||
BuildLogger.LogException(new InvalidOperationException("Cannot build asset bundles while a build is in progress"));
|
||||
return ReturnCode.Exception;
|
||||
}
|
||||
|
||||
// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
|
||||
if (parameters == null)
|
||||
{
|
||||
result = null;
|
||||
BuildLogger.LogException(new ArgumentNullException("parameters"));
|
||||
return ReturnCode.Exception;
|
||||
}
|
||||
|
||||
// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
|
||||
if (taskList.IsNullOrEmpty())
|
||||
{
|
||||
result = null;
|
||||
BuildLogger.LogException(new ArgumentException("Argument cannot be null or empty.", "taskList"));
|
||||
return ReturnCode.Exception;
|
||||
}
|
||||
|
||||
var contentBuildSettings = parameters.GetContentBuildSettings();
|
||||
if (!CanBuildPlayer(contentBuildSettings.target, contentBuildSettings.group))
|
||||
{
|
||||
result = null;
|
||||
BuildLogger.LogException(new InvalidOperationException("Unable to build with the current configuration, please check the Build Settings."));
|
||||
return ReturnCode.Exception;
|
||||
}
|
||||
|
||||
// Don't run if there are unsaved changes
|
||||
if (ValidationMethods.HasDirtyScenes())
|
||||
{
|
||||
result = null;
|
||||
return ReturnCode.UnsavedChanges;
|
||||
}
|
||||
|
||||
ThreadingManager.WaitForOutstandingTasks();
|
||||
BuildContext buildContext = new BuildContext(contextObjects);
|
||||
BuildLog buildLog = null;
|
||||
|
||||
IBuildLogger logger;
|
||||
if (!buildContext.TryGetContextObject<IBuildLogger>(out logger))
|
||||
{
|
||||
logger = buildLog = new BuildLog();
|
||||
buildContext.SetContextObject(buildLog);
|
||||
}
|
||||
|
||||
using (logger.ScopedStep(LogLevel.Info, "AssetDatabase.SaveAssets"))
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
ReturnCode exitCode;
|
||||
result = new BundleBuildResults();
|
||||
|
||||
#if !CI_TESTRUNNER_PROJECT
|
||||
using (new SceneStateCleanup())
|
||||
using (var progressTracker = new ProgressTracker())
|
||||
#else
|
||||
using (var progressTracker = new ProgressLoggingTracker())
|
||||
#endif
|
||||
{
|
||||
using (new AutoBuildCacheUtility())
|
||||
using (var interfacesWrapper = new BuildInterfacesWrapper())
|
||||
using (var buildCache = new BuildCache(parameters.CacheServerHost, parameters.CacheServerPort))
|
||||
{
|
||||
BuildCacheUtility.SetCurrentBuildContent(content);
|
||||
Directory.CreateDirectory(parameters.TempOutputFolder);
|
||||
Directory.CreateDirectory(parameters.ScriptOutputFolder);
|
||||
|
||||
try
|
||||
{
|
||||
buildContext.SetContextObject(parameters);
|
||||
buildContext.SetContextObject(content);
|
||||
buildContext.SetContextObject(result);
|
||||
buildContext.SetContextObject(interfacesWrapper);
|
||||
buildContext.SetContextObject(progressTracker);
|
||||
buildContext.SetContextObject(buildCache);
|
||||
// If IDeterministicIdentifiers was passed in with contextObjects, don't add the default
|
||||
if (!buildContext.ContainsContextObject(typeof(IDeterministicIdentifiers)))
|
||||
buildContext.SetContextObject(parameters.ContiguousBundles ? new PrefabPackedIdentifiers() : (IDeterministicIdentifiers)new Unity5PackedIdentifiers());
|
||||
buildContext.SetContextObject(new BuildDependencyData());
|
||||
buildContext.SetContextObject(new ObjectDependencyData());
|
||||
buildContext.SetContextObject(new BundleWriteData());
|
||||
buildContext.SetContextObject(BuildCallbacks);
|
||||
buildCache.SetBuildLogger(logger);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
|
||||
result = null;
|
||||
BuildLogger.LogException(e);
|
||||
return ReturnCode.Exception;
|
||||
}
|
||||
|
||||
exitCode = BuildTasksRunner.Validate(taskList, buildContext);
|
||||
if (exitCode >= ReturnCode.Success)
|
||||
#if SBP_PROFILER_ENABLE
|
||||
exitCode = BuildTasksRunner.RunProfiled(taskList, buildContext);
|
||||
#else
|
||||
exitCode = BuildTasksRunner.Run(taskList, buildContext);
|
||||
#endif
|
||||
|
||||
if (Directory.Exists(parameters.TempOutputFolder))
|
||||
Directory.Delete(parameters.TempOutputFolder, true);
|
||||
|
||||
if (buildLog != null)
|
||||
{
|
||||
string buildLogPath = parameters.GetOutputFilePathForIdentifier("buildlogtep.json");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(buildLogPath));
|
||||
File.WriteAllText(parameters.GetOutputFilePathForIdentifier("buildlogtep.json"), buildLog.FormatForTraceEventProfiler());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long maximumCacheSize = ScriptableBuildPipeline.maximumCacheSize * BuildCache.k_BytesToGigaBytes;
|
||||
BuildCache.PruneCache_Background(maximumCacheSize);
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
//Functionality has been removed due to issues with APV in yamato for package release (https://jira.unity3d.com/browse/BPSBP-735)
|
||||
private static bool CanBuildPlayer(BuildTarget target, BuildTargetGroup targetGroup)
|
||||
{
|
||||
// The Editor APIs we need only exist in 2021.3 and later. For earlier versions, assume we can build.
|
||||
//#if UNITY_2021_3_OR_NEWER
|
||||
// var module = ModuleManager.GetTargetStringFrom(targetGroup, target);
|
||||
// var buildWindowExtension = ModuleManager.GetBuildWindowExtension(module);
|
||||
// return buildWindowExtension != null ? buildWindowExtension.EnabledBuildButton() : false;
|
||||
//#else
|
||||
return true;
|
||||
//#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3ba8763d94231c9459f5a2d2aae30cfa
|
||||
timeCreated: 1504709533
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 83be1c14cfbe90c4288847f2b01c1884
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Injector
|
||||
{
|
||||
/// <summary>
|
||||
/// Use to pass around information between build tasks.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class InjectContextAttribute : Attribute
|
||||
{
|
||||
//public string Identifier { get; set; }
|
||||
/// <summary>
|
||||
/// Stores the how the attribute is used among build tasks.
|
||||
/// </summary>
|
||||
public ContextUsage Usage { get; set; }
|
||||
/// <summary>
|
||||
/// Stores whether using the context attribute is optional.
|
||||
/// </summary>
|
||||
public bool Optional { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new context attribute that stores information that can be passed between build tasks.
|
||||
/// </summary>
|
||||
/// <param name="usage">The usage behavior for the attribute. By default it is set to <see cref="ContextUsage.InOut"/>.</param>
|
||||
/// <param name="optional">Set to true if using the attribute is optional. Set to false otherwise.</param>
|
||||
public InjectContextAttribute(ContextUsage usage = ContextUsage.InOut, bool optional = false)
|
||||
{
|
||||
this.Usage = usage;
|
||||
Optional = optional;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Options for how the attribute is used among build tasks. It can be either injected to and or extracted from a build task.
|
||||
/// </summary>
|
||||
public enum ContextUsage
|
||||
{
|
||||
/// <summary>
|
||||
/// Use to indicate that the attribute can be injected to and extracted from a build task.
|
||||
/// </summary>
|
||||
InOut,
|
||||
/// <summary>
|
||||
/// Use to indicate that the attribute can only be injected to a build task.
|
||||
/// </summary>
|
||||
In,
|
||||
/// <summary>
|
||||
/// Use to indicate that the attribute can only be extracted from a build task.
|
||||
/// </summary>
|
||||
Out
|
||||
}
|
||||
|
||||
class ContextInjector
|
||||
{
|
||||
public static void Inject(IBuildContext context, object obj)
|
||||
{
|
||||
FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
foreach (FieldInfo field in fields)
|
||||
{
|
||||
object[] attrs = field.GetCustomAttributes(typeof(InjectContextAttribute), true);
|
||||
if (attrs.Length == 0)
|
||||
continue;
|
||||
|
||||
InjectContextAttribute attr = attrs[0] as InjectContextAttribute;
|
||||
if (attr == null || attr.Usage == ContextUsage.Out)
|
||||
continue;
|
||||
|
||||
object injectionObject;
|
||||
if (field.FieldType == typeof(IBuildContext))
|
||||
injectionObject = context;
|
||||
else if (!attr.Optional)
|
||||
injectionObject = context.GetContextObject(field.FieldType);
|
||||
else
|
||||
{
|
||||
IContextObject contextObject;
|
||||
context.TryGetContextObject(field.FieldType, out contextObject);
|
||||
injectionObject = contextObject;
|
||||
}
|
||||
|
||||
field.SetValue(obj, injectionObject);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Extract(IBuildContext context, object obj)
|
||||
{
|
||||
FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
foreach (FieldInfo field in fields)
|
||||
{
|
||||
object[] attrs = field.GetCustomAttributes(typeof(InjectContextAttribute), true);
|
||||
if (attrs.Length == 0)
|
||||
continue;
|
||||
|
||||
InjectContextAttribute attr = attrs[0] as InjectContextAttribute;
|
||||
if (attr == null || attr.Usage == ContextUsage.In)
|
||||
continue;
|
||||
|
||||
if (field.FieldType == typeof(IBuildContext))
|
||||
throw new InvalidOperationException("IBuildContext can only be used with the ContextUsage.In option.");
|
||||
|
||||
IContextObject contextObject = field.GetValue(obj) as IContextObject;
|
||||
if (!attr.Optional)
|
||||
context.SetContextObject(field.FieldType, contextObject);
|
||||
else if (contextObject != null)
|
||||
context.SetContextObject(field.FieldType, contextObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 29402082393e3a1439cfaa6cc77aa31b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e501e91b337adda41bd6c22cf8cae83e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Content;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// The extended data about an asset.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ExtendedAssetData
|
||||
{
|
||||
/// <summary>
|
||||
/// List of object identifiers that are classified as asset representations (sub assets).
|
||||
/// </summary>
|
||||
public List<ObjectIdentifier> Representations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, initializes properties to defaults
|
||||
/// </summary>
|
||||
public ExtendedAssetData()
|
||||
{
|
||||
Representations = new List<ObjectIdentifier>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for the storing extended data about an asset.
|
||||
/// </summary>
|
||||
public interface IBuildExtendedAssetData : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Map of asset to extended data about an asset.
|
||||
/// </summary>
|
||||
Dictionary<GUID, ExtendedAssetData> ExtendedData { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 892bac4397edc914d9ffa4cde040eb0b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Base interface for the Build Caching
|
||||
/// </summary>
|
||||
public interface IBuildCache : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a CacheEntry for an asset identified by its GUID.
|
||||
/// </summary>
|
||||
/// <param name="asset">GUID identifier for an asset from the Asset Database</param>
|
||||
/// <param name="version">Version number of the system asking for an entry to distinguish it from previous incompatible entries. (Optional)</param>
|
||||
/// <returns>CacheEntry representing current asset.</returns>
|
||||
CacheEntry GetCacheEntry(GUID asset, int version = 1);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a CacheEntry for a file identified by its relative path.
|
||||
/// </summary>
|
||||
/// <param name="path">Relative path of a file on disk</param>
|
||||
/// <param name="version">Version number of the system asking for an entry to distinguish it from previous incompatible entries. (Optional)</param>
|
||||
/// <returns>CacheEntry representing a file on disk.</returns>
|
||||
CacheEntry GetCacheEntry(string path, int version = 1);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a CacheEntry for an object identified by an Object Identifier.
|
||||
/// </summary>
|
||||
/// <param name="objectID">Object identifier for an object</param>
|
||||
/// <param name="version">Version number of the system asking for an entry to distinguish it from previous incompatible entries. (Optional)</param>
|
||||
/// <returns>CacheEntry representing an object identifier.</returns>
|
||||
CacheEntry GetCacheEntry(ObjectIdentifier objectID, int version = 1);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a CacheEntry for a scripting type by a System.Type.
|
||||
/// </summary>
|
||||
/// <param name="type">System.Type for a scripting type</param>
|
||||
/// <param name="version">Version number of the system asking for an entry to distinguish it from previous incompatible entries. (Optional)</param>
|
||||
/// <returns>CacheEntry representing an object identifier.</returns>
|
||||
CacheEntry GetCacheEntry(Type type, int version = 1);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the CachedInfo passed in needs to be rebuilt
|
||||
/// </summary>
|
||||
/// <param name="info">Cached Info to check</param>
|
||||
/// <returns><c>true</c> if the cached info needs to be rebuilt; otherwise, <c>false</c>.</returns>
|
||||
bool HasAssetOrDependencyChanged(CachedInfo info);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path where info data can be saved in the cache
|
||||
/// </summary>
|
||||
/// <param name="entry">Cache entry to get the path</param>
|
||||
/// <returns>Path on disk where to save cached info</returns>
|
||||
string GetCachedInfoFile(CacheEntry entry);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path where artifact data can be saved in the cache
|
||||
/// </summary>
|
||||
/// <param name="entry">Cache entry to get the path</param>
|
||||
/// <returns>Path on disk where to save cached artifacts</returns>
|
||||
string GetCachedArtifactsDirectory(CacheEntry entry);
|
||||
|
||||
/// <summary>
|
||||
/// Loads a set of CachedInfos from the cache
|
||||
/// </summary>
|
||||
/// <param name="entries">List of cache entries to load</param>
|
||||
/// <param name="cachedInfos">Out list of cached infos loaded</param>
|
||||
void LoadCachedData(IList<CacheEntry> entries, out IList<CachedInfo> cachedInfos);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a set of CachedInfos to the cache
|
||||
/// </summary>
|
||||
/// <param name="infos">List of cached infos to save</param>
|
||||
void SaveCachedData(IList<CachedInfo> infos);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 717b55fbf36106b449169defda0705c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,93 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Tasks;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
/// <summary>
|
||||
/// Custom Content struct mapping a source asset to a processor to generate custom data for that asset.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct CustomContent : IEquatable<CustomContent>
|
||||
{
|
||||
/// <summary>
|
||||
/// Input Asset for custom content
|
||||
/// </summary>
|
||||
public GUID Asset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Processor function to run to convert the input asset to the custom content
|
||||
/// </summary>
|
||||
public Action<GUID, CalculateCustomDependencyData> Processor;
|
||||
|
||||
/// <summary>
|
||||
/// IEquatable<CustomContent> Equals operator to handle generic collections
|
||||
/// </summary>
|
||||
/// <param name="other">Other CustomContent object to compare against.</param>
|
||||
/// <returns></returns>
|
||||
public bool Equals(CustomContent other)
|
||||
{
|
||||
return Asset == other.Asset && Processor == other.Processor;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for storing the list of Custom Assets generated during the Scriptable Build Pipeline.
|
||||
/// </summary>
|
||||
public interface ICustomAssets : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// List of Custom Assets to include.
|
||||
/// </summary>
|
||||
List<GUID> Assets { get; }
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for feeding Assets to the Scriptable Build Pipeline.
|
||||
/// </summary>
|
||||
public interface IBuildContent : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// List of Assets to include.
|
||||
/// </summary>
|
||||
List<GUID> Assets { get; }
|
||||
|
||||
/// <summary>
|
||||
/// List of Scenes to include.
|
||||
/// </summary>
|
||||
List<GUID> Scenes { get; }
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
/// <summary>
|
||||
/// List of custom content to be included in asset bundles.
|
||||
/// </summary>
|
||||
List<CustomContent> CustomAssets { get; }
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for feeding Assets with explicit Asset Bundle layout to the Scriptable Build Pipeline.
|
||||
/// </summary>
|
||||
public interface IBundleBuildContent : IBuildContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Specific layout of asset bundles to assets or scenes.
|
||||
/// </summary>
|
||||
Dictionary<string, List<GUID>> BundleLayout { get; }
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
/// <summary>
|
||||
/// Additional list of raw files to add to an asset bundle
|
||||
/// </summary>
|
||||
Dictionary<string, List<ResourceFile>> AdditionalFiles { get; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Custom loading identifiers to use for Assets or Scenes.
|
||||
/// </summary>
|
||||
Dictionary<GUID, string> Addresses { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 431079301da72b74cba77e88c2af37ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,138 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Base interface for all objects that can be stored in <see cref="IBuildContext"/>.
|
||||
/// </summary>
|
||||
public interface IContextObject {}
|
||||
|
||||
/// <summary>
|
||||
/// Base interface that handles processing the callbacks after script building step.
|
||||
/// </summary>
|
||||
public interface IScriptsCallback : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes all the callbacks after script building step.
|
||||
/// </summary>
|
||||
/// <param name="parameters">Parameters passed into the build pipeline.</param>
|
||||
/// <param name="results">Results from the script building step.</param>
|
||||
/// <returns>Return code from processing the callbacks.</returns>
|
||||
ReturnCode PostScripts(IBuildParameters parameters, IBuildResults results);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for handling running the callbacks after dependency calculation step.
|
||||
/// </summary>
|
||||
public interface IDependencyCallback : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes all the callbacks after dependency calculation step.
|
||||
/// </summary>
|
||||
/// <param name="parameters">Parameters passed into the build pipeline.</param>
|
||||
/// <param name="dependencyData">Results from the dependency calculation step.</param>
|
||||
/// <returns>Return code from processing the callbacks.</returns>
|
||||
ReturnCode PostDependency(IBuildParameters parameters, IDependencyData dependencyData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for handling running the callbacks after packing step.
|
||||
/// </summary>
|
||||
public interface IPackingCallback : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes all the callbacks after packing step.
|
||||
/// </summary>
|
||||
/// <param name="parameters">Parameters passed into the build pipeline.</param>
|
||||
/// <param name="dependencyData">Results from the dependency calculation step.</param>
|
||||
/// <param name="writeData">Results from the packing step.</param>
|
||||
/// <returns>Return code from processing the callbacks.</returns>
|
||||
ReturnCode PostPacking(IBuildParameters parameters, IDependencyData dependencyData, IWriteData writeData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for handling running the callbacks after writing step.
|
||||
/// </summary>
|
||||
public interface IWritingCallback : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes all the callbacks after writing step.
|
||||
/// </summary>
|
||||
/// <param name="parameters">Parameters passed into the build pipeline.</param>
|
||||
/// <param name="dependencyData">Results from the dependency calculation step.</param>
|
||||
/// <param name="writeData">Results from the packing step.</param>
|
||||
/// <param name="results">Results from the writing step.</param>
|
||||
/// <returns>Return code from processing the callbacks.</returns>
|
||||
ReturnCode PostWriting(IBuildParameters parameters, IDependencyData dependencyData, IWriteData writeData, IBuildResults results);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for build data container system
|
||||
/// </summary>
|
||||
public interface IBuildContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks the build context for existence of a data that is of the specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of data to check for existence.</typeparam>
|
||||
/// <returns><c>true</c> if the context contains specified type of data; otherwise, <c>false</c>.</returns>
|
||||
bool ContainsContextObject<T>() where T : IContextObject;
|
||||
|
||||
/// <summary>
|
||||
/// Checks the build context for existence of a data that is of the specified type.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of data to check for existence.</param>
|
||||
/// <returns><c>true</c> if the context contains specified type of data; otherwise, <c>false</c>.</returns>
|
||||
bool ContainsContextObject(Type type);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data of the specified type contained in the build context.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of data to return.</typeparam>
|
||||
/// <returns>The type of data specified.</returns>
|
||||
T GetContextObject<T>() where T : IContextObject;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data of the specified type contained in the build context.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of data to return.</param>
|
||||
/// <returns>The type of data specified.</returns>
|
||||
IContextObject GetContextObject(Type type);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the data of the specified type to the build context.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of data to add.</typeparam>
|
||||
/// <param name="contextObject">Object holding the data to add.</param>
|
||||
void SetContextObject<T>(IContextObject contextObject) where T : IContextObject;
|
||||
|
||||
/// <summary>
|
||||
/// Adds the data of the specified type to the build context.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of data to add.</param>
|
||||
/// <param name="contextObject">Object holding the data to add.</param>
|
||||
void SetContextObject(Type type, IContextObject contextObject);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the data to the build context. Type will be inferred using Reflection.
|
||||
/// </summary>
|
||||
/// <param name="contextObject">Object holding the data to add.</param>
|
||||
void SetContextObject(IContextObject contextObject);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the data of the specified type contained in the build context.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of data to return.</typeparam>
|
||||
/// <param name="contextObject">The object holding the data to be returned if found.</param>
|
||||
/// <returns><c>true</c> if the context was able to returned the specified data; otherwise, <c>false</c>.</returns>
|
||||
bool TryGetContextObject<T>(out T contextObject) where T : IContextObject;
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the data of the specified type contained in the build context.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of data to return.</param>
|
||||
/// <param name="contextObject">The object holding the data to be returned if found.</param>
|
||||
/// <returns><c>true</c> if the context was able to returned the specified data; otherwise, <c>false</c>.</returns>
|
||||
bool TryGetContextObject(Type type, out IContextObject contextObject);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ef728e637accb8d46ad52f863653cf75
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,211 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
|
||||
[assembly: InternalsVisibleTo("Unity.Addressables.Editor.Tests")]
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes the level of a log entry
|
||||
/// </summary>
|
||||
public enum LogLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry is reporting an error.
|
||||
/// </summary>
|
||||
Error,
|
||||
/// <summary>
|
||||
/// The entry is reporting an warning.
|
||||
/// </summary>
|
||||
Warning,
|
||||
/// <summary>
|
||||
/// The entry is reporting general information.
|
||||
/// </summary>
|
||||
Info,
|
||||
/// <summary>
|
||||
/// The entry is reporting verbose information.
|
||||
/// </summary>
|
||||
Verbose
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for monitoring the build process. Several tasks will log details of their progress through this interface.
|
||||
/// See the [Build Logging](https://docs.unity3d.com/Packages/com.unity.scriptablebuildpipeline@latest/index.html?subfolder=/manual/BuildLogger.html) documentation for more details.
|
||||
/// </summary>
|
||||
public interface IBuildLogger : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds details to the active build step
|
||||
/// </summary>
|
||||
/// <param name="level">The log level of this entry.</param>
|
||||
/// <param name="msg">The message to add.</param>
|
||||
void AddEntry(LogLevel level, string msg);
|
||||
|
||||
/// <summary>
|
||||
/// Should be called when beginning a build step.
|
||||
/// </summary>
|
||||
/// <param name="level">The log level of this step.</param>
|
||||
/// <param name="stepName">A name associated with the step. It is recommended that this name does not include specific context about the step; dynamic context should be added under the step as an entry.</param>
|
||||
/// <param name="subStepsCanBeThreaded">True if within this build step the IBuildLogger will be used on multiple threads.</param>
|
||||
void BeginBuildStep(LogLevel level, string stepName, bool subStepsCanBeThreaded);
|
||||
|
||||
/// <summary>
|
||||
/// Ends the build step.
|
||||
/// </summary>
|
||||
void EndBuildStep();
|
||||
}
|
||||
internal enum DeferredEventType
|
||||
{
|
||||
Begin,
|
||||
End,
|
||||
Info
|
||||
}
|
||||
|
||||
internal struct DeferredEvent
|
||||
{
|
||||
public LogLevel Level;
|
||||
public DeferredEventType Type;
|
||||
public double Time;
|
||||
public string Name;
|
||||
public string Context;
|
||||
}
|
||||
|
||||
internal interface IDeferredBuildLogger
|
||||
{
|
||||
void HandleDeferredEventStream(IEnumerable<DeferredEvent> events);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper class to define a scope with a using statement
|
||||
/// </summary>
|
||||
public struct ScopedBuildStep : IDisposable
|
||||
{
|
||||
IBuildLogger m_Logger;
|
||||
internal ScopedBuildStep(LogLevel level, string stepName, IBuildLogger logger, bool multiThreaded, string context)
|
||||
{
|
||||
m_Logger = logger;
|
||||
m_Logger?.BeginBuildStep(level, stepName, multiThreaded);
|
||||
if (!string.IsNullOrEmpty(context))
|
||||
m_Logger?.AddEntrySafe(level, context);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
m_Logger?.EndBuildStep();
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER || ENABLE_DETAILED_PROFILE_CAPTURING
|
||||
internal struct ProfileCaptureScope : IDisposable
|
||||
{
|
||||
IBuildLogger m_Logger;
|
||||
public ProfileCaptureScope(IBuildLogger logger, ProfileCaptureOptions options)
|
||||
{
|
||||
m_Logger = ScriptableBuildPipeline.useDetailedBuildLog ? logger : null;
|
||||
ContentBuildInterface.StartProfileCapture(options);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ContentBuildProfileEvent[] events = ContentBuildInterface.StopProfileCapture();
|
||||
|
||||
if (m_Logger == null)
|
||||
return;
|
||||
|
||||
IDeferredBuildLogger dLog = (IDeferredBuildLogger)m_Logger;
|
||||
IEnumerable<DeferredEvent> dEvents = events.Select(i =>
|
||||
{
|
||||
var e = new DeferredEvent();
|
||||
e.Level = LogLevel.Verbose;
|
||||
BuildLoggerExternsions.ConvertNativeEventName(i.Name, out e.Name, out e.Context);
|
||||
e.Time = (double)i.TimeMicroseconds / (double)1000;
|
||||
e.Type = BuildLoggerExternsions.ConvertToDeferredType(i.Type);
|
||||
return e;
|
||||
});
|
||||
dLog.HandleDeferredEventStream(dEvents);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Contains extension methods for the IBuildLogger interface
|
||||
/// </summary>
|
||||
public static class BuildLoggerExternsions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds details to the active build step
|
||||
/// </summary>
|
||||
/// <param name="log">The build log.</param>
|
||||
/// <param name="level">The log level of this entry.</param>
|
||||
/// <param name="msg">The message to add.</param>
|
||||
public static void AddEntrySafe(this IBuildLogger log, LogLevel level, string msg)
|
||||
{
|
||||
if (log != null)
|
||||
{
|
||||
log.AddEntry(level, msg);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begins a new build step and returns an ScopedBuildStep which will end the build step when disposed. It is recommended to use this in conjunction with the using statement.
|
||||
/// </summary>
|
||||
/// <param name="log">The build log.</param>
|
||||
/// <param name="level">The log level of this step.</param>
|
||||
/// <param name="stepName">A name associated with the step.</param>
|
||||
/// <param name="multiThreaded">True if within this build step the IBuildLogger will be used on multiple threads.</param>
|
||||
/// <returns>Returns a ScopedBuildStep that will end the build step when it is disposed.</returns>
|
||||
public static ScopedBuildStep ScopedStep(this IBuildLogger log, LogLevel level, string stepName, bool multiThreaded = false)
|
||||
{
|
||||
return new ScopedBuildStep(level, stepName, log, multiThreaded, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begins a new build step and returns an ScopedBuildStep which will end the build step when disposed. It is recommended to use this in conjunction with the using statement.
|
||||
/// </summary>
|
||||
/// <param name="log">The build log.</param>
|
||||
/// <param name="level">The log level of this step.</param>
|
||||
/// <param name="stepName">A name associated with the step.</param>
|
||||
/// <param name="context">Adds an entry message the build step. This allows attaching specific context data without changing the stepName.</param>
|
||||
/// <returns>Returns a ScopedBuildStep that will end the build step when it is disposed.</returns>
|
||||
public static ScopedBuildStep ScopedStep(this IBuildLogger log, LogLevel level, string stepName, string context)
|
||||
{
|
||||
return new ScopedBuildStep(level, stepName, log, false, context);
|
||||
}
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER || ENABLE_DETAILED_PROFILE_CAPTURING
|
||||
internal static DeferredEventType ConvertToDeferredType(ProfileEventType type)
|
||||
{
|
||||
if (type == ProfileEventType.Begin) return DeferredEventType.Begin;
|
||||
if (type == ProfileEventType.End) return DeferredEventType.End;
|
||||
if (type == ProfileEventType.Info) return DeferredEventType.Info;
|
||||
throw new Exception("Unknown type");
|
||||
}
|
||||
|
||||
const string k_WriteFile = "Write file:";
|
||||
const string k_WriteObject = "Write object - ";
|
||||
|
||||
internal static void ConvertNativeEventName(string nativeName, out string eventName, out string eventContext)
|
||||
{
|
||||
eventName = nativeName;
|
||||
eventContext = "";
|
||||
if (nativeName.StartsWith(k_WriteFile, StringComparison.Ordinal))
|
||||
{
|
||||
eventName = "Write File";
|
||||
eventContext = nativeName.Substring(k_WriteFile.Length);
|
||||
}
|
||||
else if (nativeName.StartsWith(k_WriteObject, StringComparison.Ordinal))
|
||||
{
|
||||
eventName = "Write Object";
|
||||
eventContext = nativeName.Substring(k_WriteObject.Length);
|
||||
}
|
||||
|
||||
if (eventContext.Any(c => c == '"'))
|
||||
eventContext = eventContext.Replace("\"", "\\\"");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4f04442bb071fe8438a7e40408a9bada
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,130 @@
|
|||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Player;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
using BuildCompression = UnityEngine.BuildCompression;
|
||||
#else
|
||||
using BuildCompression = UnityEditor.Build.Content.BuildCompression;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for the parameters container
|
||||
/// </summary>
|
||||
public interface IBuildParameters : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Target build platform. <seealso cref="BuildTarget"/>
|
||||
/// </summary>
|
||||
BuildTarget Target { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Target build platform group. <seealso cref="BuildTargetGroup"/>
|
||||
/// </summary>
|
||||
BuildTargetGroup Group { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The set of build flags to use for building content.
|
||||
/// </summary>
|
||||
ContentBuildFlags ContentBuildFlags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scripting type information to use when building content.
|
||||
/// Setting this to a previously cached value will prevent the default script compiling step.
|
||||
/// </summary>
|
||||
TypeDB ScriptInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Script compilation options to use for the script compiling step.
|
||||
/// </summary>
|
||||
ScriptCompilationOptions ScriptOptions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Temporary location to be used for artifacts generated during the build but are not part of the final output.
|
||||
/// </summary>
|
||||
string TempOutputFolder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Location to be used for compiled scripts generated during the build.
|
||||
/// </summary>
|
||||
string ScriptOutputFolder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables the use of the build cache if set to true.
|
||||
/// </summary>
|
||||
bool UseCache { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables and specifies the cache server to use.
|
||||
/// </summary>
|
||||
string CacheServerHost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The port for the cache server to use
|
||||
/// </summary>
|
||||
int CacheServerPort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Writes out a link.xml file to the output folder to use with Unity managed code stripping.
|
||||
/// </summary>
|
||||
bool WriteLinkXML { get; set; }
|
||||
|
||||
#if NONRECURSIVE_DEPENDENCY_DATA
|
||||
/// <summary>
|
||||
/// Calculates and build asset bundles using Non-Recursive Dependency calculation methods.
|
||||
/// This approach helps reduce asset bundle rebuilds and runtime memory consumption.
|
||||
/// </summary>
|
||||
bool NonRecursiveDependencies { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and returns the BuildSettings struct to use for content building.
|
||||
/// </summary>
|
||||
/// <returns>Returns the BuildSettings struct to use for content building.</returns>
|
||||
BuildSettings GetContentBuildSettings();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the output folder to use for the specified identifier.
|
||||
/// </summary>
|
||||
/// <param name="identifier">Identifier used to identify which output folder to use.</param>
|
||||
/// <returns>Returns the output folder to use for the specified identifier.</returns>
|
||||
string GetOutputFilePathForIdentifier(string identifier);
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and returns the BuildCompression struct to use for the specified identifier.
|
||||
/// </summary>
|
||||
/// <param name="identifier">Identifier used to construct the BuildCompression struct.</param>
|
||||
/// <returns>Returns the BuildCompression struct to use for a specific identifier.</returns>
|
||||
BuildCompression GetCompressionForIdentifier(string identifier);
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and returns the ScriptCompilationSettings struct to use for script compiling.
|
||||
/// </summary>
|
||||
/// <returns>Returns the ScriptCompilationSettings struct to use for script compiling.</returns>
|
||||
ScriptCompilationSettings GetScriptCompilationSettings();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for the parameters container for building bundles.
|
||||
/// </summary>
|
||||
public interface IBundleBuildParameters : IBuildParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Append the hash of the AssetBundle content to the file name.
|
||||
/// </summary>
|
||||
bool AppendHash { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Packs assets in bundles contiguously based on the ordering of the source asset which results in improved asset loading times.
|
||||
/// </summary>
|
||||
bool ContiguousBundles { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Assume sub Assets have no visible asset representations (are not visible in the Project view) which results in improved build times.
|
||||
/// Sub Assets in the built bundles cannot be accessed by AssetBundle.LoadAsset<T> or AssetBundle.LoadAllAssets<T>.
|
||||
/// </summary>
|
||||
bool DisableVisibleSubAssetRepresentations { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e18580a7226c3b34c9fa7fdb324edfe6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Player;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Build.Pipeline;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
public struct AssetResultData
|
||||
{
|
||||
public GUID Guid;
|
||||
public Hash128 Hash;
|
||||
public List<ObjectIdentifier> IncludedObjects;
|
||||
public List<ObjectIdentifier> ReferencedObjects;
|
||||
public Dictionary<ObjectIdentifier, Type[]> ObjectTypes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for the build results container
|
||||
/// </summary>
|
||||
public interface IBuildResults : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Results from the script compiling step.
|
||||
/// </summary>
|
||||
ScriptCompilationResult ScriptResults { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Map of serialized file name to results for built content.
|
||||
/// </summary>
|
||||
Dictionary<string, WriteResult> WriteResults { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Map of serialized file name to additional metadata associated with the write result.
|
||||
/// </summary>
|
||||
Dictionary<string, SerializedFileMetaData> WriteResultsMetaData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Map of Asset data included in this build
|
||||
/// </summary>
|
||||
Dictionary<GUID, AssetResultData> AssetResults { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extended interface for Asset Bundle build results container.
|
||||
/// <seealso cref="IBuildResults"/>
|
||||
/// </summary>
|
||||
public interface IBundleBuildResults : IBuildResults
|
||||
{
|
||||
/// <summary>
|
||||
/// Map of Asset Bundle name to details about the built bundle.
|
||||
/// </summary>
|
||||
Dictionary<string, BundleDetails> BundleInfos { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 87c4ff2c85dcb524685caba3bb22110c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Content;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// The importer data about a sprite asset.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SpriteImporterData
|
||||
{
|
||||
/// <summary>
|
||||
/// Property if this sprite asset is packed by the sprite packer.
|
||||
/// </summary>
|
||||
public bool PackedSprite { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Object identifier of the source texture for the sprite.
|
||||
/// </summary>
|
||||
public ObjectIdentifier SourceTexture { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base interface for the storing sprite importer data for sprite assets.
|
||||
/// </summary>
|
||||
public interface IBuildSpriteData : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Map of sprite asset to importer data.
|
||||
/// </summary>
|
||||
Dictionary<GUID, SpriteImporterData> ImporterData { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fb4c2e00689dfb34985500f260df63cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,20 @@
|
|||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Base interface of all build tasks.
|
||||
/// </summary>
|
||||
public interface IBuildTask
|
||||
{
|
||||
/// <summary>
|
||||
/// Version identifier for the build task.
|
||||
/// Primarily for caching.
|
||||
/// </summary>
|
||||
int Version { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Run task method
|
||||
/// </summary>
|
||||
/// <returns>Return code with status information about success or failure causes.</returns>
|
||||
ReturnCode Run();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8f2c2ad6904ea9147a43a79fccd94ca1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,16 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Content;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Optional interface used for overriding the location where specific objects will be serialized
|
||||
/// </summary>
|
||||
public interface IBundleExplictObjectLayout : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Map listing object identifiers and their new bundle location
|
||||
/// </summary>
|
||||
Dictionary<ObjectIdentifier, string> ExplicitObjectLocation { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1a78160a9be3bdf4d9397ca7b0466850
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,47 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Base interface for the dependency data container
|
||||
/// </summary>
|
||||
public interface IDependencyData : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Map of Asset to dependency data.
|
||||
/// </summary>
|
||||
Dictionary<GUID, AssetLoadInfo> AssetInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Map of Asset to usage data.
|
||||
/// </summary>
|
||||
Dictionary<GUID, BuildUsageTagSet> AssetUsage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Map of Scene to dependency data.
|
||||
/// </summary>
|
||||
Dictionary<GUID, SceneDependencyInfo> SceneInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Map of Scene to usage data.
|
||||
/// </summary>
|
||||
Dictionary<GUID, BuildUsageTagSet> SceneUsage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Map of Asset or Scene to pre-calculated dependency hash for caching.
|
||||
/// </summary>
|
||||
Dictionary<GUID, Hash128> DependencyHash { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Reusable cache for calculating usage tags
|
||||
/// </summary>
|
||||
BuildUsageCache DependencyUsageCache { get; }
|
||||
|
||||
/// <summary>
|
||||
/// BuildUsageTagGlobal value from GraphicsSettings
|
||||
/// </summary>
|
||||
BuildUsageTagGlobal GlobalUsage { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a99d07c2f0fab1e4f8623f5913408df5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,24 @@
|
|||
using UnityEditor.Build.Content;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Base interface for the generating deterministic identifiers for different parts of the build pipeline.
|
||||
/// </summary>
|
||||
public interface IDeterministicIdentifiers : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a deterministic internal file name from the passed in name.
|
||||
/// </summary>
|
||||
/// <param name="name">Name identifier for internal file name generation</param>
|
||||
/// <returns>Deterministic file name.</returns>
|
||||
string GenerateInternalFileName(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a deterministic id for a given object in the build.
|
||||
/// </summary>
|
||||
/// <param name="objectID">Object identifier to for id generation.</param>
|
||||
/// <returns><c>long</c> representing the id of the objectID.</returns>
|
||||
long SerializationIndexFromObjectIdentifier(ObjectIdentifier objectID);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f2f62872d2484231aa95c2eb9feb8326
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEditor.Build.Content;
|
||||
|
||||
//TODO: Remove this when we make this interface public
|
||||
[assembly: InternalsVisibleTo("Unity.Addressables.Editor", AllInternalsVisible = true)]
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Base interface for the dependency data container
|
||||
/// </summary>
|
||||
internal interface IObjectDependencyData : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Dependencies of a given object
|
||||
/// </summary>
|
||||
Dictionary<ObjectIdentifier, List<ObjectIdentifier>> ObjectDependencyMap { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c07ce938101b77544a5df7d58f37aa97
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,32 @@
|
|||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Base interface for the build progress tracker
|
||||
/// </summary>
|
||||
public interface IProgressTracker : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of build tasks to run
|
||||
/// </summary>
|
||||
int TaskCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current 0.0f to 1.0f progress though the TaskCount
|
||||
/// </summary>
|
||||
float Progress { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Increments and updated the title of the progress bar.
|
||||
/// </summary>
|
||||
/// <param name="taskTitle">The title to display on the progress bar.</param>
|
||||
/// <returns><c>false</c> if the build should not continue due to user interaction with the progress bar; otherwise, <c>true</c>.</returns>
|
||||
bool UpdateTask(string taskTitle);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the secondary information display of the progress bar.
|
||||
/// </summary>
|
||||
/// <param name="taskInfo">The secondary information to display on the progress bar.</param>
|
||||
/// <returns><c>false</c> if the build should not continue due to user interaction with the progress bar; otherwise, <c>true</c>.</returns>
|
||||
bool UpdateInfo(string taskInfo);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e25b76d1a8a87c641894e4694a750cd8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,48 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Content;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Base interface for the write data container.
|
||||
/// </summary>
|
||||
public interface IWriteData : IContextObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Map of asset to file dependencies.
|
||||
/// First dependency in the list is the main file for an asset.
|
||||
/// </summary>
|
||||
Dictionary<GUID, List<string>> AssetToFiles { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Map of file to list of objects in that file
|
||||
/// </summary>
|
||||
Dictionary<string, List<ObjectIdentifier>> FileToObjects { get; }
|
||||
|
||||
/// <summary>
|
||||
/// List of all write operations to serialize data to disk
|
||||
/// </summary>
|
||||
List<IWriteOperation> WriteOperations { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extended interface for Asset Bundle write data container.
|
||||
/// </summary>
|
||||
public interface IBundleWriteData : IWriteData
|
||||
{
|
||||
/// <summary>
|
||||
/// Map of file name to bundle name
|
||||
/// </summary>
|
||||
Dictionary<string, string> FileToBundle { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Map of file name to calculated usage set
|
||||
/// </summary>
|
||||
Dictionary<string, BuildUsageTagSet> FileToUsageSet { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Map of file name to calculated object references
|
||||
/// </summary>
|
||||
Dictionary<string, BuildReferenceMap> FileToReferenceMap { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a8092de151d449b0962952fe68a54dd9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,57 @@
|
|||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Base interface for wrapping the different low level WriteSerializeFile API around a common high level Write function
|
||||
/// </summary>
|
||||
public interface IWriteOperation
|
||||
{
|
||||
/// <summary>
|
||||
/// The specific write command containing the details about what to write to disk.
|
||||
/// <seealso cref="WriteCommand"/>
|
||||
/// </summary>
|
||||
WriteCommand Command { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The specific usage data for objects in the write command.
|
||||
/// <seealso cref="BuildUsageTagSet"/>
|
||||
/// </summary>
|
||||
BuildUsageTagSet UsageSet { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The specific reference data for objects in the write command.
|
||||
/// <seealso cref="BuildReferenceMap"/>
|
||||
/// </summary>
|
||||
BuildReferenceMap ReferenceMap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The hash that represents the unique set of input dependencies for caching this write command.
|
||||
/// </summary>
|
||||
Hash128 DependencyHash { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Write function that wraps the low level WriteSerializeFile APIs that takes the common minimum set of parameters.
|
||||
/// </summary>
|
||||
/// <param name="outputFolder">The location to write data to disk.</param>
|
||||
/// <param name="settings">The build settings to use for writing data.</param>
|
||||
/// <param name="globalUsage">The global usage to use for writing data.</param>
|
||||
/// <returns>The write results struct containing details about what was written to disk</returns>
|
||||
WriteResult Write(string outputFolder, BuildSettings settings, BuildUsageTagGlobal globalUsage);
|
||||
|
||||
/// <summary>
|
||||
/// Optimized hash function for use with the Build Cache system.
|
||||
/// </summary>
|
||||
/// <returns>Unique hash for the contents of this write operation.</returns>
|
||||
Hash128 GetHash128();
|
||||
|
||||
/// <summary>
|
||||
/// Optimized hash function for use with the Build Cache system.
|
||||
/// </summary>
|
||||
/// <param name="log">The build log.</param>
|
||||
/// <returns>Unique hash for the contents of this write operation.</returns>
|
||||
Hash128 GetHash128(IBuildLogger log);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7df65588254d9194cb3fb45879168954
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 24de8307d973e7541803ec7b592a5361
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,57 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
namespace UnityEditor.Build.Profiler
|
||||
{
|
||||
internal class BuildProfiler
|
||||
{
|
||||
Stopwatch[] m_Trackers;
|
||||
long[] m_CallCount;
|
||||
string[] m_Names;
|
||||
|
||||
public BuildProfiler(int count)
|
||||
{
|
||||
m_Trackers = new Stopwatch[count];
|
||||
m_CallCount = new long[count];
|
||||
m_Names = new string[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
m_Trackers[i] = new Stopwatch();
|
||||
m_CallCount[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void Start(int index, string name)
|
||||
{
|
||||
if (m_Trackers == null)
|
||||
return;
|
||||
|
||||
Debug.Assert(!m_Trackers[index].IsRunning);
|
||||
m_Trackers[index].Start();
|
||||
m_CallCount[index]++;
|
||||
m_Names[index] = name;
|
||||
}
|
||||
|
||||
public void Stop(int index)
|
||||
{
|
||||
if (m_Trackers == null)
|
||||
return;
|
||||
|
||||
Debug.Assert(m_Trackers[index].IsRunning);
|
||||
m_Trackers[index].Stop();
|
||||
}
|
||||
|
||||
public void Print()
|
||||
{
|
||||
if (m_Trackers == null)
|
||||
return;
|
||||
|
||||
string msg = "";
|
||||
for (int i = 0; i < m_Trackers.Length; i++)
|
||||
{
|
||||
Debug.Assert(!m_Trackers[i].IsRunning);
|
||||
msg += string.Format("Counter[{0}]\t{1}\t{2}\n", m_Names[i], m_CallCount[i], m_Trackers[i].ElapsedMilliseconds);
|
||||
}
|
||||
UnityEngine.Debug.Log(msg);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ba1f63c8c87d5ab4cad407b7245879e4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,43 @@
|
|||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Options for scriptable build pipeline return codes. Int values of these return codes are standardized to 0 or greater for Success and -1 or less for Error.
|
||||
/// </summary>
|
||||
public enum ReturnCode
|
||||
{
|
||||
// Success Codes are Positive!
|
||||
/// <summary>
|
||||
/// Use to indicate that the operation suceeded.
|
||||
/// </summary>
|
||||
Success = 0,
|
||||
/// <summary>
|
||||
/// Use to indicate that the operation suceeded.
|
||||
/// </summary>
|
||||
SuccessCached = 1,
|
||||
/// <summary>
|
||||
/// Use to indicate that the operation suceeded but did not actually execute.
|
||||
/// </summary>
|
||||
SuccessNotRun = 2,
|
||||
// Error Codes are Negative!
|
||||
/// <summary>
|
||||
/// Use to indicate that the operation encountered an error.
|
||||
/// </summary>
|
||||
Error = -1,
|
||||
/// <summary>
|
||||
/// Use to indicate that the operation encountered an exception.
|
||||
/// </summary>
|
||||
Exception = -2,
|
||||
/// <summary>
|
||||
/// Use to indicate that the operation was cancelled.
|
||||
/// </summary>
|
||||
Canceled = -3,
|
||||
/// <summary>
|
||||
/// Use to indicate that the operation failed because there are unsaved scene changes.
|
||||
/// </summary>
|
||||
UnsavedChanges = -4,
|
||||
/// <summary>
|
||||
/// Use to indicate that the operation failed because it was missing the required objects.
|
||||
/// </summary>
|
||||
MissingRequiredObjects = -5
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bef0b83030006f0409c3a3cfa181ee64
|
||||
timeCreated: 1504709534
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d2753eab703276041afb1d58301a291c
|
||||
folderAsset: yes
|
||||
timeCreated: 1505167493
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic implementation of IDependencyCallback, IPackingCallback, IWritingCallback, and IScriptsCallback.
|
||||
/// Uses Func implementation for callbacks. <seealso cref="IDependencyCallback"/>, <seealso cref="IPackingCallback"/>
|
||||
/// <seealso cref="IWritingCallback"/>, and <seealso cref="IScriptsCallback"/>
|
||||
/// </summary>
|
||||
public class BuildCallbacks : IDependencyCallback, IPackingCallback, IWritingCallback, IScriptsCallback
|
||||
{
|
||||
/// <summary>
|
||||
/// Func delegate for the callback after scripts have been compiled.
|
||||
/// </summary>
|
||||
public Func<IBuildParameters, IBuildResults, ReturnCode> PostScriptsCallbacks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Func delegate for the callback after dependency calculation has occurred.
|
||||
/// </summary>
|
||||
public Func<IBuildParameters, IDependencyData, ReturnCode> PostDependencyCallback { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Func delegate for the callback after packing has occurred.
|
||||
/// </summary>
|
||||
public Func<IBuildParameters, IDependencyData, IWriteData, ReturnCode> PostPackingCallback { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Func delegate for the callback after writing content has occurred.
|
||||
/// </summary>
|
||||
public Func<IBuildParameters, IDependencyData, IWriteData, IBuildResults, ReturnCode> PostWritingCallback { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode PostScripts(IBuildParameters parameters, IBuildResults results)
|
||||
{
|
||||
if (PostScriptsCallbacks != null)
|
||||
return PostScriptsCallbacks(parameters, results);
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode PostDependency(IBuildParameters buildParameters, IDependencyData dependencyData)
|
||||
{
|
||||
if (PostDependencyCallback != null)
|
||||
return PostDependencyCallback(buildParameters, dependencyData);
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode PostPacking(IBuildParameters buildParameters, IDependencyData dependencyData, IWriteData writeData)
|
||||
{
|
||||
if (PostPackingCallback != null)
|
||||
return PostPackingCallback(buildParameters, dependencyData, writeData);
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode PostWriting(IBuildParameters parameters, IDependencyData dependencyData, IWriteData writeData, IBuildResults results)
|
||||
{
|
||||
if (PostWritingCallback != null)
|
||||
return PostWritingCallback(parameters, dependencyData, writeData, results);
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 98f1571a4d4b4a3f8a65343e6ca1966d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,172 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
using UnityEditor.Build.Content;
|
||||
#endif
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
/// <summary>
|
||||
/// Basic implementation of ICustomAssets. Stores the list of Custom Assets generated during the Scriptable Build Pipeline.
|
||||
/// <seealso cref="ICustomAssets"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class CustomAssets : ICustomAssets
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public List<GUID> Assets { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, creates an empty CustomAssets.
|
||||
/// </summary>
|
||||
public CustomAssets()
|
||||
{
|
||||
Assets = new List<GUID>();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Basic implementation of IBuildContent. Stores the list of Assets to feed the Scriptable Build Pipeline.
|
||||
/// <seealso cref="IBuildContent"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class BuildContent : IBuildContent
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public List<GUID> Assets { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<GUID> Scenes { get; private set; }
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
/// <inheritdoc />
|
||||
public List<CustomContent> CustomAssets { get; private set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, creates an empty BuildContent.
|
||||
/// </summary>
|
||||
public BuildContent() {}
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, takes a set of Assets and converts them to the appropriate properties.
|
||||
/// </summary>
|
||||
/// <param name="assets">The set of Assets identified by GUID to ensure are packaged with the build</param>
|
||||
public BuildContent(IEnumerable<GUID> assets)
|
||||
{
|
||||
if (assets == null)
|
||||
throw new ArgumentNullException("assets");
|
||||
|
||||
Assets = new List<GUID>();
|
||||
Scenes = new List<GUID>();
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
CustomAssets = new List<CustomContent>();
|
||||
#endif
|
||||
|
||||
foreach (var asset in assets)
|
||||
{
|
||||
ValidationMethods.Status assetType = ValidationMethods.ValidAsset(asset);
|
||||
if (assetType == ValidationMethods.Status.Asset)
|
||||
Assets.Add(asset);
|
||||
else if (assetType == ValidationMethods.Status.Scene)
|
||||
Scenes.Add(asset);
|
||||
else
|
||||
throw new ArgumentException(string.Format("Asset '{0}' is not a valid Asset or Scene.", asset.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Basic implementation of IBundleBuildContent. Stores the list of Assets with explicit Asset Bundle layout to feed the Scriptable Build Pipeline.
|
||||
/// <seealso cref="IBundleBuildContent"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class BundleBuildContent : IBundleBuildContent
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public List<GUID> Assets { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<GUID> Scenes { get; private set; }
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
/// <inheritdoc />
|
||||
public List<CustomContent> CustomAssets { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, List<ResourceFile>> AdditionalFiles { get; private set; }
|
||||
#endif
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<GUID, string> Addresses { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, List<GUID>> BundleLayout { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, creates an empty BundleBuildContent.
|
||||
/// </summary>
|
||||
public BundleBuildContent() {}
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, takes a set of AssetBundleBuild and converts them to the appropriate properties.
|
||||
/// </summary>
|
||||
/// <param name="bundleBuilds">The set of AssetbundleBuild to be built.</param>
|
||||
public BundleBuildContent(IEnumerable<AssetBundleBuild> bundleBuilds)
|
||||
{
|
||||
if (bundleBuilds == null)
|
||||
throw new ArgumentNullException("bundleBuilds");
|
||||
|
||||
Assets = new List<GUID>();
|
||||
Scenes = new List<GUID>();
|
||||
Addresses = new Dictionary<GUID, string>();
|
||||
BundleLayout = new Dictionary<string, List<GUID>>();
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
CustomAssets = new List<CustomContent>();
|
||||
AdditionalFiles = new Dictionary<string, List<ResourceFile>>();
|
||||
#endif
|
||||
|
||||
foreach (var bundleBuild in bundleBuilds)
|
||||
{
|
||||
List<GUID> guids;
|
||||
BundleLayout.GetOrAdd(bundleBuild.assetBundleName, out guids);
|
||||
ValidationMethods.Status bundleType = ValidationMethods.Status.Invalid;
|
||||
|
||||
for (int i = 0; i < bundleBuild.assetNames.Length; i++)
|
||||
{
|
||||
string assetPath = bundleBuild.assetNames[i];
|
||||
GUID asset = new GUID(AssetDatabase.AssetPathToGUID(assetPath));
|
||||
|
||||
// Ensure the path is valid
|
||||
ValidationMethods.Status status = ValidationMethods.ValidAsset(asset);
|
||||
if (status == ValidationMethods.Status.Invalid)
|
||||
throw new ArgumentException(string.Format("Asset '{0}' is not a valid Asset or Scene.", assetPath));
|
||||
|
||||
// Ensure we do not have a mixed bundle
|
||||
if (bundleType == ValidationMethods.Status.Invalid)
|
||||
bundleType = status;
|
||||
else if (bundleType != status)
|
||||
throw new ArgumentException(string.Format("Asset Bundle '{0}' is invalid because it contains mixed Asset and Scene types.", bundleBuild.assetBundleName));
|
||||
|
||||
string address = bundleBuild.addressableNames != null && i < bundleBuild.addressableNames.Length && !string.IsNullOrEmpty(bundleBuild.addressableNames[i]) ?
|
||||
bundleBuild.addressableNames[i] : AssetDatabase.GUIDToAssetPath(asset.ToString());
|
||||
|
||||
// Add the guid to the bundle map
|
||||
guids.Add(asset);
|
||||
// Add the guid & address
|
||||
Addresses.Add(asset, address);
|
||||
|
||||
// Add the asset to the correct collection
|
||||
if (status == ValidationMethods.Status.Asset)
|
||||
Assets.Add(asset);
|
||||
else if (status == ValidationMethods.Status.Scene)
|
||||
Scenes.Add(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6616141fe64e4fc2b16c015f32d0a64d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,156 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic implementation of IBuildContext. Stores data generated during a build.
|
||||
/// <seealso cref="IBuildContext"/>
|
||||
/// </summary>
|
||||
public class BuildContext : IBuildContext
|
||||
{
|
||||
internal Dictionary<Type, IContextObject> m_ContextObjects;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public BuildContext()
|
||||
{
|
||||
m_ContextObjects = new Dictionary<Type, IContextObject>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, adds the passed in parameters to the context.
|
||||
/// </summary>
|
||||
/// <param name="buildParams">The set of initial parameters to add to the context.</param>
|
||||
public BuildContext(params IContextObject[] buildParams)
|
||||
{
|
||||
m_ContextObjects = new Dictionary<Type, IContextObject>();
|
||||
|
||||
if (buildParams == null)
|
||||
return;
|
||||
|
||||
foreach (var buildParam in buildParams)
|
||||
{
|
||||
if (buildParam != null)
|
||||
SetContextObject(buildParam);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetContextObject<T>(IContextObject contextObject) where T : IContextObject
|
||||
{
|
||||
if (contextObject == null)
|
||||
throw new ArgumentNullException("contextObject");
|
||||
|
||||
var type = typeof(T);
|
||||
if (!type.IsInterface)
|
||||
throw new InvalidOperationException(string.Format("Passed in type '{0}' is not an interface.", type));
|
||||
if (!(contextObject is T))
|
||||
throw new InvalidOperationException(string.Format("'{0}' is not of passed in type '{1}'.", contextObject.GetType(), type));
|
||||
m_ContextObjects[typeof(T)] = contextObject;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetContextObject(Type type, IContextObject contextObject)
|
||||
{
|
||||
if (contextObject == null)
|
||||
throw new ArgumentNullException("contextObject");
|
||||
|
||||
if (!type.IsInterface)
|
||||
throw new InvalidOperationException(string.Format("Passed in type '{0}' is not an interface.", type));
|
||||
if (!type.IsInstanceOfType(contextObject))
|
||||
throw new InvalidOperationException(string.Format("'{0}' is not of passed in type '{1}'.", contextObject.GetType(), type));
|
||||
m_ContextObjects[type] = contextObject;
|
||||
}
|
||||
|
||||
private IEnumerable<Type> WalkAssignableTypes(IContextObject contextObject)
|
||||
{
|
||||
var iCType = typeof(IContextObject);
|
||||
foreach (Type t in contextObject.GetType().GetInterfaces())
|
||||
{
|
||||
if (iCType.IsAssignableFrom(t) && t != iCType)
|
||||
yield return t;
|
||||
}
|
||||
|
||||
for (var current = contextObject.GetType(); current != null; current = current.BaseType)
|
||||
if (iCType.IsAssignableFrom(current) && current != iCType)
|
||||
yield return current;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetContextObject(IContextObject contextObject)
|
||||
{
|
||||
if (contextObject == null)
|
||||
throw new ArgumentNullException("contextObject");
|
||||
|
||||
List<Type> types = new List<Type>(WalkAssignableTypes(contextObject));
|
||||
if (types.Count == 0)
|
||||
throw new Exception($"Could not determine context object type for object of type {contextObject.GetType().FullName}");
|
||||
types.ForEach(x => m_ContextObjects[x] = contextObject);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ContainsContextObject<T>() where T : IContextObject
|
||||
{
|
||||
return ContainsContextObject(typeof(T));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ContainsContextObject(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
return m_ContextObjects.ContainsKey(type);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public T GetContextObject<T>() where T : IContextObject
|
||||
{
|
||||
return (T)GetContextObject(typeof(T));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IContextObject GetContextObject(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (!m_ContextObjects.ContainsKey(type))
|
||||
throw new Exception($"Object of Type {type} was not available within the BuildContext");
|
||||
|
||||
return m_ContextObjects[type];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetContextObject<T>(out T contextObject) where T : IContextObject
|
||||
{
|
||||
IContextObject cachedContextObject;
|
||||
if (m_ContextObjects.TryGetValue(typeof(T), out cachedContextObject) && cachedContextObject is T)
|
||||
{
|
||||
contextObject = (T)cachedContextObject;
|
||||
return true;
|
||||
}
|
||||
|
||||
contextObject = default(T);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetContextObject(Type type, out IContextObject contextObject)
|
||||
{
|
||||
IContextObject cachedContextObject;
|
||||
if (m_ContextObjects.TryGetValue(type, out cachedContextObject) && type.IsInstanceOfType(cachedContextObject))
|
||||
{
|
||||
contextObject = cachedContextObject;
|
||||
return true;
|
||||
}
|
||||
|
||||
contextObject = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fdd470c95bb040bdb705dc362b132291
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,84 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic implementation of IDependencyData. Stores the dependency and usage data calculated during a build.
|
||||
/// <seealso cref="IDependencyData"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class BuildDependencyData : IDependencyData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Dictionary<GUID, AssetLoadInfo> AssetInfo { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<GUID, BuildUsageTagSet> AssetUsage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<GUID, SceneDependencyInfo> SceneInfo { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<GUID, BuildUsageTagSet> SceneUsage { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<GUID, Hash128> DependencyHash { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Stores how lighting information is being used during a build.
|
||||
/// </summary>
|
||||
public BuildUsageTagGlobal GlobalUsage { get; set; }
|
||||
|
||||
[NonSerialized]
|
||||
BuildUsageCache m_BuildUsageCache;
|
||||
|
||||
/// <summary>
|
||||
/// Stores the dependency caching object.
|
||||
/// </summary>
|
||||
public BuildUsageCache DependencyUsageCache
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_BuildUsageCache == null)
|
||||
m_BuildUsageCache = new BuildUsageCache();
|
||||
return m_BuildUsageCache;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, initializes properties to defaults
|
||||
/// </summary>
|
||||
public BuildDependencyData()
|
||||
{
|
||||
AssetInfo = new Dictionary<GUID, AssetLoadInfo>();
|
||||
AssetUsage = new Dictionary<GUID, BuildUsageTagSet>();
|
||||
SceneInfo = new Dictionary<GUID, SceneDependencyInfo>();
|
||||
SceneUsage = new Dictionary<GUID, BuildUsageTagSet>();
|
||||
DependencyHash = new Dictionary<GUID, Hash128>();
|
||||
m_BuildUsageCache = new BuildUsageCache();
|
||||
GlobalUsage = GraphicsSettingsApi.GetGlobalUsage();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Basic implementation of IObjectDependencyData. Stores the dependencies between objects calculated during a build.
|
||||
/// <seealso cref="IObjectDependencyData"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal class ObjectDependencyData : IObjectDependencyData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Dictionary<ObjectIdentifier, List<ObjectIdentifier>> ObjectDependencyMap { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, initializes properties to defaults
|
||||
/// </summary>
|
||||
public ObjectDependencyData()
|
||||
{
|
||||
ObjectDependencyMap = new Dictionary<ObjectIdentifier, List<ObjectIdentifier>>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 48594b0afbd3e84448546c74bf35a6b3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic implementation of IBuildExtendedAssetData. Stores the extended data about an asset in the build.
|
||||
/// <seealso cref="IBuildExtendedAssetData"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class BuildExtendedAssetData : IBuildExtendedAssetData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Dictionary<GUID, ExtendedAssetData> ExtendedData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, initializes properties to defaults
|
||||
/// </summary>
|
||||
public BuildExtendedAssetData()
|
||||
{
|
||||
ExtendedData = new Dictionary<GUID, ExtendedAssetData>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9b0e503817aafa447ac3b7d7db84ccc8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,189 @@
|
|||
using System;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEditor.Build.Player;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
using BuildCompression = UnityEngine.BuildCompression;
|
||||
#else
|
||||
using BuildCompression = UnityEditor.Build.Content.BuildCompression;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Basic implementation of IBuildParameters. Stores the set of parameters passed into the Scriptable Build Pipeline.
|
||||
/// <seealso cref="IBuildParameters"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class BuildParameters : IBuildParameters
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public BuildTarget Target { get; set; }
|
||||
/// <inheritdoc />
|
||||
public BuildTargetGroup Group { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ContentBuildFlags ContentBuildFlags { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public TypeDB ScriptInfo { get; set; }
|
||||
/// <inheritdoc />
|
||||
public ScriptCompilationOptions ScriptOptions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default compression option to use for all built content files
|
||||
/// </summary>
|
||||
public BuildCompression BundleCompression { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Final output location where built content will be written.
|
||||
/// </summary>
|
||||
public string OutputFolder { get; set; }
|
||||
|
||||
string m_TempOutputFolder;
|
||||
/// <inheritdoc />
|
||||
public string TempOutputFolder
|
||||
{
|
||||
get { return m_TempOutputFolder; }
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
throw new ArgumentException("Argument cannot be null or empty.", "value");
|
||||
m_TempOutputFolder = value;
|
||||
}
|
||||
}
|
||||
|
||||
string m_ScriptOutputFolder;
|
||||
/// <inheritdoc />
|
||||
public string ScriptOutputFolder
|
||||
{
|
||||
get { return m_ScriptOutputFolder; }
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
throw new ArgumentException("Argument cannot be null or empty.", "value");
|
||||
m_ScriptOutputFolder = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool UseCache { get; set; }
|
||||
/// <inheritdoc />
|
||||
public string CacheServerHost { get; set; }
|
||||
/// <inheritdoc />
|
||||
public int CacheServerPort { get; set; }
|
||||
/// <inheritdoc />
|
||||
public bool WriteLinkXML { get; set; }
|
||||
#if NONRECURSIVE_DEPENDENCY_DATA
|
||||
/// <inheritdoc />
|
||||
public bool NonRecursiveDependencies { get; set; }
|
||||
#endif
|
||||
|
||||
internal BuildParameters() {}
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, requires the target, group and output parameters at minimum for a successful build.
|
||||
/// </summary>
|
||||
/// <param name="target">The target for building content.</param>
|
||||
/// <param name="group">The group for building content.</param>
|
||||
/// <param name="outputFolder">The final output location for built content.</param>
|
||||
public BuildParameters(BuildTarget target, BuildTargetGroup group, string outputFolder)
|
||||
{
|
||||
if (string.IsNullOrEmpty(outputFolder))
|
||||
throw new ArgumentException("Argument cannot be null or empty.", "outputFolder");
|
||||
|
||||
Target = target;
|
||||
Group = group;
|
||||
// TODO: Validate target & group
|
||||
|
||||
ScriptInfo = null;
|
||||
ScriptOptions = ScriptCompilationOptions.None;
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
BundleCompression = BuildCompression.LZMA;
|
||||
#else
|
||||
BundleCompression = BuildCompression.DefaultLZMA;
|
||||
#endif
|
||||
OutputFolder = outputFolder;
|
||||
TempOutputFolder = ContentPipeline.kTempBuildPath;
|
||||
ScriptOutputFolder = ContentPipeline.kScriptBuildPath;
|
||||
UseCache = true;
|
||||
CacheServerPort = 8126;
|
||||
if (ScriptableBuildPipeline.UseBuildCacheServer)
|
||||
{
|
||||
CacheServerHost = ScriptableBuildPipeline.CacheServerHost;
|
||||
CacheServerPort = ScriptableBuildPipeline.CacheServerPort;
|
||||
}
|
||||
|
||||
WriteLinkXML = false;
|
||||
|
||||
#if NONRECURSIVE_DEPENDENCY_DATA && UNITY_2021_1_OR_NEWER
|
||||
NonRecursiveDependencies = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual BuildSettings GetContentBuildSettings()
|
||||
{
|
||||
return new BuildSettings
|
||||
{
|
||||
group = Group,
|
||||
target = Target,
|
||||
typeDB = ScriptInfo,
|
||||
buildFlags = ContentBuildFlags
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual ScriptCompilationSettings GetScriptCompilationSettings()
|
||||
{
|
||||
return new ScriptCompilationSettings
|
||||
{
|
||||
group = Group,
|
||||
target = Target,
|
||||
options = ScriptOptions
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual string GetOutputFilePathForIdentifier(string identifier)
|
||||
{
|
||||
return string.Format("{0}/{1}", OutputFolder, identifier);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual BuildCompression GetCompressionForIdentifier(string identifier)
|
||||
{
|
||||
return BundleCompression;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores the set of parameters passed into Scriptable Build Pipeline when building bundles.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class BundleBuildParameters : BuildParameters, IBundleBuildParameters
|
||||
{
|
||||
internal BundleBuildParameters() {}
|
||||
|
||||
/// <inheritdoc />
|
||||
public BundleBuildParameters(BuildTarget target, BuildTargetGroup group, string outputFolder)
|
||||
: base(target, group, outputFolder)
|
||||
{
|
||||
#if UNITY_2021_1_OR_NEWER
|
||||
ContiguousBundles = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool AppendHash { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ContiguousBundles { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool DisableVisibleSubAssetRepresentations { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 33d6ef15c1984642bd83826064bee25d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,83 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Player;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Build.Pipeline;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Additional MetaData that is associated with a serialized file write result
|
||||
/// <seealso cref="IBuildResults"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SerializedFileMetaData
|
||||
{
|
||||
/// <summary>
|
||||
/// A hash of all the serialized files
|
||||
/// </summary>
|
||||
public Hash128 RawFileHash;
|
||||
/// <summary>
|
||||
/// Hash of file contents. Some resource files may choose to exclude sections of their content from this hash. For example,
|
||||
/// serialized files exclude the header of their content which allows this hash not to change with new Unity versions.
|
||||
/// </summary>
|
||||
public Hash128 ContentHash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Basic implementation of IBuildResults. Stores the results for script compilation and content building.
|
||||
/// <seealso cref="IBuildResults"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class BuildResults : IBuildResults
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ScriptCompilationResult ScriptResults { get; set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, WriteResult> WriteResults { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, SerializedFileMetaData> WriteResultsMetaData { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<GUID, AssetResultData> AssetResults { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, initializes properties to defaults
|
||||
/// </summary>
|
||||
public BuildResults()
|
||||
{
|
||||
WriteResults = new Dictionary<string, WriteResult>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Basic implementation of IBundleBuildResults. Stores the results for script compilation and asset bundle building.
|
||||
/// <seealso cref="IBundleBuildResults"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class BundleBuildResults : IBundleBuildResults
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ScriptCompilationResult ScriptResults { get; set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, BundleDetails> BundleInfos { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, WriteResult> WriteResults { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, SerializedFileMetaData> WriteResultsMetaData { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<GUID, AssetResultData> AssetResults { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, initializes properties to defaults
|
||||
/// </summary>
|
||||
public BundleBuildResults()
|
||||
{
|
||||
BundleInfos = new Dictionary<string, BundleDetails>();
|
||||
WriteResults = new Dictionary<string, WriteResult>();
|
||||
WriteResultsMetaData = new Dictionary<string, SerializedFileMetaData>();
|
||||
AssetResults = new Dictionary<GUID, AssetResultData>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 63ad63bf47749b944a87fce982b8b54b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic implementation of IBuildSpriteData. Stores the sprite importer data for a sprite asset in the build.
|
||||
/// <seealso cref="IBuildSpriteData"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class BuildSpriteData : IBuildSpriteData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Dictionary<GUID, SpriteImporterData> ImporterData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, initializes properties to defaults
|
||||
/// </summary>
|
||||
public BuildSpriteData()
|
||||
{
|
||||
ImporterData = new Dictionary<GUID, SpriteImporterData>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 54aaf7e8e1f02d34182d881089f11f33
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,186 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEditor.Build.Profiler;
|
||||
using UnityEditor.Build.Reporting;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic static class containing default implementations for BuildTask validation and running.
|
||||
/// </summary>
|
||||
public static class BuildTasksRunner
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic run implementation that takes a set of tasks, a context, and runs returning the build results.
|
||||
/// <seealso cref="IBuildTask"/>, <seealso cref="IBuildContext"/>, and <seealso cref="ReturnCode"/>
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The set of build tasks to run.</param>
|
||||
/// <param name="context">The build context to use for this run.</param>
|
||||
/// <returns>Return code with status information about success or failure causes.</returns>
|
||||
public static ReturnCode Run(IList<IBuildTask> pipeline, IBuildContext context)
|
||||
{
|
||||
// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
|
||||
if (pipeline == null)
|
||||
{
|
||||
BuildLogger.LogException(new ArgumentNullException("pipeline"));
|
||||
return ReturnCode.Exception;
|
||||
}
|
||||
|
||||
// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
|
||||
if (context == null)
|
||||
{
|
||||
BuildLogger.LogException(new ArgumentNullException("context"));
|
||||
return ReturnCode.Exception;
|
||||
}
|
||||
|
||||
IProgressTracker tracker;
|
||||
if (context.TryGetContextObject(out tracker))
|
||||
tracker.TaskCount = pipeline.Count;
|
||||
|
||||
context.TryGetContextObject(out IBuildLogger logger);
|
||||
|
||||
foreach (IBuildTask task in pipeline)
|
||||
{
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!tracker.UpdateTaskUnchecked(task.GetType().Name.HumanReadable()))
|
||||
return ReturnCode.Canceled;
|
||||
|
||||
ContextInjector.Inject(context, task);
|
||||
ReturnCode result;
|
||||
using (logger.ScopedStep(LogLevel.Info, task.GetType().Name))
|
||||
result = task.Run();
|
||||
if (result < ReturnCode.Success)
|
||||
return result;
|
||||
ContextInjector.Extract(context, task);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BuildLogger.LogError("Build Task {0} failed with exception:\n{1}\n{2}", task.GetType().Name, e.Message, e.StackTrace);
|
||||
return ReturnCode.Exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tracker is IDisposable disposable)
|
||||
disposable.Dispose();
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run implementation with task profiler that takes a set of tasks, a context, runs returning the build results and prints out the profiler details.
|
||||
/// <seealso cref="IBuildTask"/>, <seealso cref="IBuildContext"/>, and <seealso cref="ReturnCode"/>
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The set of build tasks to run.</param>
|
||||
/// <param name="context">The build context to use for this run.</param>
|
||||
/// <returns>Return code with status information about success or failure causes.</returns>
|
||||
internal static ReturnCode RunProfiled(IList<IBuildTask> pipeline, IBuildContext context)
|
||||
{
|
||||
// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
|
||||
if (pipeline == null)
|
||||
{
|
||||
BuildLogger.LogException(new ArgumentNullException("pipeline"));
|
||||
return ReturnCode.Exception;
|
||||
}
|
||||
|
||||
// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
|
||||
if (context == null)
|
||||
{
|
||||
BuildLogger.LogException(new ArgumentNullException("context"));
|
||||
return ReturnCode.Exception;
|
||||
}
|
||||
|
||||
var profiler = new BuildProfiler(pipeline.Count + 1);
|
||||
profiler.Start(pipeline.Count, "TotalTime");
|
||||
int count = 0;
|
||||
|
||||
IProgressTracker tracker;
|
||||
if (context.TryGetContextObject(out tracker))
|
||||
tracker.TaskCount = pipeline.Count;
|
||||
|
||||
foreach (IBuildTask task in pipeline)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!tracker.UpdateTaskUnchecked(task.GetType().Name.HumanReadable()))
|
||||
{
|
||||
profiler.Stop(pipeline.Count);
|
||||
profiler.Print();
|
||||
return ReturnCode.Canceled;
|
||||
}
|
||||
|
||||
ContextInjector.Inject(context, task);
|
||||
profiler.Start(count, task.GetType().Name);
|
||||
var result = task.Run();
|
||||
profiler.Stop(count++);
|
||||
|
||||
if (result < ReturnCode.Success)
|
||||
{
|
||||
profiler.Stop(pipeline.Count);
|
||||
profiler.Print();
|
||||
return result;
|
||||
}
|
||||
ContextInjector.Extract(context, task);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
BuildLogger.LogException(e);
|
||||
profiler.Stop(count);
|
||||
profiler.Print();
|
||||
return ReturnCode.Exception;
|
||||
}
|
||||
}
|
||||
|
||||
profiler.Stop(pipeline.Count);
|
||||
profiler.Print();
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Basic validate implementation that takes a set of tasks, a context, and does checks to ensure the task requirements are all satisfied.
|
||||
/// <seealso cref="IBuildTask"/>, <seealso cref="IBuildContext"/>, and <seealso cref="ReturnCode"/>
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The set of build tasks to run.</param>
|
||||
/// <param name="context">The build context to use for this run.</param>
|
||||
/// <returns>Return code with status information about success or failure causes.</returns>
|
||||
public static ReturnCode Validate(IList<IBuildTask> pipeline, IBuildContext context)
|
||||
{
|
||||
//// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
|
||||
//if (pipeline == null)
|
||||
//{
|
||||
// BuildLogger.LogException(new ArgumentNullException("pipeline"));
|
||||
// return ReturnCode.Exception;
|
||||
//}
|
||||
|
||||
//// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
|
||||
//if (context == null)
|
||||
//{
|
||||
// BuildLogger.LogException(new ArgumentNullException("context"));
|
||||
// return ReturnCode.Exception;
|
||||
//}
|
||||
|
||||
//var requiredTypes = new HashSet<Type>();
|
||||
//foreach (IBuildTask task in pipeline)
|
||||
// requiredTypes.UnionWith(task.RequiredContextTypes);
|
||||
|
||||
//var missingTypes = new List<string>();
|
||||
//foreach (Type requiredType in requiredTypes)
|
||||
//{
|
||||
// if (!context.ContainsContextObject(requiredType))
|
||||
// missingTypes.Add(requiredType.Name);
|
||||
//}
|
||||
|
||||
//if (missingTypes.Count > 0)
|
||||
//{
|
||||
// BuildLogger.LogError("Missing required object types to run build pipeline:\n{0}", string.Join(", ", missingTypes.ToArray()));
|
||||
// return ReturnCode.MissingRequiredObjects;
|
||||
//}
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cba3bf5fbe905c841b9ace7d603fb1d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic implementation of IWriteData. Stores the write information calculated during a build.
|
||||
/// <seealso cref="IWriteData"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class BuildWriteData : IWriteData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Dictionary<GUID, List<string>> AssetToFiles { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, List<ObjectIdentifier>> FileToObjects { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public List<IWriteOperation> WriteOperations { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, initializes properties to defaults
|
||||
/// </summary>
|
||||
public BuildWriteData()
|
||||
{
|
||||
AssetToFiles = new Dictionary<GUID, List<string>>();
|
||||
FileToObjects = new Dictionary<string, List<ObjectIdentifier>>();
|
||||
WriteOperations = new List<IWriteOperation>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Basic implementation of IBundleWriteData. Stores the asset bundle write information calculated during a build.
|
||||
/// <seealso cref="IBundleWriteData"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class BundleWriteData : IBundleWriteData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Dictionary<GUID, List<string>> AssetToFiles { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, List<ObjectIdentifier>> FileToObjects { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, string> FileToBundle { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, BuildUsageTagSet> FileToUsageSet { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, BuildReferenceMap> FileToReferenceMap { get; private set; }
|
||||
/// <inheritdoc />
|
||||
public List<IWriteOperation> WriteOperations { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, initializes properties to defaults
|
||||
/// </summary>
|
||||
public BundleWriteData()
|
||||
{
|
||||
AssetToFiles = new Dictionary<GUID, List<string>>();
|
||||
FileToObjects = new Dictionary<string, List<ObjectIdentifier>>();
|
||||
FileToBundle = new Dictionary<string, string>();
|
||||
FileToUsageSet = new Dictionary<string, BuildUsageTagSet>();
|
||||
FileToReferenceMap = new Dictionary<string, BuildReferenceMap>();
|
||||
WriteOperations = new List<IWriteOperation>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2b783d170d8ed6b468a9500bbe040087
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Optional context object used for overriding the location where specific objects will be serialized
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class BundleExplictObjectLayout : IBundleExplictObjectLayout
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Dictionary<ObjectIdentifier, string> ExplicitObjectLocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, initializes properties to defaults
|
||||
/// </summary>
|
||||
public BundleExplictObjectLayout()
|
||||
{
|
||||
ExplicitObjectLocation = new Dictionary<ObjectIdentifier, string>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d723a770823401649b007044d9a978ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,160 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Tasks;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic static class containing preset build pipeline task collections.
|
||||
/// </summary>
|
||||
public static class DefaultBuildTasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Options for different preset build pipelines
|
||||
/// </summary>
|
||||
public enum Preset
|
||||
{
|
||||
/// <summary>
|
||||
/// Use to indicate that the pipeline only executes player scripts.
|
||||
/// </summary>
|
||||
PlayerScriptsOnly,
|
||||
/// <summary>
|
||||
/// Use to indicate that the pipeline should create asset bundles.
|
||||
/// </summary>
|
||||
AssetBundleCompatible,
|
||||
/// <summary>
|
||||
/// Use to indicate that the pipeline should create asset bundles and the built-in shader bundle.
|
||||
/// </summary>
|
||||
AssetBundleBuiltInShaderExtraction,
|
||||
/// <summary>
|
||||
/// Use to indicate that the pipeline should create asset bundles, the built-in shader bundle, and MonoScript bundle.
|
||||
/// </summary>
|
||||
AssetBundleShaderAndScriptExtraction,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs and returns an IList containing the build tasks in the correct order for the preset build pipeline.
|
||||
/// </summary>
|
||||
/// <param name="preset">The preset build pipeline to construct and return.</param>
|
||||
/// <returns>IList containing the build tasks in the correct order for the preset build pipeline.</returns>
|
||||
public static IList<IBuildTask> Create(Preset preset)
|
||||
{
|
||||
switch (preset)
|
||||
{
|
||||
case Preset.PlayerScriptsOnly:
|
||||
return PlayerScriptsOnly();
|
||||
case Preset.AssetBundleCompatible:
|
||||
return AssetBundleCompatible(false, false);
|
||||
case Preset.AssetBundleBuiltInShaderExtraction:
|
||||
return AssetBundleCompatible(true, false);
|
||||
case Preset.AssetBundleShaderAndScriptExtraction:
|
||||
return AssetBundleCompatible(true, true);
|
||||
default:
|
||||
throw new NotImplementedException(string.Format("Preset for '{0}' not yet implemented.", preset));
|
||||
}
|
||||
}
|
||||
|
||||
static IList<IBuildTask> PlayerScriptsOnly()
|
||||
{
|
||||
var buildTasks = new List<IBuildTask>();
|
||||
|
||||
// Setup
|
||||
buildTasks.Add(new SwitchToBuildPlatform());
|
||||
|
||||
// Player Scripts
|
||||
buildTasks.Add(new BuildPlayerScripts());
|
||||
buildTasks.Add(new PostScriptsCallback());
|
||||
|
||||
// Dependency
|
||||
// - Empty
|
||||
|
||||
// Packing
|
||||
// - Empty
|
||||
|
||||
// Writing
|
||||
// - Empty
|
||||
|
||||
return buildTasks;
|
||||
}
|
||||
|
||||
static IList<IBuildTask> AssetBundleCompatible(bool shaderTask, bool monoscriptTask)
|
||||
{
|
||||
var buildTasks = new List<IBuildTask>();
|
||||
|
||||
// Setup
|
||||
buildTasks.Add(new SwitchToBuildPlatform());
|
||||
buildTasks.Add(new RebuildSpriteAtlasCache());
|
||||
|
||||
// Player Scripts
|
||||
buildTasks.Add(new BuildPlayerScripts());
|
||||
buildTasks.Add(new PostScriptsCallback());
|
||||
|
||||
// Dependency
|
||||
buildTasks.Add(new CalculateSceneDependencyData());
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
buildTasks.Add(new CalculateCustomDependencyData());
|
||||
#endif
|
||||
buildTasks.Add(new CalculateAssetDependencyData());
|
||||
buildTasks.Add(new StripUnusedSpriteSources());
|
||||
if (shaderTask)
|
||||
buildTasks.Add(new CreateBuiltInShadersBundle("UnityBuiltInShaders.bundle"));
|
||||
if (monoscriptTask)
|
||||
buildTasks.Add(new CreateMonoScriptBundle("UnityMonoScripts.bundle"));
|
||||
buildTasks.Add(new PostDependencyCallback());
|
||||
|
||||
// Packing
|
||||
buildTasks.Add(new GenerateBundlePacking());
|
||||
if (shaderTask || monoscriptTask)
|
||||
buildTasks.Add(new UpdateBundleObjectLayout());
|
||||
buildTasks.Add(new GenerateBundleCommands());
|
||||
buildTasks.Add(new GenerateSubAssetPathMaps());
|
||||
buildTasks.Add(new GenerateBundleMaps());
|
||||
buildTasks.Add(new PostPackingCallback());
|
||||
|
||||
// Writing
|
||||
buildTasks.Add(new WriteSerializedFiles());
|
||||
buildTasks.Add(new ArchiveAndCompressBundles());
|
||||
buildTasks.Add(new AppendBundleHash());
|
||||
buildTasks.Add(new GenerateLinkXml());
|
||||
buildTasks.Add(new PostWritingCallback());
|
||||
|
||||
return buildTasks;
|
||||
}
|
||||
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
public static IList<IBuildTask> ContentFileCompatible()
|
||||
{
|
||||
var buildTasks = new List<IBuildTask>();
|
||||
|
||||
// Setup
|
||||
buildTasks.Add(new SwitchToBuildPlatform());
|
||||
buildTasks.Add(new RebuildSpriteAtlasCache());
|
||||
|
||||
// Player Scripts
|
||||
buildTasks.Add(new BuildPlayerScripts());
|
||||
buildTasks.Add(new PostScriptsCallback());
|
||||
|
||||
// Dependency
|
||||
buildTasks.Add(new CalculateSceneDependencyData());
|
||||
buildTasks.Add(new CalculateCustomDependencyData());
|
||||
|
||||
buildTasks.Add(new CalculateAssetDependencyData());
|
||||
buildTasks.Add(new StripUnusedSpriteSources());
|
||||
buildTasks.Add(new PostDependencyCallback());
|
||||
|
||||
// Packing
|
||||
buildTasks.Add(new ClusterBuildLayout());
|
||||
buildTasks.Add(new PostPackingCallback());
|
||||
|
||||
// Writing
|
||||
buildTasks.Add(new WriteSerializedFiles());
|
||||
buildTasks.Add(new ArchiveAndCompressBundles());
|
||||
buildTasks.Add(new GenerateLinkXml());
|
||||
buildTasks.Add(new PostWritingCallback());
|
||||
|
||||
return buildTasks;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 552d6f72e940a1c4a809b635a8f40d8b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,39 @@
|
|||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates identifiers linearly for built content. Only deterministic if object order and initial Index is deterministic.
|
||||
/// </summary>
|
||||
public class LinearPackedIdentifiers : IDeterministicIdentifiers
|
||||
{
|
||||
/// <summary>
|
||||
/// The index at which to start linear id assignment.
|
||||
/// </summary>
|
||||
public long Index { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor, takes an initial index at which to start linear id assignment.
|
||||
/// </summary>
|
||||
/// <param name="index">Initial index at which to start linear id assignment.</param>
|
||||
public LinearPackedIdentifiers(long index)
|
||||
{
|
||||
Index = index;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual string GenerateInternalFileName(string name)
|
||||
{
|
||||
var hash = HashingMethods.Calculate(name).ToString();
|
||||
return string.Format("CAB-{0}", hash);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual long SerializationIndexFromObjectIdentifier(ObjectIdentifier objectID)
|
||||
{
|
||||
return Index++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f004933c56f4b2f4792fdcc1aca8f9b7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a deterministic identifier using a MD5 hash algorithm and does not require object ordering to be deterministic.
|
||||
/// This algorithm ensures objects coming from the same asset are packed closer together and can improve loading performance under certain situations.
|
||||
/// </summary>
|
||||
public class PrefabPackedIdentifiers : IDeterministicIdentifiers
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public virtual string GenerateInternalFileName(string name)
|
||||
{
|
||||
return "CAB-" + HashingMethods.Calculate(name);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual long SerializationIndexFromObjectIdentifier(ObjectIdentifier objectID)
|
||||
{
|
||||
byte[] assetHash;
|
||||
byte[] objectHash;
|
||||
bool extraArtifact = objectID.filePath.StartsWith("VirtualArtifacts/Extra/", StringComparison.Ordinal);
|
||||
int hashSeed = ScriptableBuildPipeline.fileIDHashSeed;
|
||||
if (extraArtifact && hashSeed != 0)
|
||||
{
|
||||
RawHash fileHash = HashingMethods.CalculateFile(objectID.filePath);
|
||||
assetHash = HashingMethods.Calculate(hashSeed, fileHash).ToBytes();
|
||||
objectHash = HashingMethods.Calculate(hashSeed, fileHash, objectID.localIdentifierInFile).ToBytes();
|
||||
}
|
||||
else if (extraArtifact)
|
||||
{
|
||||
RawHash fileHash = HashingMethods.CalculateFile(objectID.filePath);
|
||||
assetHash = fileHash.ToBytes();
|
||||
objectHash = HashingMethods.Calculate(fileHash, objectID.localIdentifierInFile).ToBytes();
|
||||
}
|
||||
else if (hashSeed != 0)
|
||||
{
|
||||
assetHash = HashingMethods.Calculate(hashSeed, objectID.guid, objectID.filePath).ToBytes();
|
||||
objectHash = HashingMethods.Calculate(hashSeed, objectID).ToBytes();
|
||||
}
|
||||
else
|
||||
{
|
||||
assetHash = HashingMethods.Calculate(objectID.guid, objectID.filePath).ToBytes();
|
||||
objectHash = HashingMethods.Calculate(objectID).ToBytes();
|
||||
}
|
||||
|
||||
int headerSize = ScriptableBuildPipeline.prefabPackedHeaderSize;
|
||||
if (headerSize < 4)
|
||||
{
|
||||
for (int i = 0; i < headerSize; i++)
|
||||
objectHash[i] = assetHash[i];
|
||||
return BitConverter.ToInt64(objectHash, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var assetVal = BitConverter.ToUInt64(assetHash, 0);
|
||||
var objectVal = BitConverter.ToUInt64(objectHash, 0);
|
||||
return (long)((0xFFFFFFFF00000000 & assetVal) | (0x00000000FFFFFFFF & (objectVal ^ assetVal)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5046b687c98667141a9a4f0add3345be
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a deterministic identifier using a MD4 hash algorithm and does not require object ordering to be deterministic.
|
||||
/// This algorithm generates identical results to what is used internally in <c>BuildPipeline.BuildAssetbundles</c>.
|
||||
/// </summary>
|
||||
public class Unity5PackedIdentifiers : IDeterministicIdentifiers
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public virtual string GenerateInternalFileName(string name)
|
||||
{
|
||||
return "CAB-" + HashingMethods.Calculate<MD4>(name);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual long SerializationIndexFromObjectIdentifier(ObjectIdentifier objectID)
|
||||
{
|
||||
RawHash hash;
|
||||
bool extraArtifact = objectID.filePath.StartsWith("VirtualArtifacts/Extra/", StringComparison.Ordinal);
|
||||
int hashSeed = ScriptableBuildPipeline.fileIDHashSeed;
|
||||
if (extraArtifact && hashSeed != 0)
|
||||
{
|
||||
RawHash fileHash = HashingMethods.CalculateFile(objectID.filePath);
|
||||
hash = HashingMethods.Calculate(hashSeed, fileHash, objectID.localIdentifierInFile);
|
||||
}
|
||||
else if (extraArtifact)
|
||||
{
|
||||
RawHash fileHash = HashingMethods.CalculateFile(objectID.filePath);
|
||||
hash = HashingMethods.Calculate(fileHash, objectID.localIdentifierInFile);
|
||||
}
|
||||
else if (hashSeed != 0)
|
||||
{
|
||||
if (objectID.fileType == FileType.MetaAssetType || objectID.fileType == FileType.SerializedAssetType)
|
||||
hash = HashingMethods.Calculate<MD4>(hashSeed, objectID.guid.ToString(), objectID.fileType, objectID.localIdentifierInFile);
|
||||
else
|
||||
hash = HashingMethods.Calculate<MD4>(hashSeed, objectID.filePath, objectID.localIdentifierInFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (objectID.fileType == FileType.MetaAssetType || objectID.fileType == FileType.SerializedAssetType)
|
||||
hash = HashingMethods.Calculate<MD4>(objectID.guid.ToString(), objectID.fileType, objectID.localIdentifierInFile);
|
||||
else
|
||||
hash = HashingMethods.Calculate<MD4>(objectID.filePath, objectID.localIdentifierInFile);
|
||||
}
|
||||
|
||||
return BitConverter.ToInt64(hash.ToBytes(), 0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b8ee6f8e7df445bfb88fb0372dcf691a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d3f1cef9a16d4a21826a13742ee5ea01
|
||||
timeCreated: 1513096288
|
|
@ -0,0 +1,46 @@
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Append a hash to each bundle name.
|
||||
/// </summary>
|
||||
public class AppendBundleHash : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBundleBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext]
|
||||
IBundleBuildResults m_Results;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
if (!m_Parameters.AppendHash)
|
||||
return ReturnCode.SuccessNotRun;
|
||||
|
||||
string[] bundles = m_Results.BundleInfos.Keys.ToArray();
|
||||
foreach (string bundle in bundles)
|
||||
{
|
||||
var details = m_Results.BundleInfos[bundle];
|
||||
var oldFileName = details.FileName;
|
||||
var newFileName = string.Format("{0}_{1}", details.FileName, details.Hash.ToString());
|
||||
details.FileName = newFileName;
|
||||
m_Results.BundleInfos[bundle] = details;
|
||||
|
||||
File.Delete(newFileName);
|
||||
File.Move(oldFileName, newFileName);
|
||||
}
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f4af5ab96cd890342912b92e54ac2c3e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,442 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor.Build.Content;
|
||||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Build.Pipeline;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
using BuildCompression = UnityEngine.BuildCompression;
|
||||
#else
|
||||
using BuildCompression = UnityEditor.Build.Content.BuildCompression;
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Archives and compresses all asset bundles.
|
||||
/// </summary>
|
||||
public class ArchiveAndCompressBundles : IBuildTask
|
||||
{
|
||||
private const int kVersion = 2;
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return kVersion; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBundleWriteData m_WriteData;
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
[InjectContext(ContextUsage.In)]
|
||||
IBundleBuildContent m_Content;
|
||||
#endif
|
||||
|
||||
[InjectContext]
|
||||
IBundleBuildResults m_Results;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IProgressTracker m_Tracker;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildCache m_Cache;
|
||||
|
||||
[InjectContext(ContextUsage.In, true)]
|
||||
IBuildLogger m_Log;
|
||||
#pragma warning restore 649
|
||||
|
||||
internal static void CopyFileWithTimestampIfDifferent(string srcPath, string destPath, IBuildLogger log)
|
||||
{
|
||||
if (srcPath == destPath)
|
||||
return;
|
||||
|
||||
srcPath = Path.GetFullPath(srcPath);
|
||||
destPath = Path.GetFullPath(destPath);
|
||||
|
||||
#if UNITY_EDITOR_WIN
|
||||
// Max path length per MS Path code.
|
||||
const int MaxPath = 260;
|
||||
|
||||
if (srcPath.Length > MaxPath)
|
||||
throw new PathTooLongException(srcPath);
|
||||
|
||||
if (destPath.Length > MaxPath)
|
||||
throw new PathTooLongException(destPath);
|
||||
#endif
|
||||
|
||||
DateTime time = File.GetLastWriteTime(srcPath);
|
||||
DateTime destTime = File.Exists(destPath) ? File.GetLastWriteTime(destPath) : new DateTime();
|
||||
|
||||
if (destTime == time)
|
||||
return;
|
||||
|
||||
using (log.ScopedStep(LogLevel.Verbose, "Copying From Cache", $"{srcPath} -> {destPath}"))
|
||||
{
|
||||
var directory = Path.GetDirectoryName(destPath);
|
||||
Directory.CreateDirectory(directory);
|
||||
File.Copy(srcPath, destPath, true);
|
||||
}
|
||||
}
|
||||
|
||||
static CacheEntry GetCacheEntry(IBuildCache cache, string bundleName, IEnumerable<ResourceFile> resources, BuildCompression compression, List<SerializedFileMetaData> hashes)
|
||||
{
|
||||
var entry = new CacheEntry();
|
||||
entry.Type = CacheEntry.EntryType.Data;
|
||||
entry.Guid = HashingMethods.Calculate("ArchiveAndCompressBundles", bundleName).ToGUID();
|
||||
List<object> toHash = new List<object> { kVersion, compression };
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
toHash.Add(resource.serializedFile);
|
||||
toHash.Add(resource.fileAlias);
|
||||
}
|
||||
toHash.AddRange(hashes.Select(x => (object)x.RawFileHash));
|
||||
entry.Hash = HashingMethods.Calculate(toHash).ToHash128();
|
||||
entry.Version = kVersion;
|
||||
return entry;
|
||||
}
|
||||
|
||||
static CachedInfo GetCachedInfo(IBuildCache cache, CacheEntry entry, IEnumerable<ResourceFile> resources, BundleDetails details)
|
||||
{
|
||||
var info = new CachedInfo();
|
||||
info.Asset = entry;
|
||||
info.Dependencies = new CacheEntry[0];
|
||||
info.Data = new object[] { details };
|
||||
return info;
|
||||
}
|
||||
|
||||
internal static Hash128 CalculateHashVersion(ArchiveWorkItem item, string[] dependencies)
|
||||
{
|
||||
List<Hash128> hashes = new List<Hash128>();
|
||||
|
||||
hashes.AddRange(item.SeriliazedFileMetaDatas.Select(x => x.ContentHash));
|
||||
|
||||
return HashingMethods.Calculate(hashes, dependencies).ToHash128();
|
||||
}
|
||||
|
||||
internal class ArchiveWorkItem
|
||||
{
|
||||
public int Index;
|
||||
public string BundleName;
|
||||
public string OutputFilePath;
|
||||
public string CachedArtifactPath;
|
||||
public List<ResourceFile> ResourceFiles;
|
||||
public BuildCompression Compression;
|
||||
public BundleDetails ResultDetails;
|
||||
public List<SerializedFileMetaData> SeriliazedFileMetaDatas = new List<SerializedFileMetaData>();
|
||||
}
|
||||
|
||||
internal struct TaskInput
|
||||
{
|
||||
public Dictionary<string, WriteResult> InternalFilenameToWriteResults;
|
||||
public Dictionary<string, SerializedFileMetaData> InternalFilenameToWriteMetaData;
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
public Dictionary<string, List<ResourceFile>> BundleNameToAdditionalFiles;
|
||||
#endif
|
||||
public Dictionary<string, string> InternalFilenameToBundleName;
|
||||
public Func<string, BuildCompression> GetCompressionForIdentifier;
|
||||
public Func<string, string> GetOutputFilePathForIdentifier;
|
||||
public IBuildCache BuildCache;
|
||||
public Dictionary<GUID, List<string>> AssetToFilesDependencies;
|
||||
public IProgressTracker ProgressTracker;
|
||||
public string TempOutputFolder;
|
||||
public bool Threaded;
|
||||
public List<string> OutCachedBundles;
|
||||
public IBuildLogger Log;
|
||||
public bool StripUnityVersion;
|
||||
}
|
||||
|
||||
internal struct TaskOutput
|
||||
{
|
||||
public Dictionary<string, BundleDetails> BundleDetails;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
TaskInput input = new TaskInput();
|
||||
input.InternalFilenameToWriteResults = m_Results.WriteResults;
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
input.BundleNameToAdditionalFiles = m_Content.AdditionalFiles;
|
||||
#endif
|
||||
input.InternalFilenameToBundleName = m_WriteData.FileToBundle;
|
||||
input.GetCompressionForIdentifier = (x) => m_Parameters.GetCompressionForIdentifier(x);
|
||||
input.GetOutputFilePathForIdentifier = (x) => m_Parameters.GetOutputFilePathForIdentifier(x);
|
||||
input.BuildCache = m_Parameters.UseCache ? m_Cache : null;
|
||||
input.ProgressTracker = m_Tracker;
|
||||
input.TempOutputFolder = m_Parameters.TempOutputFolder;
|
||||
input.AssetToFilesDependencies = m_WriteData.AssetToFiles;
|
||||
input.InternalFilenameToWriteMetaData = m_Results.WriteResultsMetaData;
|
||||
input.Log = m_Log;
|
||||
input.StripUnityVersion = (m_Parameters.GetContentBuildSettings().buildFlags & ContentBuildFlags.StripUnityVersion) != 0;
|
||||
|
||||
input.Threaded = ReflectionExtensions.SupportsMultiThreadedArchiving && ScriptableBuildPipeline.threadedArchiving;
|
||||
|
||||
TaskOutput output;
|
||||
ReturnCode code = Run(input, out output);
|
||||
|
||||
if (code == ReturnCode.Success)
|
||||
{
|
||||
foreach (var item in output.BundleDetails)
|
||||
m_Results.BundleInfos.Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
internal static Dictionary<string, string[]> CalculateBundleDependencies(List<List<string>> assetFileList, Dictionary<string, string> filenameToBundleName)
|
||||
{
|
||||
var bundleDependencies = new Dictionary<string, string[]>();
|
||||
Dictionary<string, HashSet<string>> bundleDependenciesHash = new Dictionary<string, HashSet<string>>();
|
||||
foreach (var files in assetFileList)
|
||||
{
|
||||
if (files.IsNullOrEmpty())
|
||||
continue;
|
||||
|
||||
string bundle = filenameToBundleName[files.First()];
|
||||
HashSet<string> dependencies;
|
||||
bundleDependenciesHash.GetOrAdd(bundle, out dependencies);
|
||||
dependencies.UnionWith(files.Select(x => filenameToBundleName[x]));
|
||||
dependencies.Remove(bundle);
|
||||
|
||||
// Ensure we create mappings for all encountered files
|
||||
foreach (var file in files)
|
||||
bundleDependenciesHash.GetOrAdd(filenameToBundleName[file], out dependencies);
|
||||
}
|
||||
|
||||
// Recursively combine dependencies
|
||||
foreach (var dependencyPair in bundleDependenciesHash)
|
||||
{
|
||||
List<string> dependencies = dependencyPair.Value.ToList();
|
||||
for (int i = 0; i < dependencies.Count; i++)
|
||||
{
|
||||
if (!bundleDependenciesHash.TryGetValue(dependencies[i], out var recursiveDependencies))
|
||||
continue;
|
||||
foreach (var recursiveDependency in recursiveDependencies)
|
||||
{
|
||||
if (dependencyPair.Value.Add(recursiveDependency))
|
||||
dependencies.Add(recursiveDependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var dep in bundleDependenciesHash)
|
||||
{
|
||||
string[] ret = dep.Value.ToArray();
|
||||
Array.Sort(ret);
|
||||
bundleDependencies.Add(dep.Key, ret);
|
||||
}
|
||||
return bundleDependencies;
|
||||
}
|
||||
|
||||
static void PostArchiveProcessing(List<ArchiveWorkItem> items, List<List<string>> assetFileList, Dictionary<string, string> filenameToBundleName, IBuildLogger log)
|
||||
{
|
||||
using (log.ScopedStep(LogLevel.Info, "PostArchiveProcessing"))
|
||||
{
|
||||
Dictionary<string, string[]> bundleDependencies = CalculateBundleDependencies(assetFileList, filenameToBundleName);
|
||||
foreach (ArchiveWorkItem item in items)
|
||||
{
|
||||
// apply bundle dependencies
|
||||
item.ResultDetails.Dependencies = bundleDependencies.ContainsKey(item.BundleName) ? bundleDependencies[item.BundleName] : new string[0];
|
||||
item.ResultDetails.Hash = CalculateHashVersion(item, item.ResultDetails.Dependencies);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ArchiveWorkItem GetOrCreateWorkItem(TaskInput input, string bundleName, Dictionary<string, ArchiveWorkItem> bundleToWorkItem)
|
||||
{
|
||||
if (!bundleToWorkItem.TryGetValue(bundleName, out ArchiveWorkItem item))
|
||||
{
|
||||
item = new ArchiveWorkItem();
|
||||
item.BundleName = bundleName;
|
||||
item.Compression = input.GetCompressionForIdentifier(bundleName);
|
||||
item.OutputFilePath = input.GetOutputFilePathForIdentifier(bundleName);
|
||||
item.ResourceFiles = new List<ResourceFile>();
|
||||
bundleToWorkItem[bundleName] = item;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
static RawHash HashResourceFiles(List<ResourceFile> files)
|
||||
{
|
||||
return HashingMethods.Calculate(files.Select((x) => HashingMethods.CalculateFile(x.fileName)));
|
||||
}
|
||||
|
||||
static List<ArchiveWorkItem> CreateWorkItems(TaskInput input)
|
||||
{
|
||||
using (input.Log.ScopedStep(LogLevel.Info, "CreateWorkItems"))
|
||||
{
|
||||
Dictionary<string, ArchiveWorkItem> bundleNameToWorkItem = new Dictionary<string, ArchiveWorkItem>();
|
||||
|
||||
foreach (var pair in input.InternalFilenameToWriteResults)
|
||||
{
|
||||
string internalName = pair.Key;
|
||||
string bundleName = input.InternalFilenameToBundleName[internalName];
|
||||
ArchiveWorkItem item = GetOrCreateWorkItem(input, bundleName, bundleNameToWorkItem);
|
||||
|
||||
if (input.InternalFilenameToWriteMetaData.TryGetValue(pair.Key, out SerializedFileMetaData md))
|
||||
item.SeriliazedFileMetaDatas.Add(md);
|
||||
else
|
||||
throw new Exception($"Archive {bundleName} with internal name {internalName} does not have associated SerializedFileMetaData");
|
||||
|
||||
item.ResourceFiles.AddRange(pair.Value.resourceFiles);
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
if (input.BundleNameToAdditionalFiles.TryGetValue(bundleName, out List<ResourceFile> additionalFiles))
|
||||
{
|
||||
RawHash hash = HashResourceFiles(additionalFiles);
|
||||
item.SeriliazedFileMetaDatas.Add(new SerializedFileMetaData() { ContentHash = hash.ToHash128(), RawFileHash = hash.ToHash128() });
|
||||
item.ResourceFiles.AddRange(additionalFiles);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
List<ArchiveWorkItem> allItems = bundleNameToWorkItem.Select((x, index) => { x.Value.Index = index; return x.Value; }).ToList();
|
||||
return allItems;
|
||||
}
|
||||
}
|
||||
|
||||
static internal ReturnCode Run(TaskInput input, out TaskOutput output)
|
||||
{
|
||||
output = new TaskOutput();
|
||||
output.BundleDetails = new Dictionary<string, BundleDetails>();
|
||||
|
||||
List<ArchiveWorkItem> allItems = CreateWorkItems(input);
|
||||
|
||||
IList<CacheEntry> cacheEntries = null;
|
||||
IList<CachedInfo> cachedInfo = null;
|
||||
List<ArchiveWorkItem> cachedItems = new List<ArchiveWorkItem>();
|
||||
List<ArchiveWorkItem> nonCachedItems = allItems;
|
||||
if (input.BuildCache != null)
|
||||
{
|
||||
using (input.Log.ScopedStep(LogLevel.Info, "Creating Cache Entries"))
|
||||
cacheEntries = allItems.Select(x => GetCacheEntry(input.BuildCache, x.BundleName, x.ResourceFiles, x.Compression, x.SeriliazedFileMetaDatas)).ToList();
|
||||
|
||||
using (input.Log.ScopedStep(LogLevel.Info, "Load Cached Data"))
|
||||
input.BuildCache.LoadCachedData(cacheEntries, out cachedInfo);
|
||||
|
||||
cachedItems = allItems.Where(x => cachedInfo[x.Index] != null).ToList();
|
||||
nonCachedItems = allItems.Where(x => cachedInfo[x.Index] == null).ToList();
|
||||
foreach (ArchiveWorkItem i in allItems)
|
||||
i.CachedArtifactPath = string.Format("{0}/{1}", input.BuildCache.GetCachedArtifactsDirectory(cacheEntries[i.Index]), HashingMethods.Calculate(i.BundleName));
|
||||
}
|
||||
|
||||
using (input.Log.ScopedStep(LogLevel.Info, "CopyingCachedFiles"))
|
||||
{
|
||||
foreach (ArchiveWorkItem item in cachedItems)
|
||||
{
|
||||
if (!input.ProgressTracker.UpdateInfoUnchecked(string.Format("{0} (Cached)", item.BundleName)))
|
||||
return ReturnCode.Canceled;
|
||||
|
||||
item.ResultDetails = (BundleDetails)cachedInfo[item.Index].Data[0];
|
||||
item.ResultDetails.FileName = item.OutputFilePath;
|
||||
CopyFileWithTimestampIfDifferent(item.CachedArtifactPath, item.ResultDetails.FileName, input.Log);
|
||||
}
|
||||
}
|
||||
|
||||
// Write all the files that aren't cached
|
||||
if (!ArchiveItems(nonCachedItems, input.TempOutputFolder, input.ProgressTracker, input.Threaded, input.Log, input.StripUnityVersion))
|
||||
return ReturnCode.Canceled;
|
||||
|
||||
PostArchiveProcessing(allItems, input.AssetToFilesDependencies.Values.ToList(), input.InternalFilenameToBundleName, input.Log);
|
||||
|
||||
// Put everything into the cache
|
||||
if (input.BuildCache != null)
|
||||
{
|
||||
using (input.Log.ScopedStep(LogLevel.Info, "Copying To Cache"))
|
||||
{
|
||||
List<CachedInfo> uncachedInfo = nonCachedItems.Select(x => GetCachedInfo(input.BuildCache, cacheEntries[x.Index], x.ResourceFiles, x.ResultDetails)).ToList();
|
||||
input.BuildCache.SaveCachedData(uncachedInfo);
|
||||
}
|
||||
}
|
||||
|
||||
output.BundleDetails = allItems.ToDictionary((x) => x.BundleName, (x) => x.ResultDetails);
|
||||
|
||||
if (input.OutCachedBundles != null)
|
||||
input.OutCachedBundles.AddRange(cachedItems.Select(x => x.BundleName));
|
||||
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
|
||||
static private void ArchiveSingleItem(ArchiveWorkItem item, string tempOutputFolder, IBuildLogger log, bool stripUnityVersion)
|
||||
{
|
||||
using (log.ScopedStep(LogLevel.Info, "ArchiveSingleItem", item.BundleName))
|
||||
{
|
||||
item.ResultDetails = new BundleDetails();
|
||||
string writePath = string.Format("{0}/{1}", tempOutputFolder, item.BundleName);
|
||||
if (!string.IsNullOrEmpty(item.CachedArtifactPath))
|
||||
writePath = item.CachedArtifactPath;
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(writePath));
|
||||
item.ResultDetails.FileName = item.OutputFilePath;
|
||||
item.ResultDetails.Crc = ContentBuildInterface.ArchiveAndCompress(item.ResourceFiles.ToArray(), writePath, item.Compression, stripUnityVersion);
|
||||
|
||||
CopyFileWithTimestampIfDifferent(writePath, item.ResultDetails.FileName, log);
|
||||
}
|
||||
}
|
||||
|
||||
static private bool ArchiveItems(List<ArchiveWorkItem> items, string tempOutputFolder, IProgressTracker tracker, bool threaded, IBuildLogger log, bool stripUnityVersion)
|
||||
{
|
||||
using (log.ScopedStep(LogLevel.Info, "ArchiveItems", threaded))
|
||||
{
|
||||
log?.AddEntry(LogLevel.Info, $"Archiving {items.Count} Bundles");
|
||||
if (threaded)
|
||||
return ArchiveItemsThreaded(items, tempOutputFolder, tracker, log, stripUnityVersion);
|
||||
|
||||
foreach (ArchiveWorkItem item in items)
|
||||
{
|
||||
if (tracker != null && !tracker.UpdateInfoUnchecked(item.BundleName))
|
||||
return false;
|
||||
|
||||
ArchiveSingleItem(item, tempOutputFolder, log, stripUnityVersion);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static private bool ArchiveItemsThreaded(List<ArchiveWorkItem> items, string tempOutputFolder, IProgressTracker tracker, IBuildLogger log, bool stripUnityVersion)
|
||||
{
|
||||
CancellationTokenSource srcToken = new CancellationTokenSource();
|
||||
|
||||
SemaphoreSlim semaphore = new SemaphoreSlim(0);
|
||||
List<Task> tasks = new List<Task>(items.Count);
|
||||
foreach (ArchiveWorkItem item in items)
|
||||
{
|
||||
tasks.Add(Task.Run(() =>
|
||||
{
|
||||
try { ArchiveSingleItem(item, tempOutputFolder, log, stripUnityVersion); }
|
||||
finally { semaphore.Release(); }
|
||||
}, srcToken.Token));
|
||||
}
|
||||
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
semaphore.Wait(srcToken.Token);
|
||||
if (tracker != null && !tracker.UpdateInfoUnchecked($"Archive {i + 1}/{items.Count}"))
|
||||
{
|
||||
srcToken.Cancel();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Task.WaitAny(Task.WhenAll(tasks));
|
||||
int count = 0;
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
if (task.Exception == null)
|
||||
continue;
|
||||
Debug.LogException(task.Exception);
|
||||
count++;
|
||||
}
|
||||
if (count > 0)
|
||||
throw new BuildFailedException($"ArchiveAndCompressBundles encountered {count} exception(s). See console for logged exceptions.");
|
||||
|
||||
return !srcToken.Token.IsCancellationRequested;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b7bdc0bcfab4e714b88a12d6b22bac9b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,50 @@
|
|||
using UnityEditor.Build.Pipeline.Injector;
|
||||
using UnityEditor.Build.Pipeline.Utilities;
|
||||
using UnityEditor.Build.Pipeline.Interfaces;
|
||||
using UnityEditor.Build.Player;
|
||||
using System.IO;
|
||||
|
||||
namespace UnityEditor.Build.Pipeline.Tasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Compiles all player scripts.
|
||||
/// </summary>
|
||||
public class BuildPlayerScripts : IBuildTask
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Version { get { return 1; } }
|
||||
|
||||
#pragma warning disable 649
|
||||
[InjectContext]
|
||||
IBuildParameters m_Parameters;
|
||||
|
||||
[InjectContext]
|
||||
IBuildResults m_Results;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReturnCode Run()
|
||||
{
|
||||
if (m_Parameters.ScriptInfo != null)
|
||||
{
|
||||
BuildCacheUtility.SetTypeDB(m_Parameters.ScriptInfo);
|
||||
return ReturnCode.SuccessNotRun;
|
||||
}
|
||||
|
||||
// We need to ensure the directory is empty so prior results or other artifacts in this directory do not influence the build result
|
||||
if (Directory.Exists(m_Parameters.ScriptOutputFolder))
|
||||
{
|
||||
Directory.Delete(m_Parameters.ScriptOutputFolder, true);
|
||||
Directory.CreateDirectory(m_Parameters.ScriptOutputFolder);
|
||||
}
|
||||
|
||||
m_Results.ScriptResults = PlayerBuildInterface.CompilePlayerScripts(m_Parameters.GetScriptCompilationSettings(), m_Parameters.ScriptOutputFolder);
|
||||
m_Parameters.ScriptInfo = m_Results.ScriptResults.typeDB;
|
||||
BuildCacheUtility.SetTypeDB(m_Parameters.ScriptInfo);
|
||||
|
||||
if (m_Results.ScriptResults.assemblies.IsNullOrEmpty() && m_Results.ScriptResults.typeDB == null)
|
||||
return ReturnCode.Error;
|
||||
return ReturnCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2c42a8e1e1d1b874e95761dab5bdfbc8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue