Get started with Asset Discovery
Asset Discovery is a Unity Cloud service that allows you to discover and manage your project's published assets. You can use Asset Discovery to:
- Get a published asset
- Search for published assets based on a set of criteria
- Aggregate published assets based on a set of criteria
This section explains how to set up a basic scene and script to initialize and use the Unity Asset Manager SDK package with Asset Discovery. It performs a basic search for published assets of the selected project and displays the results in a simple GUI.
Requirements
To use Asset Discovery, you must have a minimum role of:
- Manager in the Unity Cloud Organization you belong to.
OR - Asset Manager Viewer in the Unity Cloud Project you belong to.
Configure the package
To configure the Unity Asset Manager SDK package, you must do the following:
- Set up a Unity scene
- Create an
AssetDiscovery
- Create the
PlatformServices
Set up a Unity scene
To set up a Unity scene, perform the following steps:
- In your Unity project window, navigate to Assets > Scenes.
- Right-click the
Assets/Scenes
folder and navigate to Create > Scene. - Name the new scene
AssetDiscoveryExample
.
Create an AssetDiscovery
To create a MonoBehaviour
, perform the following steps:
- In your Unity project window, go to Assets > Scripts. Create an
Assets/Scripts
folder if the folder doesn't already exist. - Right-click the
Assets/Scripts
folder and go to Create > C# Script. Name your scriptAssetDiscoveryUI
. - In the
AssetDiscoveryExample
scene you created earlier, right-click the hierarchy and select Create Empty. - Name your new object
AssetDiscovery
. - Select the
AssetDiscovery
object and add theAssetDiscoveryUI
script you created earlier.
Create the PlatformServices
To instantiate the necessary providers and managers, follow these steps:
- Implement the platform services pattern. See the Best practices: dependency injection page of the Identity package documentation for more information.
- Update the
PlatformServices
class in yourPlatformServices.cs
file to look like the following:
using System;
using System.Threading.Tasks;
using Unity.Cloud.Assets;
using Unity.Cloud.Common;
using Unity.Cloud.Common.Runtime;
using Unity.Cloud.Identity;
using Unity.Cloud.Identity.Runtime;
public static class PlatformServices
{
/// <summary>
/// Returns a <see cref="ICompositeAuthenticator"/>.
/// </summary>
public static ICompositeAuthenticator Authenticator { get; private set; }
/// <summary>
/// Returns a <see cref="IAuthenticationStateProvider"/>.
/// </summary>
public static IAuthenticationStateProvider AuthenticationStateProvider => Authenticator;
/// <summary>
/// Returns an <see cref="IOrganizationProvider"/>.
/// </summary>
public static IOrganizationProvider OrganizationProvider { get; private set; }
/// <summary>
/// Returns an <see cref="IProjectProvider"/>.
/// </summary>
public static IProjectProvider ProjectProvider { get; private set; }
/// <summary>
/// Returns an <see cref="IAssetProvider"/>
/// </summary>
public static IAssetProvider AssetProvider { get; private set; }
public static void Create()
{
var httpClient = new UnityHttpClient();
var serviceHostResolver = UnityRuntimeServiceHostResolverFactory.Create();
var playerSettings = UnityCloudPlayerSettings.Instance;
var platformSupport = PlatformSupportFactory.GetAuthenticationPlatformSupport();
var compositeAuthenticatorSettings = new CompositeAuthenticatorSettingsBuilder(httpClient, platformSupport, serviceHostResolver)
.AddDefaultPkceAuthenticator(playerSettings)
.Build();
Authenticator = new CompositeAuthenticator(compositeAuthenticatorSettings);
var serviceHttpClient = new ServiceHttpClient(httpClient, Authenticator, playerSettings);
OrganizationProvider = new CloudOrganizationProvider(serviceHttpClient, serviceHostResolver);
ProjectProvider = new CloudProjectProvider(serviceHttpClient, serviceHostResolver);
var assetServiceConfiguration = new AssetServiceConfiguration(true);
AssetProvider = new CloudAssetProvider(serviceHttpClient, serviceHostResolver, assetServiceConfiguration);
}
/// <summary>
/// A Task that initializes all platform services.
/// </summary>
/// <returns>A Task.</returns>
public static async Task InitializeAsync()
{
await Authenticator.InitializeAsync();
}
/// <summary>
/// Shuts down all platform services.
/// </summary>
public static void ShutDownServices()
{
(Authenticator as IDisposable)?.Dispose();
Authenticator = null;
}
}
What this script accomplishes:
- Initializes an
IAuthenticator
for logging in and verifying your identity when accessing the HTTP services. - Initializes an
IOrganizationProvider
to fetch the organizations you belong to. - Initializes an
IProjectProvider
to fetch the projects you have access to. - Initializes an
IAssetProvider
to fetch your assets.
To initialize the PlatformServices
in your scene, follow these steps:
- In your Unity project window, go to Assets > Scripts.
- Right-click the
Assets/Scripts
folder and go to Create > C# Script. Name your scriptPlatformServicesInitialization
. - In the
AssetDiscoveryExample
scene you created earlier, right-click the hierarchy and select Create Empty. - Name your new object
PlatformServices
. - Select the
PlatformServices
object and add thePlatformServicesInitialization
script you created earlier. - Update the
PlatformServicesInitialization
class in yourPlatformServicesInitialization.cs
file to look like the following:
using System.Threading.Tasks;
using UnityEngine;
/// <summary>
/// A Mono behaviour class to initialize services and dependencies for the Unity Cloud platform.
/// </summary>
[DefaultExecutionOrder(int.MinValue)]
[AddComponentMenu("Assets/Manual/Discovery/Platform Services Initialization")]
public class PlatformServicesInitialization : MonoBehaviour
{
void Awake()
{
DontDestroyOnLoad(gameObject);
PlatformServices.Create();
}
async Task Start()
{
await PlatformServices.InitializeAsync();
}
}
What this script accomplishes:
- Triggers the creation of the services available in the
PlatformServices
. - Initializes the
IAuthenticator
.
To clean up the PlatformServices
in your scene, follow these steps:
- In your Unity project window, go to Assets > Scripts.
- Right-click the
Assets/Scripts
folder and go to Create > C# Script. Name your scriptPlatformServicesShutdown
. - Select the
PlatformServices
object you created earlier and add thePlatformServicesShutdown
script you created earlier. - Update the
PlatformServicesShutdown
class in yourPlatformServicesShutdown.cs
file to look like the following:
using UnityEngine;
/// <summary>
/// A Mono behaviour class to shut down services and dependencies from the Unity Cloud platform.
/// </summary>
[DefaultExecutionOrder(int.MaxValue)]
[AddComponentMenu("Assets/Manual/Discovery/Platform Services Shutdown")]
public class PlatformServicesShutdown : MonoBehaviour
{
void OnDestroy()
{
PlatformServices.ShutDownServices();
}
}
This script cleans up of the services when the scene is closed.
Create the behaviour for getting assets
To create the behaviour for asset discovery, perform the following steps:
- In your Unity project window, go to Assets > Scripts.
- Right-click the
Assets/Scripts
folder and go to Create > C# Script. Name your scriptAssetDiscoveryBehaviour
. - Open the
AssetDiscoveryBehaviour
script you created and replace the contents of the file with the following code sample:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Unity.Cloud.Assets;
using UnityEngine;
public class AssetDiscoveryBehaviour
{
static readonly Pagination m_DefaultPagination = new(nameof(IAsset.Name), Range.All);
IOrganization[] m_AvailableOrganizations;
IOrganization m_CurrentOrganization;
CancellationTokenSource m_ProjectCancellationTokenSrc = new();
CancellationTokenSource m_AssetCancellationTokenSrc = new();
public IOrganization[] AvailableOrganizations => m_AvailableOrganizations;
public IOrganization CurrentOrganization => m_CurrentOrganization;
public bool IsOrganizationSelected => m_CurrentOrganization != null;
public List<IProject> AvailableProjects { get; } = new();
public IProject CurrentProject { get; private set; }
public bool IsProjectSelected => CurrentProject != null;
public List<IAsset> AvailableAssets { get; } = new();
public IAsset CurrentAsset { get; set; }
public void Clear()
{
m_ProjectCancellationTokenSrc.Cancel();
m_ProjectCancellationTokenSrc.Dispose();
m_AssetCancellationTokenSrc.Cancel();
m_AssetCancellationTokenSrc.Dispose();
CurrentAsset = null;
CurrentProject = null;
m_CurrentOrganization = null;
}
public void SetSelectedOrganization(IOrganization organization)
{
m_CurrentOrganization = organization;
if (m_CurrentOrganization != null)
{
GetProjects();
}
}
public void SetSelectedProject(IProject project)
{
CurrentProject = project;
if (CurrentProject != null)
{
GetAssets();
}
}
public async Task GetOrganizationsAsync()
{
m_AvailableOrganizations = null;
try
{
var cancellationTokenSrc = new CancellationTokenSource();
m_AvailableOrganizations = await PlatformServices.OrganizationProvider.GetOrganizationsAsync(cancellationTokenSrc.Token);
}
catch (OperationCanceledException oe)
{
Debug.LogError(oe);
}
catch (AggregateException e)
{
Debug.LogError(e.InnerException);
}
catch (Exception e)
{
Debug.LogError(e);
}
}
public void GetProjects()
{
m_ProjectCancellationTokenSrc.Cancel();
m_ProjectCancellationTokenSrc.Dispose();
m_ProjectCancellationTokenSrc = new CancellationTokenSource();
try
{
var projects = PlatformServices.ProjectProvider.ListProjectsAsync(m_CurrentOrganization, m_DefaultPagination, m_ProjectCancellationTokenSrc.Token);
_ = PopulateProjectsAsync(projects);
}
catch (OperationCanceledException oe)
{
Debug.LogError(oe);
}
catch (AggregateException e)
{
Debug.LogError(e.InnerException);
}
catch (Exception e)
{
Debug.LogError(e);
}
}
async Task PopulateProjectsAsync(IAsyncEnumerable<IProject> projects)
{
AvailableProjects.Clear();
CurrentProject = null;
await foreach (var project in projects.WithCancellation(m_ProjectCancellationTokenSrc.Token))
{
AvailableProjects.Add(project);
}
}
void GetAssets()
{
m_AssetCancellationTokenSrc.Cancel();
m_AssetCancellationTokenSrc.Dispose();
m_AssetCancellationTokenSrc = new CancellationTokenSource();
try
{
var assets = PlatformServices.AssetProvider.SearchAsync(new AssetSearchFilter(CurrentProject), m_DefaultPagination, m_AssetCancellationTokenSrc.Token);
_ = PopulateAssetsAsync(assets);
}
catch (OperationCanceledException oe)
{
Debug.LogError(oe);
}
catch (AggregateException e)
{
Debug.LogError(e.InnerException);
}
catch (Exception e)
{
Debug.LogError(e);
}
}
async Task PopulateAssetsAsync(IAsyncEnumerable<IAsset> assets)
{
AvailableAssets.Clear();
CurrentAsset = null;
await foreach (var asset in assets.WithCancellation(m_AssetCancellationTokenSrc.Token))
{
AvailableAssets.Add(asset);
}
}
}
The script does the following:
- Provides the functions to list and select organizations.
- Provides the functions to list and select projects.
- Performs a basic search to list the published assets of the selected project.
Create the UI for navigating assets
To create a simple UI for navigating assets, do the following:
Open the AssetDiscoveryUI
script you created earlier and replace the contents of the file with the following code sample:
using System;
using Unity.Cloud.Identity;
using UnityEngine;
public class AssetDiscoveryUI : MonoBehaviour
{
protected readonly AssetDiscoveryBehaviour m_Behaviour = new();
IAuthenticationStateProvider m_AuthenticationStateProvider;
Vector2 m_ProjectListScrollPosition;
Vector2 m_AssetListScrollPosition;
bool IsLoggedIn => m_AuthenticationStateProvider?.AuthenticationState == AuthenticationState.LoggedIn;
void Start()
{
m_AuthenticationStateProvider = PlatformServices.AuthenticationStateProvider;
m_AuthenticationStateProvider.AuthenticationStateChanged += OnAuthenticationStateChanged;
}
void OnDestroy()
{
if (m_AuthenticationStateProvider != null)
{
m_AuthenticationStateProvider.AuthenticationStateChanged -= OnAuthenticationStateChanged;
}
}
void OnGUI()
{
GUILayout.BeginHorizontal();
UpdateAuthenticationUI(m_AuthenticationStateProvider.AuthenticationState);
if (!IsLoggedIn)
{
GUILayout.EndHorizontal();
return;
}
if (!m_Behaviour.IsOrganizationSelected)
{
// Refresh the org list
if (GUILayout.Button("Refresh"))
{
_ = m_Behaviour.GetOrganizationsAsync();
return;
}
GUILayout.Space(50);
// If an organization is not selected, list those available.
SelectAnOrganization();
}
else if (!m_Behaviour.IsProjectSelected)
{
GUILayout.BeginVertical();
// Go back to select a different scene.
if (GUILayout.Button("Back"))
{
m_Behaviour.SetSelectedOrganization(null);
return;
}
// Refresh the org list
if (GUILayout.Button("Refresh"))
{
m_Behaviour.GetProjects();
return;
}
GUILayout.EndVertical();
GUILayout.Space(50);
SelectAProject();
}
else
{
// Go back to select a different scene.
if (GUILayout.Button("Back"))
{
m_Behaviour.SetSelectedProject(null);
return;
}
GUILayout.Space(50);
SelectAnAsset();
GUILayout.Space(50);
AssetActions();
}
GUILayout.EndHorizontal();
}
protected virtual void AssetActions()
{
// Add additional actions here.
}
void SelectAnOrganization()
{
GUILayout.BeginVertical();
GUILayout.Label("Available Organizations:");
GUILayout.Space(10);
var availableOrganizations = m_Behaviour.AvailableOrganizations;
if (availableOrganizations != null)
{
for (var i = 0; i < availableOrganizations.Length; ++i)
{
if (GUILayout.Button(availableOrganizations[i].Name))
{
m_Behaviour.SetSelectedOrganization(availableOrganizations[i]);
}
}
}
else
{
GUILayout.Label("Loading...");
}
GUILayout.EndVertical();
}
void SelectAProject()
{
GUILayout.BeginVertical();
GUILayout.Label($"{m_Behaviour.CurrentOrganization.Name}");
GUILayout.Space(10);
GUILayout.Label("Available Projects:");
GUILayout.Space(10);
var projects = m_Behaviour.AvailableProjects;
if (projects.Count > 0)
{
m_ProjectListScrollPosition = GUILayout.BeginScrollView(m_ProjectListScrollPosition, GUILayout.Height(Screen.height * 0.8f));
for (var i = 0; i < projects.Count; ++i)
{
if (GUILayout.Button(projects[i].Name))
{
m_Behaviour.SetSelectedProject(projects[i]);
}
}
GUILayout.EndScrollView();
}
else
{
GUILayout.Label("No projects found.");
}
GUILayout.EndVertical();
}
void SelectAnAsset()
{
GUILayout.BeginVertical();
GUILayout.Label($"{m_Behaviour.CurrentOrganization.Name} >> {m_Behaviour.CurrentProject.Name}");
GUILayout.Space(10);
GUILayout.Label("Available Assets:");
GUILayout.Space(10);
var assets = m_Behaviour.AvailableAssets;
if (assets.Count > 0)
{
m_AssetListScrollPosition = GUILayout.BeginScrollView(m_AssetListScrollPosition, GUILayout.Height(Screen.height * 0.3f));
for (var i = 0; i < assets.Count; ++i)
{
if (GUILayout.Button(assets[i].Name))
{
m_Behaviour.CurrentAsset = assets[i];
Debug.Log($"Selected: {assets[i].Name}");
}
}
GUILayout.EndScrollView();
}
else
{
GUILayout.Label("No assets found.");
}
GUILayout.EndVertical();
}
static void UpdateAuthenticationUI(AuthenticationState state)
{
GUILayout.BeginVertical();
switch (state)
{
case AuthenticationState.AwaitingInitialization:
GUILayout.Label("Initializing Service...");
break;
case AuthenticationState.AwaitingLogout:
GUILayout.Label("Logging out...");
break;
case AuthenticationState.LoggedOut:
if (GUILayout.Button("Login"))
{
_ = PlatformServices.Authenticator.LoginAsync();
}
break;
case AuthenticationState.AwaitingLogin:
GUILayout.Label("Logging in...");
if (GUILayout.Button("Cancel"))
{
PlatformServices.Authenticator.CancelLogin();
}
break;
case AuthenticationState.LoggedIn:
if (GUILayout.Button("Logout"))
{
_ = PlatformServices.Authenticator.LogoutAsync();
}
break;
default:
throw new ArgumentOutOfRangeException(nameof(state), state, null);
}
GUILayout.EndVertical();
}
void OnAuthenticationStateChanged(AuthenticationState obj)
{
if (obj == AuthenticationState.LoggedIn)
{
_ = m_Behaviour.GetOrganizationsAsync();
}
}
}
The script does the following:
- Registers to the
IAuthenticator
to track login changes. - Creates an instance of an
AssetDiscoveryBehaviour
. - Creates a simple UI flow for selecting organizations, projects and assets.