Use case: Manage an asset's metadata
Use the Unity Cloud Assets package to perform the following:
- View the metadata of an asset.
- Add or remove a metadata entry from an asset.
- Update the value of the metadata entry of an asset.
Note
To manage assets, you need the Asset Manager Admin role at the organization level or the Asset Manager Contributor add-on role at the project level. Asset Manager Contributors can manage assets only for the specific projects to which they have access.
Before you start
Before you start, do the following:
Verify you have the required permissions. Read more about verifying permissions.
Note
Asset Manager roles define the permissions that you have for a single Asset Manager project. Depending on your work, permissions may vary across projects.
Create assets in Unity Cloud in any of the following ways:
- Add assets using the Asset SDK.
- Add a single asset or multiple assets through the dashboard.
How do I...?
View the metadata of an asset
To fetch the metadata of an asset, follow these steps:
- Open the
AssetManagementBehaviourscript that you created as described in Get started with Asset SDK. - Add the following code to the end of the class:
IReadOnlyMetadataContainer MetadataContainer { get; set; }
public IReadOnlyDictionary<string, MetadataValue> Metadata { get; private set; }
public async Task GetMetadataAsync(IReadOnlyMetadataContainer metadataContainer)
{
MetadataContainer = metadataContainer;
Metadata = null;
if (metadataContainer == null) return;
var result = MetadataContainer.Query().ExecuteAsync(CancellationToken.None);
var metadata = new Dictionary<string, MetadataValue>();
await foreach (var item in result)
{
metadata[item.Key] = item.Value;
}
Metadata = metadata;
Debug.Log("Successfully fetched metadata.");
}
The code snippet fills a dictionary with metadata.
Add or update entries in an asset's metadata
[!NOTE] Metadata keys must be pre-existing in your organization's library. Read more about adding and removing metadata keys.
To add or update an entry in the metadata of an asset, follow these steps:
- Open the
AssetManagementBehaviourscript that you created as described in Get started with Asset SDK. - Add the following code to the end of the class:
public async Task UpdateAsync(string key, MetadataValue value)
{
try
{
if (MetadataContainer is not IMetadataContainer metadataContainer)
{
throw new NotSupportedException();
}
await metadataContainer.AddOrUpdateAsync(key, value, CancellationToken.None);
Debug.Log("Successfully updated metadata.");
}
catch (Exception e)
{
Debug.LogError("Could not update metadata: " + e.Message);
}
}
The code snippet does the following:
- Adds or updates the specified metadata key with the provided value for the selected asset.
- Displays a success message in the console.
Remove an entry from an asset's metadata
To remove an entry from the metadata:
- Open the
AssetManagementBehaviourscript that you created as described in Get started with Asset SDK. - Add the following code to the end of the class:
public async Task RemoveMetadata(string key)
{
try
{
if (MetadataContainer is not IMetadataContainer metadataContainer)
{
throw new NotSupportedException();
}
await metadataContainer.RemoveAsync(new[] {key}, CancellationToken.None);
Debug.Log("Successfully removed metadata.");
}
catch (Exception e)
{
Debug.LogError("Could not remove metadata: " + e.Message);
}
}
The code snippet does the following:
- Removes the specified metadata key from the selected asset.
- Displays a success message in the console.
Add a UI for viewing and modifying the metadata of an asset
To create the UI, start by creating helper classes:
- In the Project window of the Unity Editor, go to Assets > Scripts.
- Select and hold the
Assets/Scriptsfolder. - Go to Create > C# Script.
- Name your script
BooleanMetadataValueDisplayer. - Open the file and replace its contents with the following code sample:
public interface IMetadataValueDisplayer
{
MetadataValue Value { get; }
bool IsValid { get; }
void Display();
}
public class BooleanMetadataValueDisplayer : IMetadataValueDisplayer
{
readonly BooleanMetadata m_Boolean;
public MetadataValue Value => m_Boolean;
public bool IsValid => true;
public BooleanMetadataValueDisplayer(BooleanMetadata value)
{
m_Boolean = value;
}
public void Display()
{
m_Boolean.Value = GUILayout.Toggle(m_Boolean.Value, "Is enabled");
}
}
- Repeat steps 3, 4 and 5 to create subsequent helper classes with the following scripts and code samples:
- For the
NumberMetadataValueDisplayerscript, use the following code sample:
public class NumberMetadataValueDisplayer : IMetadataValueDisplayer
{
readonly NumberMetadata m_Number;
public MetadataValue Value => m_Number;
public bool IsValid { get; private set; }
public NumberMetadataValueDisplayer(NumberMetadata value)
{
m_Number = value;
}
public void Display()
{
var number = GUILayout.TextField(m_Number.Value.ToString());
if (string.IsNullOrWhiteSpace(number))
{
number = "0";
}
if (number.StartsWith('.'))
{
number = number.Insert(0, "0");
}
else if (number.EndsWith('.'))
{
number = number.Insert(number.Length, "0");
}
if (double.TryParse(number, out var parsedNumber))
{
m_Number.Value = parsedNumber;
IsValid = true;
}
else
{
IsValid = false;
GUILayout.Label("Invalid number");
}
}
}
- For the
UrlMetadataValueDisplayerscript, use the following code sample:
public class UrlMetadataValueDisplayer : IMetadataValueDisplayer
{
readonly UrlMetadata m_UrlMetadata;
string m_Url;
public MetadataValue Value => m_UrlMetadata;
public bool IsValid { get; private set; }
public UrlMetadataValueDisplayer(UrlMetadata value)
{
m_UrlMetadata = value;
m_Url = m_UrlMetadata.Uri.ToString();
}
public void Display()
{
m_UrlMetadata.Label = GUILayout.TextField(m_UrlMetadata.Label);
m_Url = GUILayout.TextField(m_Url);
if (Uri.TryCreate(m_Url, UriKind.Absolute, out var uri))
{
m_UrlMetadata.Uri = uri;
IsValid = true;
}
else
{
IsValid = false;
GUILayout.Label("Invalid URL");
}
}
}
- For the
SingleSelectionMetadataValueDisplayerscript, use the following code sample:
public class SingleSelectionMetadataValueDisplayer : IMetadataValueDisplayer
{
readonly SingleSelectionMetadata m_SelectionMetadata;
readonly HashSet<string> m_AcceptedValues = new();
public MetadataValue Value => m_SelectionMetadata;
public bool IsValid { get; private set; }
public SingleSelectionMetadataValueDisplayer(SingleSelectionMetadata value, FieldDefinitionDescriptor definitionDescriptor)
{
m_SelectionMetadata = value;
_ = PopulateAcceptedValues(definitionDescriptor);
}
async Task PopulateAcceptedValues(FieldDefinitionDescriptor descriptor)
{
var fieldDefinition = await PlatformServices.AssetRepository.GetFieldDefinitionAsync(descriptor, default);
try
{
var selectionFieldDefinitionProperties = await fieldDefinition.AsSelectionFieldDefinition().GetPropertiesAsync(default);
m_AcceptedValues.UnionWith(selectionFieldDefinitionProperties.AcceptedValues);
}
catch (Exception)
{
// Fail silently
}
}
public void Display()
{
GUILayout.Label("Accepted values: " + string.Join(", ", m_AcceptedValues));
m_SelectionMetadata.SelectedValue = GUILayout.TextField(m_SelectionMetadata.SelectedValue);
IsValid = m_AcceptedValues.Contains(m_SelectionMetadata.SelectedValue);
if (!IsValid)
{
GUILayout.Label("Invalid value");
}
}
}
- For the
MultiSelectionMetadataValueDisplayerscript, use the following code sample:
public class MultiSelectionMetadataValueDisplayer : IMetadataValueDisplayer
{
readonly MultiSelectionMetadata m_SelectionMetadata;
readonly HashSet<string> m_AcceptedValues = new();
string m_SelectedValues;
public MetadataValue Value => m_SelectionMetadata;
public bool IsValid { get; private set; }
public MultiSelectionMetadataValueDisplayer(MultiSelectionMetadata value, FieldDefinitionDescriptor descriptor)
{
m_SelectionMetadata = value;
m_SelectedValues = string.Join(", ", m_SelectionMetadata.SelectedValues);
_ = PopulateAcceptedValues(descriptor);
}
async Task PopulateAcceptedValues(FieldDefinitionDescriptor descriptor)
{
var fieldDefinition = await PlatformServices.AssetRepository.GetFieldDefinitionAsync(descriptor, default);
try
{
var selectionFieldDefinitionProperties = await fieldDefinition.AsSelectionFieldDefinition().GetPropertiesAsync(default);
m_AcceptedValues.UnionWith(selectionFieldDefinitionProperties.AcceptedValues);
}
catch (Exception)
{
// Fail silently
}
}
public void Display()
{
GUILayout.Label("Accepted values: " + string.Join(", ", m_AcceptedValues));
m_SelectedValues = GUILayout.TextField(m_SelectedValues);
IsValid = true;
var selectedValues = new List<string>();
var selectedValuesString = m_SelectedValues.Split(',');
foreach (var selectedValue in selectedValuesString)
{
var value = selectedValue.Trim();
if (string.IsNullOrWhiteSpace(value)) continue;
if (!m_AcceptedValues.Contains(value))
{
IsValid = false;
break;
}
selectedValues.Add(value);
}
if (!IsValid)
{
GUILayout.Label("Invalid value");
}
else
{
m_SelectionMetadata.SelectedValues = selectedValues;
}
}
}
- For the
TextMetadataValueDisplayerscript, use the following code sample:
public class TextMetadataValueDisplayer : IMetadataValueDisplayer
{
readonly StringMetadata m_Text;
public MetadataValue Value => m_Text;
public bool IsValid => true;
public TextMetadataValueDisplayer(StringMetadata value)
{
m_Text = value;
}
public void Display()
{
m_Text.Value = GUILayout.TextField(m_Text.Value);
}
}
To complete the UI, follow these steps:
- In the Project window of the Unity Editor, go to Assets > Scripts.
- Select and hold the
Assets/Scriptsfolder. - Go to Create > C# Script.
- Name your script
UseCaseAssetMetadataExampleUI. - Open the file and replace its contents with the following code sample:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using Unity.Cloud.Assets;
using Unity.Cloud.Identity;
public class UseCaseAssetMetadataExampleUI : IAssetManagementUI
{
readonly AssetManagementBehaviour m_Behaviour;
public UseCaseAssetMetadataExampleUI(AssetManagementBehaviour behaviour)
{
m_Behaviour = behaviour;
}
public void OnGUI() { }
}
- In the same script, replace the
OnGUIfunction with the following code:
enum MetadataType
{
none,
metadata,
systemMetadata
}
IAsset m_CurrentAsset;
MetadataType m_MetadataType;
Vector2 m_MetadataListScrollPosition;
string m_CurrentMetadataKey;
IMetadataValueDisplayer m_MetadataValueDisplayer;
string m_NewKey = string.Empty;
string m_NewValue = string.Empty;
public void OnGUI()
{
if (!m_Behaviour.IsProjectSelected) return;
if (m_CurrentAsset != m_Behaviour.CurrentAsset)
{
m_CurrentAsset = m_Behaviour.CurrentAsset;
m_CurrentMetadataKey = null;
m_MetadataValueDisplayer = null;
_ = m_MetadataType switch
{
MetadataType.metadata => m_Behaviour.GetMetadataAsync(m_Behaviour.CurrentAsset?.Metadata as IReadOnlyMetadataContainer),
MetadataType.systemMetadata => m_Behaviour.GetMetadataAsync(m_Behaviour.CurrentAsset?.SystemMetadata),
_ => m_Behaviour.GetMetadataAsync(null)
};
}
if (m_CurrentAsset == null)
{
GUILayout.Label(" ! No asset selected !");
return;
}
GUILayout.BeginVertical();
DisplayMetadataTypeToggle();
if (m_MetadataType == MetadataType.none)
{
GUILayout.Label(" ! No metadata selected !");
GUILayout.EndVertical();
return;
}
if (m_Behaviour.Metadata == null)
{
GUILayout.Label("Loading...");
GUILayout.EndVertical();
return;
}
ListAssetMetadata();
AddMetadata();
GUILayout.EndVertical();
DisplayCurrentMetadataValue();
}
void DisplayMetadataTypeToggle()
{
GUILayout.BeginHorizontal();
GUI.enabled = m_MetadataType != MetadataType.metadata;
if (GUILayout.Button("Metadata", GUILayout.Width(130)))
{
m_MetadataType = MetadataType.metadata;
_ = m_Behaviour.GetMetadataAsync(m_Behaviour.CurrentAsset.Metadata as IReadOnlyMetadataContainer);
}
GUI.enabled = m_MetadataType != MetadataType.systemMetadata;
if (GUILayout.Button("System Metadata", GUILayout.Width(130)))
{
m_MetadataType = MetadataType.systemMetadata;
_ = m_Behaviour.GetMetadataAsync(m_Behaviour.CurrentAsset.SystemMetadata);
}
GUI.enabled = true;
GUILayout.EndHorizontal();
}
void ListAssetMetadata()
{
m_MetadataListScrollPosition = GUILayout.BeginScrollView(m_MetadataListScrollPosition);
if (m_Behaviour.Metadata.Count == 0)
{
GUILayout.Label("No metadata.");
}
foreach (var key in m_Behaviour.Metadata.Keys)
{
GUILayout.BeginHorizontal();
GUILayout.Label(key, GUILayout.ExpandWidth(true));
if (GUILayout.Button("Select", GUILayout.Width(60)))
{
m_CurrentMetadataKey = key;
var metadataValue = m_Behaviour.Metadata[key];
m_MetadataValueDisplayer = metadataValue.ValueType switch
{
MetadataValueType.Boolean => new BooleanMetadataValueDisplayer(metadataValue.AsBoolean()),
MetadataValueType.Number => new NumberMetadataValueDisplayer(metadataValue.AsNumber()),
MetadataValueType.Url => new UrlMetadataValueDisplayer(metadataValue.AsUrl()),
MetadataValueType.SingleSelection => new SingleSelectionMetadataValueDisplayer(metadataValue.AsSingleSelection(),
new FieldDefinitionDescriptor(m_Behaviour.CurrentOrganization.Id, key)),
MetadataValueType.MultiSelection => new MultiSelectionMetadataValueDisplayer(metadataValue.AsMultiSelection(),
new FieldDefinitionDescriptor(m_Behaviour.CurrentOrganization.Id, key)),
_ => new TextMetadataValueDisplayer(metadataValue.AsText())
};
}
if (m_MetadataType == MetadataType.metadata && GUILayout.Button("Remove", GUILayout.Width(60)))
{
_ = m_Behaviour.RemoveMetadata(key);
}
GUILayout.EndHorizontal();
}
GUILayout.EndScrollView();
}
void AddMetadata()
{
if (m_Behaviour.Metadata == null) return;
GUI.enabled = m_MetadataType == MetadataType.metadata;
GUILayout.BeginVertical();
GUILayout.Label("Key:");
m_NewKey = GUILayout.TextField(m_NewKey);
GUILayout.Label("Value:");
m_NewValue = GUILayout.TextField(m_NewValue);
GUI.enabled &= !string.IsNullOrWhiteSpace(m_NewKey) && !string.IsNullOrWhiteSpace(m_NewValue);
try
{
m_NewValue ??= string.Empty;
if (GUILayout.Button("Add Boolean"))
{
_ = m_Behaviour.UpdateAsync(m_NewKey, new BooleanMetadata(bool.Parse(m_NewValue)));
}
if (GUILayout.Button("Add Number"))
{
_ = m_Behaviour.UpdateAsync(m_NewKey, new NumberMetadata(double.Parse(m_NewValue)));
}
if (GUILayout.Button("Add Timestamp"))
{
_ = m_Behaviour.UpdateAsync(m_NewKey, new DateTimeMetadata(DateTime.Parse(m_NewValue)));
}
if (GUILayout.Button("Add Multi-selection"))
{
_ = m_Behaviour.UpdateAsync(m_NewKey, new MultiSelectionMetadata(m_NewValue.Split(',').Select(x => x.Trim()).ToArray()));
}
if (GUILayout.Button("Add String"))
{
_ = m_Behaviour.UpdateAsync(m_NewKey, new StringMetadata(m_NewValue));
}
}
catch (Exception e)
{
Debug.LogError("Could not add metadata: " + e.Message);
}
GUI.enabled = true;
GUILayout.EndVertical();
}
void DisplayCurrentMetadataValue()
{
if (m_Behaviour.Metadata == null || m_Behaviour.Metadata.Count == 0) return;
if (m_CurrentMetadataKey == null)
{
GUILayout.Label(" ! No metadata value selected !");
return;
}
GUILayout.BeginVertical();
GUILayout.Label(m_CurrentMetadataKey);
GUI.enabled = m_MetadataType == MetadataType.metadata;
m_MetadataValueDisplayer.Display();
GUI.enabled &= m_MetadataValueDisplayer.IsValid;
if (GUILayout.Button("Update"))
{
_ = m_Behaviour.UpdateAsync(m_CurrentMetadataKey, m_MetadataValueDisplayer.Value);
}
GUI.enabled = true;
GUILayout.EndVertical();
}
- Open the
AssetManagementUIscript that you created as described in Get started with Asset SDK and replace the content of theAwakefunction with the following code:
m_UI.Add(new OrganizationSelectionExampleUI(m_Behaviour));
m_UI.Add(new ProjectSelectionExampleUI(m_Behaviour));
m_UI.Add(new AssetSelectionExampleUI(m_Behaviour));
m_UI.Add(new UseCaseAssetMetadataExampleUI(m_Behaviour));
The code snippet displays the following UI elements:
The list of metadata
For each metadata key, the Select and Delete buttons
If you select a metadata key:
An editable field that contains the key value
The Update button to save your modifications
[!NOTE] This editable field displays only when you select a metadata key.