< 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:93
Coverable lines:151
Total lines:341
Line coverage:38.4% (58 of 151)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
NFTShapeLoaderController()0%110100%
Awake()0%550100%
Update()0%2.52050%
LoadAsset(...)0%23.8412056.52%
UpdateBackgroundColor(...)0%2.062075%
FetchNFTImage()0%80.613026.32%
FinishLoading(...)0%30500%
SetFrameImage(...)0%56700%
UpdateTexture(...)0%6200%
InitializePerlinNoise()0%26.6410045%
OnDestroy()0%8.36060%
SetupGifPlayer(...)0%6200%

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.Text.RegularExpressions;
 5using UnityEngine;
 6using DCL;
 7using NFTShape_Internal;
 8
 9public class NFTShapeLoaderController : MonoBehaviour
 10{
 11    public enum NoiseType
 12    {
 13        ClassicPerlin,
 14        PeriodicPerlin,
 15        Simplex,
 16        SimplexNumericalGrad,
 17        SimplexAnalyticalGrad,
 18        None
 19    }
 20
 21    public NFTShapeConfig config;
 22    public MeshRenderer meshRenderer;
 23    public new BoxCollider collider;
 24    public Color backgroundColor;
 25    public GameObject spinner;
 26
 27    [HideInInspector] public bool alreadyLoadedAsset = false;
 28
 29    public event System.Action OnLoadingAssetSuccess;
 30    public event System.Action OnLoadingAssetFail;
 31
 32    [SerializeField]
 33    NFTShapeMaterial[] materials;
 34
 35    [Header("Noise Shader")]
 36    [SerializeField]
 2937    NoiseType noiseType = NoiseType.Simplex;
 38
 39    [SerializeField] bool noiseIs3D = false;
 40    [SerializeField] bool noiseIsFractal = false;
 41
 42    System.Action<LoadWrapper> OnSuccess;
 43    System.Action<LoadWrapper> OnFail;
 44    string darURLProtocol;
 45    string darURLRegistry;
 46    string darURLAsset;
 47
 048    public Material frameMaterial { private set; get; } = null;
 049    public Material imageMaterial { private set; get; } = null;
 050    public Material backgroundMaterial { private set; get; } = null;
 51
 2952    int BASEMAP_SHADER_PROPERTY = Shader.PropertyToID("_BaseMap");
 2953    int COLOR_SHADER_PROPERTY = Shader.PropertyToID("_BaseColor");
 54
 55    IPromiseLike_TextureAsset assetPromise = null;
 56    GifPlayer gifPlayer = null;
 57    NFTShapeHQImageHandler hqTextureHandler = null;
 58
 59    bool isDestroyed = false;
 60
 61    void Awake()
 62    {
 663        Material[] meshMaterials = new Material[materials.Length];
 4864        for (int i = 0; i < materials.Length; i++)
 65        {
 1866            switch (materials[i].type)
 67            {
 68                case NFTShapeMaterial.MaterialType.BACKGROUND:
 669                    backgroundMaterial = new Material(materials[i].material);
 670                    meshMaterials[i] = backgroundMaterial;
 671                    break;
 72                case NFTShapeMaterial.MaterialType.FRAME:
 673                    frameMaterial = materials[i].material;
 674                    meshMaterials[i] = frameMaterial;
 675                    break;
 76                case NFTShapeMaterial.MaterialType.IMAGE:
 677                    imageMaterial = new Material(materials[i].material);
 678                    meshMaterials[i] = imageMaterial;
 79                    break;
 80            }
 81        }
 682        meshRenderer.materials = meshMaterials;
 83
 84        // NOTE: we use half scale to keep backward compatibility cause we are using 512px to normalize the scale with a
 685        meshRenderer.transform.localScale = new Vector3(0.5f, 0.5f, 1);
 86
 687        InitializePerlinNoise();
 688    }
 89
 290    void Update() { hqTextureHandler?.Update(); }
 91
 92    public void LoadAsset(string url, bool loadEvenIfAlreadyLoaded = false)
 93    {
 294        if (string.IsNullOrEmpty(url) || (!loadEvenIfAlreadyLoaded && alreadyLoadedAsset))
 095            return;
 96
 297        UpdateBackgroundColor(backgroundColor);
 98
 99        // Check the src follows the needed format e.g.: 'ethereum://0x06012c8cf97BEaD5deAe237070F9587f8E7A266d/558536'
 2100        var regexMatches = Regex.Matches(url, "(?<protocol>[^:]+)://(?<registry>0x([A-Fa-f0-9])+)(?:/(?<asset>.+))?");
 2101        if (regexMatches.Count == 0)
 102        {
 0103            Debug.LogError($"Couldn't fetch DAR url '{url}' for NFTShape. The accepted format is 'ethereum://ContractAdd
 104
 0105            OnLoadingAssetFail?.Invoke();
 106
 0107            return;
 108        }
 109
 2110        Match match = regexMatches[0];
 2111        if (match.Groups["protocol"] == null || match.Groups["registry"] == null || match.Groups["asset"] == null)
 112        {
 0113            Debug.LogError($"Couldn't fetch DAR url '{url}' for NFTShape.");
 114
 0115            OnLoadingAssetFail?.Invoke();
 116
 0117            return;
 118        }
 119
 2120        darURLProtocol = match.Groups["protocol"].ToString();
 2121        if (darURLProtocol != "ethereum")
 122        {
 0123            Debug.LogError($"Couldn't fetch DAR url '{url}' for NFTShape. The only protocol currently supported is 'ethe
 124
 0125            OnLoadingAssetFail?.Invoke();
 126
 0127            return;
 128        }
 129
 2130        darURLRegistry = match.Groups["registry"].ToString();
 2131        darURLAsset = match.Groups["asset"].ToString();
 132
 2133        alreadyLoadedAsset = false;
 134
 2135        StartCoroutine(FetchNFTImage());
 2136    }
 137
 138    public void UpdateBackgroundColor(Color newColor)
 139    {
 4140        if (backgroundMaterial == null)
 0141            return;
 142
 4143        backgroundMaterial.SetColor(COLOR_SHADER_PROPERTY, newColor);
 4144    }
 145
 146    IEnumerator FetchNFTImage()
 147    {
 2148        if (spinner != null)
 2149            spinner.SetActive(true);
 150
 2151        NFTInfo nftInfo = new NFTInfo();
 152
 2153        bool isError = false;
 154
 2155        yield return NFTHelper.FetchNFTInfo(darURLRegistry, darURLAsset,
 156            (info) =>
 157            {
 0158                nftInfo = info;
 0159            },
 160            (error) =>
 161            {
 0162                Debug.LogError($"Couldn't fetch NFT: '{darURLRegistry}/{darURLAsset}' {error}");
 0163                OnLoadingAssetFail?.Invoke();
 0164                isError = true;
 0165            });
 166
 0167        if (isError)
 0168            yield break;
 169
 0170        yield return new DCL.WaitUntil(() => (CommonScriptableObjects.playerUnityPosition - transform.position).sqrMagni
 171
 172        // We download the "preview" 256px image
 0173        bool foundDCLImage = false;
 0174        if (!string.IsNullOrEmpty(nftInfo.previewImageUrl))
 175        {
 0176            yield return WrappedTextureUtils.Fetch(nftInfo.previewImageUrl, (promise) =>
 177            {
 0178                foundDCLImage = true;
 0179                this.assetPromise = promise;
 0180                SetFrameImage(promise.asset, resizeFrameMesh: true);
 0181                SetupGifPlayer(promise.asset);
 182
 0183                var hqImageHandlerConfig = new NFTShapeHQImageConfig()
 184                {
 185                    controller = this,
 186                    nftConfig = config,
 187                    nftInfo = nftInfo,
 188                    asset = NFTAssetFactory.CreateAsset(promise.asset, config, UpdateTexture, gifPlayer)
 189                };
 0190                hqTextureHandler = NFTShapeHQImageHandler.Create(hqImageHandlerConfig);
 0191            });
 192        }
 193
 194        //We fall back to the nft original image which can have a really big size
 0195        if (!foundDCLImage && !string.IsNullOrEmpty(nftInfo.originalImageUrl))
 196        {
 0197            yield return WrappedTextureUtils.Fetch(nftInfo.originalImageUrl,
 198                (promise) =>
 199                {
 0200                    foundDCLImage = true;
 0201                    this.assetPromise = promise;
 0202                    SetFrameImage(promise.asset, resizeFrameMesh: true);
 0203                    SetupGifPlayer(promise.asset);
 0204                }, () => isError = true);
 205        }
 206
 0207        if (isError)
 208        {
 0209            Debug.LogError($"Couldn't fetch NFT image for: '{darURLRegistry}/{darURLAsset}' {nftInfo.originalImageUrl}")
 0210            OnLoadingAssetFail?.Invoke();
 0211            yield break;
 212        }
 213
 0214        FinishLoading(foundDCLImage);
 0215    }
 216
 217    void FinishLoading(bool loadedSuccessfully)
 218    {
 0219        if (loadedSuccessfully)
 220        {
 0221            if (spinner != null)
 0222                spinner.SetActive(false);
 223
 0224            OnLoadingAssetSuccess?.Invoke();
 0225        }
 226        else
 227        {
 0228            OnLoadingAssetFail?.Invoke();
 229        }
 0230    }
 231
 232    void SetFrameImage(ITexture newAsset, bool resizeFrameMesh = false)
 233    {
 0234        if (newAsset == null)
 0235            return;
 236
 0237        UpdateTexture(newAsset.texture);
 238
 0239        if (resizeFrameMesh && !isDestroyed && meshRenderer != null)
 240        {
 241            float w, h;
 0242            w = h = 0.5f;
 0243            if (newAsset.width > newAsset.height)
 0244                h *= newAsset.height / (float)newAsset.width;
 0245            else if (newAsset.width < newAsset.height)
 0246                w *= newAsset.width / (float)newAsset.height;
 0247            Vector3 newScale = new Vector3(w, h, 1f);
 248
 0249            meshRenderer.transform.localScale = newScale;
 250        }
 0251    }
 252
 253    public void UpdateTexture(Texture2D texture)
 254    {
 0255        if (imageMaterial == null)
 0256            return;
 257
 0258        imageMaterial.SetTexture(BASEMAP_SHADER_PROPERTY, texture);
 0259        imageMaterial.SetColor(COLOR_SHADER_PROPERTY, Color.white);
 0260    }
 261
 262    void InitializePerlinNoise()
 263    {
 6264        if (frameMaterial == null)
 0265            return;
 266
 6267        frameMaterial.shaderKeywords = null;
 268
 6269        if (noiseType == NoiseType.None)
 0270            return;
 271
 6272        switch (noiseType)
 273        {
 274            case NoiseType.ClassicPerlin:
 0275                frameMaterial.EnableKeyword("CNOISE");
 0276                break;
 277            case NoiseType.PeriodicPerlin:
 0278                frameMaterial.EnableKeyword("PNOISE");
 0279                break;
 280            case NoiseType.Simplex:
 6281                frameMaterial.EnableKeyword("SNOISE");
 6282                break;
 283            case NoiseType.SimplexNumericalGrad:
 0284                frameMaterial.EnableKeyword("SNOISE_NGRAD");
 0285                break;
 286            default: // SimplexAnalyticalGrad
 0287                frameMaterial.EnableKeyword("SNOISE_AGRAD");
 288                break;
 289        }
 290
 6291        if (noiseIs3D)
 0292            frameMaterial.EnableKeyword("THREED");
 293
 6294        if (noiseIsFractal)
 0295            frameMaterial.EnableKeyword("FRACTAL");
 6296    }
 297
 298    void OnDestroy()
 299    {
 6300        isDestroyed = true;
 301
 6302        if (hqTextureHandler != null)
 303        {
 0304            hqTextureHandler.Dispose();
 0305            hqTextureHandler = null;
 306        }
 307
 6308        if (gifPlayer != null)
 309        {
 0310            gifPlayer.OnFrameTextureChanged -= UpdateTexture;
 0311            gifPlayer.Dispose();
 312        }
 313
 6314        if (assetPromise != null)
 315        {
 0316            assetPromise.Forget();
 0317            assetPromise = null;
 318        }
 319
 6320        if (backgroundMaterial != null)
 321        {
 6322            Object.Destroy(backgroundMaterial);
 323        }
 6324        if (imageMaterial != null)
 325        {
 6326            Object.Destroy(imageMaterial);
 327        }
 6328    }
 329
 330    private void SetupGifPlayer(ITexture asset)
 331    {
 0332        if (!(asset is Asset_Gif gifAsset))
 333        {
 0334            return;
 335        }
 336
 0337        gifPlayer = new GifPlayer(gifAsset);
 0338        gifPlayer.Play();
 0339        gifPlayer.OnFrameTextureChanged += UpdateTexture;
 0340    }
 341}