< Summary

Class:NFTShapeLoaderController
Assembly:MainScripts
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/LoadableShapes/NFTShape/NFTShapeLoaderController.cs
Covered lines:58
Uncovered lines:75
Coverable lines:133
Total lines:323
Line coverage:43.6% (58 of 133)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
NFTShapeLoaderController()0%110100%
NFTShapeLoaderController()0%110100%
Awake()0%110100%
Start()0%110100%
Update()0%2.52050%
LoadAsset(...)0%28.0812051.85%
UpdateBackgroundColor(...)0%2.062075%
FetchNFTContents()0%110100%
FetchNFTInfoSuccess(...)0%2100%
FetchNFTInfoFail()0%2100%
PrepareFrame(...)0%2100%
LoadNFTAssetCoroutine()0%20400%
FinishLoading(...)0%20400%
SetFrameImage(...)0%56700%
UpdateTexture(...)0%6200%
ShowLoading(...)0%2.062075%
ShowErrorFeedback(...)0%3.333066.67%
InitializeMaterials()0%20.6414067.65%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/LoadableShapes/NFTShape/NFTShapeLoaderController.cs

#LineLine coverage
 1using DCL.Components;
 2using DCL.Helpers.NFT;
 3using System.Collections;
 4using System.Collections.Generic;
 5using System.IO;
 6using System.Text.RegularExpressions;
 7using UnityEngine;
 8using DCL;
 9using Newtonsoft.Json;
 10using NFTShape_Internal;
 11using UnityGLTF.Loader;
 12
 13public class NFTShapeLoaderController : MonoBehaviour
 14{
 15    internal const string COULD_NOT_FETCH_DAR_URL = "Couldn't fetch DAR url '{0}' for NFTShape.";
 16    internal const string ACCEPTED_URL_FORMAT = "The accepted format is 'ethereum://ContractAddress/TokenID'.";
 17    internal const string SUPPORTED_PROTOCOL = "The only protocol currently supported is 'ethereum'.";
 18    internal const string DOES_NOT_SUPPORT_POLYGON = "Warning: OpenSea API does not support fetching Polygon assets.";
 19    internal const string COULD_NOT_FETCH_NFT_FROM_API = "Couldn't fetch NFT: '{0}/{1}'.";
 20    internal const string COULD_NOT_FETCH_NFT_IMAGE = "Couldn't fetch NFT image for: '{0}/{1}': {2}.";
 21
 22    public enum NoiseType
 23    {
 24        ClassicPerlin,
 25        PeriodicPerlin,
 26        Simplex,
 27        SimplexNumericalGrad,
 28        SimplexAnalyticalGrad,
 29        None
 30    }
 31
 32    public NFTShapeConfig config;
 33    public MeshRenderer meshRenderer;
 34    public new BoxCollider collider;
 35    public Color backgroundColor;
 36    public GameObject spinner;
 37    public GameObject errorFeedback;
 38
 39    [HideInInspector] public bool alreadyLoadedAsset = false;
 40    [HideInInspector] public INFTInfoLoadHelper nftInfoLoadHelper;
 41    internal INFTAssetLoadHelper nftAssetLoadHelper;
 42    private NFTShapeHQImageHandler hqTextureHandler = null;
 43    private Coroutine loadNftAssetCoroutine;
 44
 45    public event System.Action OnLoadingAssetSuccess;
 46    public event System.Action OnLoadingAssetFail;
 47
 48    [SerializeField]
 49    NFTShapeMaterial[] materials;
 50
 51    [Header("Noise Shader")]
 52    [SerializeField]
 3053    NoiseType noiseType = NoiseType.Simplex;
 54
 55    [SerializeField] bool noiseIs3D = false;
 56    [SerializeField] bool noiseIsFractal = false;
 57
 58    System.Action<LoadWrapper> OnSuccess;
 59    System.Action<LoadWrapper> OnFail;
 60    private string darURLProtocol;
 61    private string darURLRegistry;
 62    private string darURLAsset;
 63
 064    public Material frameMaterial { private set; get; } = null;
 065    public Material imageMaterial { private set; get; } = null;
 066    public Material backgroundMaterial { private set; get; } = null;
 67
 168    static readonly int BASEMAP_SHADER_PROPERTY = Shader.PropertyToID("_BaseMap");
 169    static readonly int COLOR_SHADER_PROPERTY = Shader.PropertyToID("_BaseColor");
 70
 71
 72    bool isDestroyed = false;
 73
 74
 75    void Awake()
 76    {
 77        // NOTE: we use half scale to keep backward compatibility cause we are using 512px to normalize the scale with a
 778        meshRenderer.transform.localScale = new Vector3(0.5f, 0.5f, 1);
 79
 780        InitializeMaterials();
 781        nftInfoLoadHelper = new NFTInfoLoadHelper();
 782        nftAssetLoadHelper = new NFTAssetLoadHelper();
 783    }
 84
 485    private void Start() { spinner.layer = LayerMask.NameToLayer("ViewportCullingIgnored"); }
 86
 387    void Update() { hqTextureHandler?.Update(); }
 88
 89
 90    public void LoadAsset(string url, bool loadEvenIfAlreadyLoaded = false)
 91    {
 392        if (string.IsNullOrEmpty(url) || (!loadEvenIfAlreadyLoaded && alreadyLoadedAsset))
 093            return;
 94
 395        ShowErrorFeedback(false);
 396        UpdateBackgroundColor(backgroundColor);
 97
 98        // Check the src follows the needed format e.g.: 'ethereum://0x06012c8cf97BEaD5deAe237070F9587f8E7A266d/558536'
 399        var regexMatches = Regex.Matches(url, "(?<protocol>[^:]+)://(?<registry>0x([A-Fa-f0-9])+)(?:/(?<asset>.+))?");
 3100        if (regexMatches.Count == 0)
 101        {
 0102            Debug.LogError(string.Format(COULD_NOT_FETCH_DAR_URL + " " + ACCEPTED_URL_FORMAT, url));
 0103            ShowErrorFeedback(true);
 0104            OnLoadingAssetFail?.Invoke();
 105
 0106            return;
 107        }
 108
 3109        Match match = regexMatches[0];
 3110        if (match.Groups["protocol"] == null || match.Groups["registry"] == null || match.Groups["asset"] == null)
 111        {
 0112            Debug.LogError(string.Format(COULD_NOT_FETCH_DAR_URL + " " + ACCEPTED_URL_FORMAT, url));
 0113            ShowErrorFeedback(true);
 0114            OnLoadingAssetFail?.Invoke();
 115
 0116            return;
 117        }
 118
 3119        darURLProtocol = match.Groups["protocol"].ToString();
 3120        if (darURLProtocol != "ethereum")
 121        {
 0122            Debug.LogError(string.Format(COULD_NOT_FETCH_DAR_URL + " " + SUPPORTED_PROTOCOL + " " + ACCEPTED_URL_FORMAT,
 0123            ShowErrorFeedback(true);
 0124            OnLoadingAssetFail?.Invoke();
 125
 0126            return;
 127        }
 128
 3129        darURLRegistry = match.Groups["registry"].ToString();
 3130        darURLAsset = match.Groups["asset"].ToString();
 131
 3132        alreadyLoadedAsset = false;
 133
 3134        FetchNFTContents();
 3135    }
 136
 137    public void UpdateBackgroundColor(Color newColor)
 138    {
 6139        if (backgroundMaterial == null)
 0140            return;
 141
 6142        backgroundMaterial.SetColor(COLOR_SHADER_PROPERTY, newColor);
 6143    }
 144
 145    private void FetchNFTContents()
 146    {
 3147        ShowLoading(true);
 3148        nftInfoLoadHelper.FetchNFTInfo(darURLRegistry, darURLAsset, FetchNFTInfoSuccess, FetchNFTInfoFail);
 3149    }
 150
 151    private void FetchNFTInfoSuccess(NFTInfo nftInfo)
 152    {
 0153        loadNftAssetCoroutine = StartCoroutine(LoadNFTAssetCoroutine(nftInfo));
 0154    }
 155
 156    private void FetchNFTInfoFail()
 157    {
 0158        ShowErrorFeedback(true);
 0159        FinishLoading(false);
 0160    }
 161
 162    private void PrepareFrame(INFTAsset nftAsset, string nftName, string nftImageUrl)
 163    {
 0164        SetFrameImage(nftAsset.previewAsset.texture, resizeFrameMesh: true);
 165
 0166        var hqImageHandlerConfig = new NFTShapeHQImageConfig()
 167        {
 168            controller = this,
 169            nftShapeConfig = config,
 170            name = nftName,
 171            imageUrl = nftImageUrl,
 172            asset = nftAsset
 173        };
 174
 0175        hqTextureHandler = NFTShapeHQImageHandler.Create(hqImageHandlerConfig);
 0176        nftAsset.OnTextureUpdate += UpdateTexture;
 0177    }
 178
 179    internal IEnumerator LoadNFTAssetCoroutine(NFTInfo nftInfo)
 180    {
 0181        yield return new DCL.WaitUntil(() => (CommonScriptableObjects.playerUnityPosition - transform.position).sqrMagni
 182
 183        // We download the "preview" 256px image
 0184        yield return nftAssetLoadHelper.LoadNFTAsset(
 185            nftInfo.previewImageUrl,
 186            (result) =>
 187            {
 0188                PrepareFrame(result, nftInfo.name, nftInfo.imageUrl);
 0189                FinishLoading(true);
 0190            },
 191            (exc) =>
 192            {
 0193                Debug.LogError(string.Format(COULD_NOT_FETCH_NFT_IMAGE, darURLRegistry, darURLAsset,
 194                    nftInfo.previewImageUrl));
 195
 0196                ShowErrorFeedback(true);
 0197                OnLoadingAssetFail?.Invoke();
 0198                FinishLoading(false);
 0199            });
 0200    }
 201
 202    void FinishLoading(bool loadedSuccessfully)
 203    {
 0204        if (loadedSuccessfully)
 205        {
 0206            ShowLoading(false);
 0207            OnLoadingAssetSuccess?.Invoke();
 0208        }
 209        else
 210        {
 0211            OnLoadingAssetFail?.Invoke();
 212        }
 0213    }
 214
 215    void SetFrameImage(Texture2D texture, bool resizeFrameMesh = false)
 216    {
 0217        if (texture == null)
 0218            return;
 219
 0220        UpdateTexture(texture);
 221
 0222        if (resizeFrameMesh && !isDestroyed && meshRenderer != null)
 223        {
 224            float w, h;
 0225            w = h = 0.5f;
 0226            if (texture.width > texture.height)
 0227                h *= texture.height / (float) texture.width;
 0228            else if (texture.width < texture.height)
 0229                w *= texture.width / (float) texture.height;
 0230            Vector3 newScale = new Vector3(w, h, 1f);
 231
 0232            meshRenderer.transform.localScale = newScale;
 233        }
 0234    }
 235
 236    public void UpdateTexture(Texture2D texture)
 237    {
 0238        if (imageMaterial == null)
 0239            return;
 240
 0241        imageMaterial.SetTexture(BASEMAP_SHADER_PROPERTY, texture);
 0242        imageMaterial.SetColor(COLOR_SHADER_PROPERTY, Color.white);
 0243    }
 244
 245    private void ShowLoading(bool isVisible)
 246    {
 3247        if (spinner == null)
 0248            return;
 249
 3250        spinner.SetActive(isVisible);
 3251    }
 252
 253    private void ShowErrorFeedback(bool isVisible)
 254    {
 3255        if (errorFeedback == null)
 0256            return;
 257
 3258        if (isVisible)
 0259            ShowLoading(false);
 260
 3261        errorFeedback.SetActive(isVisible);
 3262    }
 263
 264    void InitializeMaterials()
 265    {
 7266        Material[] meshMaterials = new Material[materials.Length];
 56267        for (int i = 0; i < materials.Length; i++)
 268        {
 21269            switch (materials[i].type)
 270            {
 271                case NFTShapeMaterial.MaterialType.BACKGROUND:
 7272                    backgroundMaterial = new Material(materials[i].material);
 7273                    meshMaterials[i] = backgroundMaterial;
 7274                    break;
 275                case NFTShapeMaterial.MaterialType.FRAME:
 7276                    frameMaterial = materials[i].material;
 7277                    meshMaterials[i] = frameMaterial;
 7278                    break;
 279                case NFTShapeMaterial.MaterialType.IMAGE:
 7280                    imageMaterial = new Material(materials[i].material);
 7281                    meshMaterials[i] = imageMaterial;
 282                    break;
 283            }
 284        }
 285
 286
 7287        meshRenderer.materials = meshMaterials;
 288
 7289        if (frameMaterial == null)
 0290            return;
 291
 7292        frameMaterial.shaderKeywords = null;
 293
 7294        if (noiseType == NoiseType.None)
 0295            return;
 296
 7297        switch (noiseType)
 298        {
 299            case NoiseType.ClassicPerlin:
 0300                frameMaterial.EnableKeyword("CNOISE");
 0301                break;
 302            case NoiseType.PeriodicPerlin:
 0303                frameMaterial.EnableKeyword("PNOISE");
 0304                break;
 305            case NoiseType.Simplex:
 7306                frameMaterial.EnableKeyword("SNOISE");
 7307                break;
 308            case NoiseType.SimplexNumericalGrad:
 0309                frameMaterial.EnableKeyword("SNOISE_NGRAD");
 0310                break;
 311            default: // SimplexAnalyticalGrad
 0312                frameMaterial.EnableKeyword("SNOISE_AGRAD");
 313                break;
 314        }
 315
 7316        if (noiseIs3D)
 0317            frameMaterial.EnableKeyword("THREED");
 318
 7319        if (noiseIsFractal)
 0320            frameMaterial.EnableKeyword("FRACTAL");
 7321    }
 322
 323}