Editor Window

Editor Window - AppSetupWindow.cs

AppSetupWindow extends EditorWindow class and provides all algorithms necessary to display metaproSDK setup editor window and manage its operations.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Grpc.Core;
using MetaPod;
using metaproSDK.Scripts.Serialization;
using Newtonsoft.Json;
using Unity.EditorCoroutines.Editor;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UIElements;

public class AppSetupWindow : EditorWindow
{
    private bool _hasKeyAssigned;
    private TemplateContainer baseContainer;
    private StyleSheet baseStyleSheet;
    private TemplateContainer importedContainer;
    private StyleSheet importedStyleSheet;

    private static string PROD_URL = "";

    private string _requestURL = PROD_URL;
    
    private MetaproAppSetup _metaproAppSetup;
    
    [MenuItem("Tools/Metapro SDK Setup")]
    public static void ShowWindow()
    {
        var window = GetWindow<AppSetupWindow>();
        window.titleContent = new GUIContent("Metapro SDK");
        window.minSize = new Vector2(400, 600);
        window.maxSize = new Vector2(400, 600);
    }

    private void OnEnable()
    {
        var editorAssetsPath = "Assets/Augmented Life Studio LLC/metapro for Unity/Editor";
        VisualTreeAsset baseAssetTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(editorAssetsPath + "/AppSetupTemplate.uxml");
        baseContainer = baseAssetTree.CloneTree();
        baseStyleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>(editorAssetsPath + "/AppSetupStyles.uss");

        VisualTreeAsset importedAssetTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(editorAssetsPath + "/AppSetupImported.uxml");
        importedContainer = importedAssetTree.CloneTree();
        importedStyleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>(editorAssetsPath + "/AppSetupImportedStyles.uss");
        
        var guid = AssetDatabase.FindAssets("t:MetaproAppSetup");
        var setups = new MetaproAppSetup[guid.Length];
        for (int i = 0; i < setups.Length; i++)
        {
            var path = AssetDatabase.GUIDToAssetPath(guid[i]);
            setups[i] = AssetDatabase.LoadAssetAtPath<MetaproAppSetup>(path);
        }

        _metaproAppSetup = setups[0];
        
        CheckData();
        UpdateVisuals();
    }

    private void CheckData()
    {
        EditorUtility.SetDirty(_metaproAppSetup); 
        AssetDatabase.SaveAssets();
        if (_metaproAppSetup.GameKey != "")
        {
            _hasKeyAssigned = true;
        }
        else
        {
            _hasKeyAssigned = false;
        }
    }

    public void UpdateVisuals()
    {
        if (_hasKeyAssigned)
        {
            EditorCoroutineUtility.StartCoroutine(ShowItemsView(), this);
        }
        else
        {
            EditorCoroutineUtility.StartCoroutine(ShowBaseView(), this);
        }
    }
    
    private IEnumerator ShowBaseView()
    {
        importedContainer.RemoveFromHierarchy();
        rootVisualElement.Add(baseContainer);
        rootVisualElement.styleSheets.Add(baseStyleSheet);

        yield return new WaitForSeconds(1f);
        var textField = rootVisualElement.Query<TextField>("styled_input").First();
        textField.value = "Enter app key";
        
        var setupButton = rootVisualElement.Query<Button>("button").First();
        setupButton.clicked -= SetupButtonOnclicked;
        setupButton.clicked += SetupButtonOnclicked;
        
        var pasteButton = rootVisualElement.Query<Button>("paste_input").First();
        pasteButton.clicked -= PasteButtonOnClicked;
        pasteButton.clicked += PasteButtonOnClicked;
        
    }

    private IEnumerator ShowItemsView()
    {
        baseContainer.RemoveFromHierarchy();
        
        rootVisualElement.Add(importedContainer);
        rootVisualElement.styleSheets.Add(importedStyleSheet);

        yield return new WaitForSeconds(1f);
        
        var appName = rootVisualElement.Query<Label>("app_name").First();
        appName.text = _metaproAppSetup.GameName;
        
        var teamName = rootVisualElement.Query<Label>("team_name").First();
        teamName.text = _metaproAppSetup.TeamName;
        
        var appImage = rootVisualElement.Query<Image>("app_image").First();
        
        EditorCoroutineUtility.StartCoroutine(GetTexture(_metaproAppSetup.GameImageURL, appImage), this);

        var listView = rootVisualElement.Query<ScrollView>("test_view").First();
        
        var changeKeyButton = rootVisualElement.Query<Button>("change_app").First();
        changeKeyButton.clicked -= ClearImportedView;
        changeKeyButton.clicked += ClearImportedView;
        
        
        var downloadAllButton = rootVisualElement.Query<Button>("download_all_button").First();
        downloadAllButton.clicked -= DownloadAllItems;
        downloadAllButton.clicked += DownloadAllItems;

        foreach (var gameAsset in _metaproAppSetup.GameAssets)
        {
            
            Box itemBox = new Box();
            itemBox.AddToClassList("item_element");

            Image itemImage = new Image();
            itemImage.AddToClassList("item_image");
            EditorCoroutineUtility.StartCoroutine(GetTexture(gameAsset.ImageURL, itemImage), this);
            Label itemName = new Label();
            itemName.AddToClassList("item_name");
            itemName.text = gameAsset.Name;
            Button itemButton = new Button();
            itemButton.AddToClassList("item_button");
            itemButton.text = "Download";
            itemButton.clicked += () =>
            {
                DownloadFile(gameAsset.BucketHash, gameAsset.TokenId, gameAsset.ItemId);
            };
            itemBox.Add(itemImage);
            itemBox.Add(itemName);
            itemBox.Add(itemButton);
            listView.Add(itemBox);
        }
    }

