docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Use case: Create and upload files to a dataset

    You can use the Unity Cloud Assets package to perform the following:

    • View the files of an asset.
    • Upload files to an asset's dataset.
    • Reference files between datasets.
    Note

    To create and upload assets, as well as add or remove file references, you need an Asset Manager Admin role at Organization level or an Asset Management Contributor add-on role at Project level. Asset Management Contributors can manage assets only for the specific projects to which they have access.

    Before you start

    Before you start, do the following:

    1. Verify your permissions as described in Asset Manager user roles.
    Note

    Asset Manager roles specify permissions you have for a single Asset Manager project. Depending on your work, permissions can vary across different projects.

    1. Set up a Unity scene in the Unity Editor with an Organization and Project browser. See the Get started with Asset SDK page for more information.

    2. Create assets in the cloud any of the following ways:

      • Add assets using the Asset SDK.
      • Add single or multiple assets through the dashboard.

    How do I...?

    List an asset's datasets and files

    List datasets as follows:

    1. Open the AssetManagementBehaviour script you created as described in Get started with Asset SDK.
    2. Add the following code to the end of the class:
    
    public List<IDataset> Datasets { get; private set; }
    
    public async Task GetDatasets()
    {
        Datasets = null;
    
        if (CurrentAsset == null) return;
    
        var datasets = new List<IDataset>();
        var asyncList = CurrentAsset.ListDatasetsAsync(Range.All, CancellationToken.None);
        await foreach (var dataset in asyncList)
        {
            datasets.Add(dataset);
        }
    
        Datasets = datasets;
    }
    
    

    List files as follows:

    1. Open the AssetManagementBehaviour script you created as described in Get started with Asset SDK.
    2. Add the following code to the end of the class:
    
    public Dictionary<DatasetId, IEnumerable<IFile>> DatasetFiles { get; } = new();
    
    public async Task GetFilesAsync(DatasetId datasetId)
    {
        DatasetFiles.Remove(datasetId);
    
        var dataset = Datasets?.FirstOrDefault(d => d.Descriptor.DatasetId == datasetId);
        if (dataset == null) return;
    
        DatasetFiles[datasetId] = null;
    
        var files = new List<IFile>();
        var fileList = dataset.ListFilesAsync(Range.All, CancellationToken.None);
        await foreach (var file in fileList)
        {
            files.Add(file);
        }
    
        files.Sort((a, b) => string.Compare(a.Descriptor.Path, b.Descriptor.Path, StringComparison.Ordinal));
    
        DatasetFiles[datasetId] = files;
    }
    
    

    Upload a file

    Upload a file to an asset's dataset as follows:

    1. Open the AssetManagementBehaviour script you created as described in Get started with Asset SDK.
    2. Add the following code to the end of the class:
    
    class LogProgress : IProgress<HttpProgress>
    {
        string m_Name;
    
        public LogProgress(string name)
        {
            m_Name = name;
        }
    
        public void Report(HttpProgress value)
        {
            if (!value.UploadProgress.HasValue) return;
    
            Debug.Log($"Upload progress for {m_Name}: {value.UploadProgress * 100} %");
        }
    }
    
    static string GetRelativePath(string folderPath, string filePath)
    {
        return string.IsNullOrEmpty(folderPath) ? filePath : Path.GetRelativePath(folderPath, filePath);
    }
    
    public async Task UploadFile(IDataset dataset, string filePath, string folderPath = "", bool refreshFiles = true)
    {
        var fileCreation = new FileCreation(GetRelativePath(folderPath, filePath))
        {
            Description = "Documentation example file creation.",
        };
    
        try
        {
            var progress = new LogProgress(filePath);
    
            var fileStream = File.OpenRead(filePath);
            var file = await dataset.UploadFileAsync(fileCreation, fileStream, progress, default);
            await dataset.RefreshAsync(default);
    
            if (refreshFiles)
            {
                _ = GetFilesAsync(dataset.Descriptor.DatasetId);
            }
    
            Debug.Log($"File upload: {file.Descriptor.Path} added and uploaded.");
        }
        catch (Exception e)
        {
            Debug.LogError($"Failed to upload file: {fileCreation.Path}. {e}");
        }
    }
    
    public async Task ReplaceFile(IDataset dataset, string filePath, string folderPath = "", bool refreshFiles = true)
    {
        var path = GetRelativePath(folderPath, filePath);
    
        if (DatasetFiles.TryGetValue(dataset.Descriptor.DatasetId, out var files))
        {
            var file = files.FirstOrDefault(f => f.Descriptor.Path == path);
            if (file != null)
            {
                try
                {
                    await dataset.RemoveFileAsync(file.Descriptor.Path, CancellationToken.None);
                }
                catch (Exception e)
                {
                    Debug.LogError($"Failed to remove file for replace: {file.Descriptor.Path}. {e}");
                    return;
                }
            }
        }
    
        await UploadFile(dataset, filePath, folderPath, refreshFiles);
    }
    
    public async Task ReuploadFile(IDataset dataset, string filePath, string folderPath = "", bool refreshFiles = true)
    {
        var path = GetRelativePath(folderPath, filePath);
    
        if (DatasetFiles.TryGetValue(dataset.Descriptor.DatasetId, out var files))
        {
            var file = files.FirstOrDefault(f => f.Descriptor.Path == path);
            if (file != null)
            {
                try
                {
                    var logProgress = new LogProgress(path);
    
                    var fileStream = File.OpenRead(filePath);
                    await file.UploadAsync(fileStream, logProgress, default);
                    await dataset.RefreshAsync(default);
    
                    if (refreshFiles)
                    {
                        _ = GetFilesAsync(dataset.Descriptor.DatasetId);
                    }
    
                    Debug.Log($"Re-uplaoded file: {file.Descriptor.Path}.");
                }
                catch (Exception e)
                {
                    Debug.LogError($"Failed to re-upload file: {file.Descriptor.Path}. {e}");
                }
    
                return;
            }
        }
    
        await UploadFile(dataset, filePath, folderPath, refreshFiles);
    }
    
    

    The code snippet does the following:

    • Provides a method to upload a new file to a dataset.
    • Provides a method to replace the content of an existing file in a dataset.
    • Provides a method to replace a file in a dataset with another file.

    Upload a folder

    Upload a folder to an asset's dataset as follows:

    1. Open the AssetManagementBehaviour script you created as described in Get started with Asset SDK.
    2. Add the following code to the end of the class:
    
    public async Task UploadFolderAsync(IDataset dataset, string folderPath, string uploadType)
    {
        var parentDirectoryPath = Directory.GetParent(folderPath)?.FullName;
        var files = Directory.GetFiles(folderPath, "*.*", SearchOption.AllDirectories);
    
        var tasks = new List<Task>();
        foreach (var file in files)
        {
            switch (uploadType)
            {
                case "Replace":
                    tasks.Add(ReplaceFile(dataset, file, parentDirectoryPath, false));
                    break;
                case "Reupload":
                    tasks.Add(ReuploadFile(dataset, file, parentDirectoryPath, false));
                    break;
                default:
                    tasks.Add(UploadFile(dataset, file, parentDirectoryPath, false));
                    break;
            }
        }
    
        try
        {
            await Task.WhenAll(tasks);
    
            _ = GetFilesAsync(dataset.Descriptor.DatasetId);
    
            Debug.Log($"Folder: {folderPath} uploaded.");
        }
        catch (Exception e)
        {
            Debug.LogError($"Failed to upload folder: {folderPath}. {e}");
        }
    }
    
    

    The code snippet provides a method to upload the entire content of a folder to a dataset.

    Note

    The method checks for existing files in the dataset and replaces their content. If an existing file is not found, it uploads the file as new.

    Reference a file in a different dataset

    Reference a file in a different dataset as follows:

    1. Open the AssetManagementBehaviour script you created as described in Get started with Asset SDK.
    2. Add the following code to the end of the class:
    
    public async Task LinkFile(IDataset dataset, IFile file)
    {
        try
        {
            await dataset.AddExistingFileAsync(file.Descriptor.Path, file.Descriptor.DatasetId, CancellationToken.None);
            Debug.Log($"File: {file.Descriptor.Path} linked to dataset {dataset.Descriptor.DatasetId}.");
    
            // If the dataset files are already loaded, refresh them
            if (DatasetFiles.ContainsKey(dataset.Descriptor.DatasetId))
            {
                _ = GetFilesAsync(dataset.Descriptor.DatasetId);
            }
        }
        catch (Exception e)
        {
            Debug.LogError($"Failed to link file: {file.Descriptor.Path}. {e}");
        }
    }
    
    

    The code snippet does the following:

    • Links a file to a dataset.
    • Prints a success message to the console on success or an error message if the linking fails.

    Remove a file reference from a dataset

    Remove a file reference from a dataset as follows:

    1. Open the AssetManagementBehaviour script you created as described in Get started with Asset SDK.
    2. Add the following code to the end of the class:
    
    public async Task UnlinkFile(IDataset dataset, IFile file)
    {
        try
        {
            await dataset.RemoveFileAsync(file.Descriptor.Path, CancellationToken.None);
            Debug.Log($"File: {file.Descriptor.Path} unlinked from dataset {dataset.Descriptor.DatasetId}.");
    
            // If the dataset files are already loaded, refresh them
            if (DatasetFiles.ContainsKey(dataset.Descriptor.DatasetId))
            {
                _ = GetFilesAsync(dataset.Descriptor.DatasetId);
            }
        }
        catch (Exception e)
        {
            Debug.LogError($"Failed to unlink file: {file.Descriptor.Path}. {e}");
        }
    }
    
    

    The code snippet does the following:

    • Unlinks a file from a dataset.
    • Prints a success message to the console on success or an error message if the unlinking fails.

    Add a UI to create files

    Add a UI to create files as follows:

    1. In your Unity Project window, go to Assets > Scripts.
    2. Select and hold the Assets/Scripts folder.
    3. Go to Create > C# Script.
    4. Name your script UseCaseFileCreationExampleUI.
    5. Open the UseCaseFileCreationExampleUI script you created in the previous step and replace the contents of the file with the following code sample:
    
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using Unity.Cloud.Assets;
    using Unity.Cloud.Common;
    using UnityEngine;
    
    public class UseCaseFileCreationExampleUI : IAssetManagementUI
    {
        readonly AssetManagementBehaviour m_Behaviour;
    
        public UseCaseFileCreationExampleUI(AssetManagementBehaviour behaviour)
        {
            m_Behaviour = behaviour;
        }
    
        public void OnGUI() { }
    }
    
    
    1. In the same script, replace the OnGUI function with the following code:
    
            static readonly GUILayoutOption k_DefaultButtonSize = GUILayout.Width(60);
    
            IAsset m_CurrentAsset;
            Vector2 m_DatasetsScrollPosition;
            Dictionary<DatasetId, bool> m_Expanded = new();
    
            static readonly string[] m_OverrideActions = {"None", "Replace", "Reupload"};
            int m_OverrideFileActionIndex;
    
            public void OnGUI()
            {
                if (!m_Behaviour.IsProjectSelected) return;
    
                if (m_CurrentAsset != m_Behaviour.CurrentAsset)
                {
                    m_CurrentAsset = m_Behaviour.CurrentAsset;
                    _ = m_Behaviour.GetDatasets();
                }
    
                if (m_CurrentAsset == null)
                {
                    GUILayout.Label(" ! No asset selected !");
                    return;
                }
    
                GUILayout.BeginVertical();
    
                if (GUILayout.Button("Refresh", k_DefaultButtonSize))
                {
                    _ = m_Behaviour.GetDatasets();
                }
    
                GUILayout.Space(5);
    
                if (m_Behaviour.Datasets == null)
                {
                    GUILayout.Label("Loading datasets...");
                    GUILayout.EndVertical();
                    return;
                }
    
                DisplayDatasets(m_Behaviour.Datasets?.ToArray());
    
                GUILayout.EndVertical();
            }
    
            void DisplayDatasets(IReadOnlyCollection<IDataset> datasets)
            {
                if (datasets.Count == 0)
                {
                    GUILayout.Label("No datasets.");
                    return;
                }
    
    #if UNITY_EDITOR
                GUILayout.Label("File upload options:");
                m_OverrideFileActionIndex = GUILayout.SelectionGrid(m_OverrideFileActionIndex, m_OverrideActions, 3, GUILayout.Width(240));
    
                GUILayout.Space(10);
    #endif
    
                m_DatasetsScrollPosition = GUILayout.BeginScrollView(m_DatasetsScrollPosition, GUILayout.ExpandHeight(true));
    
                foreach (var dataset in datasets)
                {
                    DisplayDataset(dataset);
    
                    GUILayout.Space(10);
                }
    
                GUILayout.EndScrollView();
            }
    
            void DisplayDataset(IDataset dataset)
            {
                GUILayout.BeginHorizontal();
    
                GUILayout.Label(dataset.Name + " (" + dataset.Status + ")");
    
                GUILayout.Space(5);
    
                TryUploadFolder(dataset);
                TryUploadFile(dataset);
    
                var expanded = m_Expanded.GetValueOrDefault(dataset.Descriptor.DatasetId);
                if (GUILayout.Button(expanded ? "-" : "+", GUILayout.Width(20)))
                {
                    expanded = !expanded;
                    m_Expanded[dataset.Descriptor.DatasetId] = expanded;
    
                    if (!expanded)
                    {
                        m_Behaviour.DatasetFiles.Remove(dataset.Descriptor.DatasetId);
                    }
                }
    
                GUILayout.EndHorizontal();
    
                if (expanded)
                {
                    GUILayout.BeginHorizontal();
    
                    GUILayout.Space(25);
    
                    DisplayFiles(dataset);
    
                    GUILayout.EndHorizontal();
                }
    
                if (m_SelectedFile != null)
                {
                    m_WindowRect = GUILayout.Window(0, m_WindowRect, DisplayWindow, "Select files to link");
                }
            }
    
            void TryUploadFolder(IDataset dataset)
            {
    #if UNITY_EDITOR
                if (GUILayout.Button("Upload folder", GUILayout.Width(90)))
                {
                    var folderPath = UnityEditor.EditorUtility.OpenFolderPanel("Folder to upload", "Assets", string.Empty);
                    if (!string.IsNullOrEmpty(folderPath))
                    {
                        _ = m_Behaviour.UploadFolderAsync(dataset, folderPath, m_OverrideActions[m_OverrideFileActionIndex]);
                    }
                }
    #endif
            }
    
            void TryUploadFile(IDataset dataset)
            {
    #if UNITY_EDITOR
                if (GUILayout.Button("Upload file", GUILayout.Width(90)))
                {
                    var filePath = UnityEditor.EditorUtility.OpenFilePanel("File to upload", "Assets", string.Empty);
                    var folderPath = filePath[..filePath.LastIndexOf(Path.DirectorySeparatorChar)];
                    if (!string.IsNullOrEmpty(filePath))
                    {
                        _ = m_OverrideFileActionIndex switch
                        {
                            1 => m_Behaviour.ReplaceFile(dataset, filePath, folderPath),
                            2 => m_Behaviour.ReuploadFile(dataset, filePath, folderPath),
                            _ => m_Behaviour.UploadFile(dataset, filePath, folderPath)
                        };
                    }
                }
    #endif
            }
    
            void DisplayFiles(IDataset dataset)
            {
                if (!m_Behaviour.DatasetFiles.ContainsKey(dataset.Descriptor.DatasetId))
                {
                    _ = m_Behaviour.GetFilesAsync(dataset.Descriptor.DatasetId);
                }
    
                var files = m_Behaviour.DatasetFiles.GetValueOrDefault(dataset.Descriptor.DatasetId);
    
                if (files == null)
                {
                    GUILayout.Label("Loading files...");
                    return;
                }
    
                var enumerable = files.ToArray();
                if (!enumerable.Any())
                {
                    GUILayout.Label("No files.");
                    return;
                }
    
                GUILayout.BeginVertical();
    
                foreach (var file in enumerable)
                {
                    DisplayFile(dataset, file);
                }
    
                GUILayout.EndVertical();
            }
    
            void DisplayFile(IDataset dataset, IFile file)
            {
                GUILayout.BeginHorizontal();
    
                var size = file.SizeBytes < 1000 ? "<1" : MathF.Round(file.SizeBytes / 1000f).ToString("F0");
                GUILayout.Label($"{file.Descriptor.Path} ({size} KB)");
    
                if (GUILayout.Button("Link to", k_DefaultButtonSize))
                {
                    m_WindowRect = new Rect(Screen.width * 0.4f, Screen.height * 0.4f, Screen.width * 0.2f, Screen.height * 0.2f);
                    m_SelectedFile = file;
                    m_AvailableDatasets = m_Behaviour.Datasets?.Where(f => !m_SelectedFile.LinkedDatasets.Contains(dataset.Descriptor)).ToList();
                }
    
                if (GUILayout.Button("Unlink", k_DefaultButtonSize))
                {
                    _ = m_Behaviour.UnlinkFile(dataset, file);
                }
    
                GUILayout.EndHorizontal();
            }
    
            Rect m_WindowRect;
            IFile m_SelectedFile;
            List<IDataset> m_AvailableDatasets;
    
            void DisplayWindow(int windowId)
            {
                GUILayout.BeginVertical();
    
                GUILayout.Label($"Link {m_SelectedFile.Descriptor.Path} to:");
    
                if (m_AvailableDatasets.Count == 0)
                {
                    GUILayout.Label(" ! No datasets to link to !");
                }
                else
                {
                    for (var i = 0; i < m_AvailableDatasets.Count; ++i)
                    {
                        GUILayout.BeginHorizontal();
    
                        GUILayout.Label(m_AvailableDatasets[i].Name);
    
                        if (GUILayout.Button("Link", k_DefaultButtonSize))
                        {
                            _ = m_Behaviour.LinkFile(m_AvailableDatasets[i], m_SelectedFile);
                            m_AvailableDatasets.RemoveAt(i);
    
                            // Force a refresh of the dataset files, including the already linked ones of the selected one
                            foreach (var linkedDatasetId in m_SelectedFile.LinkedDatasets.Select(d => d.DatasetId))
                            {
                                m_Behaviour.DatasetFiles.Remove(linkedDatasetId);
                                m_Expanded.Remove(linkedDatasetId);
                            }
    
                            m_Behaviour.DatasetFiles.Remove(m_AvailableDatasets[i].Descriptor.DatasetId);
                            m_Expanded.Remove(m_AvailableDatasets[i].Descriptor.DatasetId);
    
                            GUILayout.EndHorizontal();
                            break;
                        }
    
                        GUILayout.EndHorizontal();
                    }
                }
    
                GUILayout.Space(10);
    
                if (GUILayout.Button("Close", k_DefaultButtonSize))
                {
                    m_SelectedFile = null;
                    m_AvailableDatasets = null;
                }
    
                GUILayout.EndVertical();
            }
    
    
    1. Open the AssetManagementUI script you created as described in Get started with Asset SDK and replace the contents of the Awake function 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 UseCaseFileCreationExampleUI(m_Behaviour));
    
    

    The code snippet does the following:

    • Provides a UI button to refresh the list of files within each dataset.
    • Provides UI buttons to trigger the creation of a new file within a dataset.
    • Provides a UI button to link an existing file to a dataset.
    • Provides a UI button for each existing file to unlink it from its dataset.

    Going further

    Update and download files

    See the Download and manage files use case for more information.

    Replace uploaded file content

    See the Replace uploaded file content use case for more information.

    In This Article
    Back to top
    Copyright © 2024 Unity Technologies — Trademarks and terms of use
    • Legal
    • Privacy Policy
    • Cookie Policy
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)