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/Scenesfolder 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/Scriptsfolder if the folder doesn't already exist. - Right-click the
Assets/Scriptsfolder and go to Create > C# Script. Name your scriptAssetDiscoveryUI. - In the
AssetDiscoveryExamplescene you created earlier, right-click the hierarchy and select Create Empty. - Name your new object
AssetDiscovery. - Select the
AssetDiscoveryobject and add theAssetDiscoveryUIscript 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
PlatformServicesclass in yourPlatformServices.csfile 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);
AssetProvider = new CloudAssetDiscovery(serviceHttpClient, serviceHostResolver);
}
/// <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
IAuthenticatorfor logging in and verifying your identity when accessing the HTTP services. - Initializes an
IOrganizationProviderto fetch the organizations you belong to. - Initializes an
IProjectProviderto fetch the projects you have access to. - Initializes an
IAssetProviderto 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/Scriptsfolder and go to Create > C# Script. Name your scriptPlatformServicesInitialization. - In the
AssetDiscoveryExamplescene you created earlier, right-click the hierarchy and select Create Empty. - Name your new object
PlatformServices. - Select the
PlatformServicesobject and add thePlatformServicesInitializationscript you created earlier. - Update the
PlatformServicesInitializationclass in yourPlatformServicesInitialization.csfile 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/Scriptsfolder and go to Create > C# Script. Name your scriptPlatformServicesShutdown. - Select the
PlatformServicesobject you created earlier and add thePlatformServicesShutdownscript you created earlier. - Update the
PlatformServicesShutdownclass in yourPlatformServicesShutdown.csfile 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/Scriptsfolder and go to Create > C# Script. Name your scriptAssetDiscoveryBehaviour. - Open the
AssetDiscoveryBehaviourscript you created and replace the contents of the file with the following code sample:
using System;
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), 25);
IOrganization[] m_AvailableOrganizations;
IOrganization m_CurrentOrganization;
IProjectPage m_AvailableProjects;
IProject m_CurrentProject;
IAssetPage m_AvailableAssets;
public IOrganization[] AvailableOrganizations => m_AvailableOrganizations;
public IOrganization CurrentOrganization => m_CurrentOrganization;
public bool IsOrganizationSelected => m_CurrentOrganization != null;
public IProjectPage AvailableProjects => m_AvailableProjects;
public IProject CurrentProject => m_CurrentProject;
public bool IsProjectSelected => m_CurrentProject != null;
public IAssetPage AvailableAssets => m_AvailableAssets;
public IAsset CurrentAsset { get; set; }
public void Clear()
{
m_CurrentProject = null;
m_AvailableProjects = null;
m_CurrentOrganization = null;
}
public void SetSelectedOrganization(IOrganization organization)
{
m_CurrentOrganization = organization;
if (m_CurrentOrganization != null)
{
_ = GetProjectsAsync();
}
}
public void SetSelectedProject(IProject project)
{
m_CurrentProject = project;
if (m_CurrentProject != null)
{
_ = GetAssetsAsync();
}
}
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 async Task GetProjectsAsync()
{
m_AvailableProjects = null;
try
{
var cancellationTokenSrc = new CancellationTokenSource();
m_AvailableProjects = await PlatformServices.ProjectProvider.GetCurrentUserProjectList(m_CurrentOrganization, m_DefaultPagination, cancellationTokenSrc.Token);
}
catch (OperationCanceledException oe)
{
Debug.LogError(oe);
}
catch (AggregateException e)
{
Debug.LogError(e.InnerException);
}
catch (Exception e)
{
Debug.LogError(e);
}
}
public void GetPreviousProjects()
{
m_AvailableProjects = m_AvailableProjects?.PreviousPage as IProjectPage;
}
public Task GetNextAvailableProjectsAsync()
{
return Task.CompletedTask;
}
async Task GetAssetsAsync()
{
m_AvailableAssets = null;
CurrentAsset = null;
try
{
var cancellationTokenSrc = new CancellationTokenSource();
m_AvailableAssets = await PlatformServices.AssetProvider.SearchAsync(new AssetSearchFilter(m_CurrentOrganization, m_CurrentProject), m_DefaultPagination, cancellationTokenSrc.Token);
}
catch (OperationCanceledException oe)
{
Debug.LogError(oe);
}
catch (AggregateException e)
{
Debug.LogError(e.InnerException);
}
catch (Exception e)
{
Debug.LogError(e);
}
}
public void GetPreviousAssets()
{
m_AvailableAssets = m_AvailableAssets?.PreviousPage as IAssetPage;
}
public Task GetNextAvailableAssetsAsync()
{
return Task.CompletedTask;
}
}
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;
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.GetProjectsAsync();
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 projectPage = m_Behaviour.AvailableProjects;
if (projectPage != null)
{
var projects = projectPage.Elements;
for (var i = 0; i < projects.Length; ++i)
{
if (GUILayout.Button(projects[i].Name))
{
m_Behaviour.SetSelectedProject(projects[i]);
}
}
GUILayout.BeginHorizontal();
GUI.enabled = projectPage.PreviousPage != null;
// Go back to select a different scene.
if (GUILayout.Button("Previous Page"))
{
m_Behaviour.GetPreviousProjects();
}
GUI.enabled = !string.IsNullOrEmpty(projectPage.NextPageToken);
// Go back to select a different scene.
if (GUILayout.Button("Next Page"))
{
_ = m_Behaviour.GetNextAvailableProjectsAsync();
}
GUI.enabled = true;
GUILayout.EndHorizontal();
}
else
{
GUILayout.Label("Loading...");
}
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 assetPage = m_Behaviour.AvailableAssets;
if (assetPage != null)
{
var assets = assetPage.Elements;
for (var i = 0; i < assets.Length; ++i)
{
if (GUILayout.Button(assets[i].Name))
{
m_Behaviour.CurrentAsset = assets[i];
Debug.Log($"Selected: {assets[i].Name}");
}
}
GUILayout.BeginHorizontal();
GUI.enabled = assetPage.PreviousPage != null;
// Go back to select a different scene.
if (GUILayout.Button("Previous Page"))
{
m_Behaviour.GetPreviousAssets();
}
GUI.enabled = !string.IsNullOrEmpty(assetPage.NextPageToken);
// Go back to select a different scene.
if (GUILayout.Button("Next Page"))
{
_ = m_Behaviour.GetNextAvailableAssetsAsync();
}
GUI.enabled = true;
GUILayout.EndHorizontal();
}
else
{
GUILayout.Label("Loading...");
}
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
IAuthenticatorto track login changes. - Creates an instance of an
AssetDiscoveryBehaviour. - Creates a simple UI flow for selecting organizations, projects and assets.