    private IEnumerator GetTexture(string url, Image imageToAssign)
    {
        UnityWebRequest www = UnityWebRequestTexture.GetTexture(url);
        yield return www.SendWebRequest();

        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.Log(www.error);
            Debug.Log(www.downloadHandler.error);
            imageToAssign.visible = false;
            imageToAssign.SetEnabled(false);
            EditorCoroutineUtility.StartCoroutine(GetGifData(url, imageToAssign), this);
        }
        else
        {
            imageToAssign.SetEnabled(true);
            imageToAssign.visible = true;
            Texture texture = ((DownloadHandlerTexture)www.downloadHandler).texture;
            imageToAssign.image = texture;
        }
    }
    
    private IEnumerator GetGifData(string url, Image imageToAssign)
    {
        UnityWebRequest www = UnityWebRequest.Get(url);
        yield return www.SendWebRequest();
        Debug.Log("Downloading preview GIF for image: " + url);
        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.Log(www.error);
            Debug.Log(www.downloadHandler.error);
        }
        else
        { 
            Debug.Log("Downloaded GIF texture");
            var fileId = url.Split('/')[3];
            var relativePath = "Assets/Resources/downloadedGif_" + fileId + ".gif";
            ByteArrayToFile(relativePath, www.downloadHandler.data);
            AssetDatabase.ImportAsset(relativePath);
            AssetDatabase.Refresh();
            TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(relativePath);
 
            importer.isReadable = true;
            importer.textureType = TextureImporterType.Sprite;
            
            TextureImporterSettings importerSettings = new TextureImporterSettings();
            importer.ReadTextureSettings(importerSettings);
            importerSettings.textureType = TextureImporterType.Sprite;
            importerSettings.spriteExtrude = 0;
            importerSettings.spriteGenerateFallbackPhysicsShape = false;
            importerSettings.spriteMeshType = SpriteMeshType.FullRect;
            importerSettings.spriteMode = (int)SpriteImportMode.Single;
            importer.SetTextureSettings(importerSettings);
            importer.spriteImportMode = SpriteImportMode.Single;
            importer.maxTextureSize = 1024;
            importer.alphaIsTransparency = true;
            importer.textureCompression = TextureImporterCompression.Uncompressed;
            importer.alphaSource = TextureImporterAlphaSource.FromInput;
            EditorUtility.SetDirty(importer);
            
            importer.SaveAndReimport();
            Sprite spriteImage = (Sprite)AssetDatabase.LoadAssetAtPath(relativePath, typeof(Sprite));
            imageToAssign.image = spriteImage.texture;
            imageToAssign.SetEnabled(true);
            imageToAssign.visible = true;
        }
    }

    private void DownloadAllItems()
    {
        foreach (var gameAsset in _metaproAppSetup.GameAssets)
        {
            DownloadFile(gameAsset.BucketHash, gameAsset.TokenId, gameAsset.ItemId);
        }
    }

    private void ClearImportedView()
    {
        var listView = rootVisualElement.Query<ScrollView>("test_view").First();
        _metaproAppSetup.GameKey = "";
        _metaproAppSetup.AppId = "";
        _metaproAppSetup.GameName = "";
        _metaproAppSetup.GameImageURL = "";
        _metaproAppSetup.TeamName = "";
        _metaproAppSetup.GameAssets = new List<AvailableAsset>();
        listView.contentContainer.Clear();
        CheckData();
        UpdateVisuals();
        
    }


    private void PasteButtonOnClicked()
    {
        TextEditor textEditor = new TextEditor();
        textEditor.Paste();
        var textField = rootVisualElement.Query<TextField>("styled_input").First();
        textField.value = textEditor.text;
    }
    private void SetupButtonOnclicked()
    {
        EditorCoroutineUtility.StartCoroutine(GetAppData(), this);
    }

    private string DownloadFile(string bucketHash, int tokenId, string itemId)
    {
        var channel = new Channel("prd-pod-1.metaprotocol.one:8181", ChannelCredentials.Insecure);

        var client = new Storage.StorageClient(channel);
        
        var bucketResponse = client.GetBucket(new GetBucketRequest { BucketIdentifier = bucketHash });
       
        var fileURI = "";
        foreach (var bucketResponseFile in bucketResponse.Files)
        {
            var fileResponse = client.GetFile(new GetFileRequest { FileIdentifier = bucketResponseFile });
            
            var fileBytes = Array.Empty<byte>();
            SortedDictionary<ulong, byte[]> fileChunksDictionary = new SortedDictionary<ulong, byte[]>();
            
            foreach (var fileResponseChunk in fileResponse.Chunks)
            {
                var fileChunkResponse = client.GetChunk(new GetChunkRequest { ChunkIdentifier = fileResponseChunk.ChunkIdentifier });
                fileChunksDictionary.Add(fileChunkResponse.ChunkIndex, fileChunkResponse.Chunk.ToByteArray());
            }
            
            foreach (var (key, value) in fileChunksDictionary)
            {
                fileBytes = CombineBytes(fileBytes, value);
            }

            Directory.CreateDirectory("Assets/Resources/" + tokenId);
            ByteArrayToFile("Assets/Resources/" + tokenId + "/" + fileResponse.FileName, fileBytes);
            Debug.Log("Asset download completed");
            fileURI = "Assets/Resources/" + fileResponse.FileName;
            EditorCoroutineUtility.StartCoroutine(SendDownloadConfirmation(_metaproAppSetup.AppId, bucketHash, tokenId, itemId, bucketResponseFile), this);
            
            AssetDatabase.ImportAsset("Assets/Resources/" + tokenId, ImportAssetOptions.ImportRecursive);
        }

        return fileURI;
    }

    public static byte[] CombineBytes(byte[] first, byte[] second)
    {
        byte[] bytes = new byte[first.Length + second.Length];
        Buffer.BlockCopy(first, 0, bytes, 0, first.Length);
        Buffer.BlockCopy(second, 0, bytes, first.Length, second.Length);
        return bytes;
    }
    
    public bool ByteArrayToFile(string fileName, byte[] byteArray)
    {
        try
        {
            using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
            {
                fs.Write(byteArray, 0, byteArray.Length);
                return true;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception caught in process: {0}", ex);
            return false;
        }
    }

    private IEnumerator SendDownloadConfirmation(
        string appId,
        string bucketHash,
        int tokenId,
        string itemId,
        string fileId)
    {
        WWWForm form = new WWWForm();
        form.AddField("appId", appId);
        form.AddField("_bucketHash", bucketHash);
        form.AddField("_tokenId", tokenId);
        form.AddField("itemId", itemId);
        form.AddField("fileId", fileId);

        using (UnityWebRequest www = UnityWebRequest.Post("https://" + _requestURL + "api.metaproprotocol.com/ms/teams/v1/collect", form))
        {
            yield return www.SendWebRequest();

            if (www.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError(www.error);
                Debug.LogError(www.downloadHandler.text);
            }
            else
            {
                Debug.Log("Form upload complete!");
            }
        }
    }
    
    protected IEnumerator GetAppData()
    {
        var appKey = rootVisualElement.Query<TextField>("styled_input").First();
        var appKeyValue = appKey.value;
        
        using (UnityWebRequest www = UnityWebRequest.Get("https://" + _requestURL + "api.metaproprotocol.com/ms/apps/v1/apps/appkey/" + appKeyValue))
        {
            yield return www.SendWebRequest();
 
            if (www.isNetworkError || www.isHttpError)
            {
                Debug.LogError(www.error);
            }
            else
            {
                _metaproAppSetup.GameKey = appKeyValue;
                
                var appItemsResult = JsonConvert.DeserializeObject<AppItemsResult>(www.downloadHandler.text);

                _metaproAppSetup.AppId = appItemsResult.appId;
                _metaproAppSetup.GameImageURL = appItemsResult.gallery[0];
                _metaproAppSetup.GameName = appItemsResult.name;
                _metaproAppSetup.TeamName = appItemsResult.team;
                
                _metaproAppSetup.GameAssets = new List<AvailableAsset>();
                
                foreach (var itemResult in appItemsResult.items)
                {
                    AvailableAsset asset = new AvailableAsset();
                    asset.Name = itemResult.tokenName;
                    asset.BucketHash = itemResult._bucketHash;
                    asset.ImageURL = itemResult.image;
                    asset.ItemId = itemResult.itemId;
                    asset.TokenId = itemResult._tokenId;
                    _metaproAppSetup.GameAssets.Add(asset);
                }
                
                CheckData();
                UpdateVisuals();
            }
        }
    }
}

Last updated