< Summary

Class:NFTShapeLoaderController
Assembly:MainScripts
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/LoadableShapes/NFTShape/NFTShapeLoaderController.cs
Covered lines:64
Uncovered lines:75
Coverable lines:139
Total lines:326
Line coverage:46% (64 of 139)
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%
OnEnable()0%110100%
OnDisable()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%42600%
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.Text.RegularExpressions;
 5using UnityEngine;
 6using DCL;
 7using NFTShape_Internal;
 8
 9public class NFTShapeLoaderController : MonoBehaviour
 10{
 11    internal const string COULD_NOT_FETCH_DAR_URL = "Couldn't fetch DAR url '{0}' for NFTShape.";
 12    internal const string ACCEPTED_URL_FORMAT = "The accepted format is 'ethereum://ContractAddress/TokenID'.";
 13    internal const string SUPPORTED_PROTOCOL = "The only protocol currently supported is 'ethereum'.";
 14    internal const string DOES_NOT_SUPPORT_POLYGON = "Warning: OpenSea API does not support fetching Polygon assets.";
 15    internal const string COULD_NOT_FETCH_NFT_FROM_API = "Couldn't fetch NFT: '{0}/{1}'.";
 16    internal const string COULD_NOT_FETCH_NFT_IMAGE = "Couldn't fetch NFT image for: '{0}/{1}': {2}.";
 17
 18    public enum NoiseType
 19    {
 20        ClassicPerlin,
 21        PeriodicPerlin,
 22        Simplex,
 23        SimplexNumericalGrad,
 24        SimplexAnalyticalGrad,
 25        None
 26    }
 27
 28    public NFTShapeConfig config;
 29    public MeshRenderer meshRenderer;
 30    public new BoxCollider collider;
 31    public Color backgroundColor;
 32    public GameObject spinner;
 33    public GameObject errorFeedback;
 34
 35    [HideInInspector] public bool alreadyLoadedAsset = false;
 36    private INFTInfoLoadHelper nftInfoLoadHelper;
 37    private INFTAssetLoadHelper nftAssetLoadHelper;
 38    private NFTShapeHQImageHandler hqTextureHandler = null;
 39    private Coroutine loadNftAssetCoroutine;
 40
 41    public event System.Action OnLoadingAssetSuccess;
 42    public event System.Action OnLoadingAssetFail;
 43
 44    [SerializeField]
 45    NFTShapeMaterial[] materials;
 46
 47    [Header("Noise Shader")]
 48    [SerializeField]
 3049    NoiseType noiseType = NoiseType.Simplex;
 50
 51    [SerializeField] bool noiseIs3D = false;
 52    [SerializeField] bool noiseIsFractal = false;
 53
 54    System.Action<LoadWrapper> OnSuccess;
 55    System.Action<LoadWrapper> OnFail;
 56    private string darURLProtocol;
 57    private string darURLRegistry;
 58    private string darURLAsset;
 59
 060    public Material frameMaterial { private set; get; } = null;
 061    public Material imageMaterial { private set; get; } = null;
 062    public Material backgroundMaterial { private set; get; } = null;
 63
 164    static readonly int BASEMAP_SHADER_PROPERTY = Shader.PropertyToID("_BaseMap");
 165    static readonly int COLOR_SHADER_PROPERTY = Shader.PropertyToID("_BaseColor");
 66    void Awake()
 67    {
 68        // NOTE: we use half scale to keep backward compatibility cause we are using 512px to normalize the scale with a
 769        meshRenderer.transform.localScale = new Vector3(0.5f, 0.5f, 1);
 70
 771        InitializeMaterials();
 72
 773        nftInfoLoadHelper = new NFTInfoLoadHelper();
 774        nftAssetLoadHelper = new NFTAssetLoadHelper();
 775    }
 76
 77    private void OnEnable()
 78    {
 779        nftInfoLoadHelper.OnFetchInfoSuccess += FetchNFTInfoSuccess;
 780        nftInfoLoadHelper.OnFetchInfoFail += FetchNFTInfoFail;
 781    }
 82
 83    private void OnDisable()
 84    {
 785        nftInfoLoadHelper.OnFetchInfoSuccess -= FetchNFTInfoSuccess;
 786        nftInfoLoadHelper.OnFetchInfoFail -= FetchNFTInfoFail;
 787    }
 88
 489    private void Start() { spinner.layer = LayerMask.NameToLayer("ViewportCullingIgnored"); }
 90
 391    void Update() { hqTextureHandler?.Update(); }
 92
 93    public void LoadAsset(string url, bool loadEvenIfAlreadyLoaded = false)
 94    {
 395        if (string.IsNullOrEmpty(url) || (!loadEvenIfAlreadyLoaded && alreadyLoadedAsset))
 096            return;
 97
 398        ShowErrorFeedback(false);
 399        UpdateBackgroundColor(backgroundColor);
 100
 101        // Check the src follows the needed format e.g.: 'ethereum://0x06012c8cf97BEaD5deAe237070F9587f8E7A266d/558536'
 3102        var regexMatches = Regex.Matches(url, "(?<protocol>[^:]+)://(?<registry>0x([A-Fa-f0-9])+)(?:/(?<asset>.+))?");
 3103        if (regexMatches.Count == 0)
 104        {
 0105            Debug.LogError(string.Format(COULD_NOT_FETCH_DAR_URL + " " + ACCEPTED_URL_FORMAT, url));
 0106            ShowErrorFeedback(true);
 0107            OnLoadingAssetFail?.Invoke();
 108
 0109            return;
 110        }
 111
 3112        Match match = regexMatches[0];
 3113        if (match.Groups["protocol"] == null || match.Groups["registry"] == null || match.Groups["asset"] == null)
 114        {
 0115            Debug.LogError(string.Format(COULD_NOT_FETCH_DAR_URL + " " + ACCEPTED_URL_FORMAT, url));
 0116            ShowErrorFeedback(true);
 0117            OnLoadingAssetFail?.Invoke();
 118
 0119            return;
 120        }
 121
 3122        darURLProtocol = match.Groups["protocol"].ToString();
 3123        if (darURLProtocol != "ethereum")
 124        {
 0125            Debug.LogError(string.Format(COULD_NOT_FETCH_DAR_URL + " " + SUPPORTED_PROTOCOL + " " + ACCEPTED_URL_FORMAT,
 0126            ShowErrorFeedback(true);
 0127            OnLoadingAssetFail?.Invoke();
 128
 0129            return;
 130        }
 131
 3132        darURLRegistry = match.Groups["registry"].ToString();
 3133        darURLAsset = match.Groups["asset"].ToString();
 134
 3135        alreadyLoadedAsset = false;
 136
 3137        FetchNFTContents();
 3138    }
 139
 140    public void UpdateBackgroundColor(Color newColor)
 141    {
 6142        if (backgroundMaterial == null)
 0143            return;
 144
 6145        backgroundMaterial.SetColor(COLOR_SHADER_PROPERTY, newColor);
 6146    }
 147
 148    private void FetchNFTContents()
 149    {
 3150        ShowLoading(true);
 3151        nftInfoLoadHelper.FetchNFTInfo(darURLRegistry, darURLAsset);
 3152    }
 153
 154    private void FetchNFTInfoSuccess(NFTInfo nftInfo)
 155    {
 0156        loadNftAssetCoroutine = StartCoroutine(LoadNFTAssetCoroutine(nftInfo));
 0157    }
 158
 159    private void FetchNFTInfoFail()
 160    {
 0161        ShowErrorFeedback(true);
 0162        FinishLoading(false);
 0163    }
 164
 165    private void PrepareFrame(INFTAsset nftAsset, string nftName, string nftImageUrl)
 166    {
 0167        SetFrameImage(nftAsset.previewAsset.texture, resizeFrameMesh: true);
 168
 0169        var hqImageHandlerConfig = new NFTShapeHQImageConfig()
 170        {
 171            controller = this,
 172            nftShapeConfig = config,
 173            name = nftName,
 174            imageUrl = nftImageUrl,
 175            asset = nftAsset
 176        };
 177
 0178        hqTextureHandler = NFTShapeHQImageHandler.Create(hqImageHandlerConfig);
 0179        nftAsset.OnTextureUpdate += UpdateTexture;
 0180    }
 181
 182    internal IEnumerator LoadNFTAssetCoroutine(NFTInfo nftInfo)
 183    {
 0184        yield return new DCL.WaitUntil(() => (CommonScriptableObjects.playerUnityPosition - transform.position).sqrMagni
 185
 186        // We download the "preview" 256px image
 0187        yield return nftAssetLoadHelper.LoadNFTAsset(
 188            nftInfo.previewImageUrl,
 189            (result) =>
 190            {
 0191                PrepareFrame(result, nftInfo.name, nftInfo.imageUrl);
 0192                FinishLoading(true);
 0193            },
 194            (exc) =>
 195            {
 0196                Debug.LogError(string.Format(COULD_NOT_FETCH_NFT_IMAGE, darURLRegistry, darURLAsset,
 197                    nftInfo.previewImageUrl));
 198
 0199                ShowErrorFeedback(true);
 0200                OnLoadingAssetFail?.Invoke();
 0201                FinishLoading(false);
 0202            });
 0203    }
 204
 205    void FinishLoading(bool loadedSuccessfully)
 206    {
 0207        if (loadedSuccessfully)
 208        {
 0209            ShowLoading(false);
 0210            OnLoadingAssetSuccess?.Invoke();
 0211        }
 212        else
 213        {
 0214            OnLoadingAssetFail?.Invoke();
 215        }
 0216    }
 217
 218    void SetFrameImage(Texture2D texture, bool resizeFrameMesh = false)
 219    {
 0220        if (texture == null)
 0221            return;
 222
 0223        UpdateTexture(texture);
 224
 0225        if (resizeFrameMesh && meshRenderer != null)
 226        {
 227            float w, h;
 0228            w = h = 0.5f;
 0229            if (texture.width > texture.height)
 0230                h *= texture.height / (float) texture.width;
 0231            else if (texture.width < texture.height)
 0232                w *= texture.width / (float) texture.height;
 0233            Vector3 newScale = new Vector3(w, h, 1f);
 234
 0235            meshRenderer.transform.localScale = newScale;
 236        }
 0237    }
 238
 239    public void UpdateTexture(Texture2D texture)
 240    {
 0241        if (imageMaterial == null)
 0242            return;
 243
 0244        imageMaterial.SetTexture(BASEMAP_SHADER_PROPERTY, texture);
 0245        imageMaterial.SetColor(COLOR_SHADER_PROPERTY, Color.white);
 0246    }
 247
 248    private void ShowLoading(bool isVisible)
 249    {
 3250        if (spinner == null)
 0251            return;
 252
 3253        spinner.SetActive(isVisible);
 3254    }
 255
 256    private void ShowErrorFeedback(bool isVisible)
 257    {
 3258        if (errorFeedback == null)
 0259            return;
 260
 3261        if (isVisible)
 0262            ShowLoading(false);
 263
 3264        errorFeedback.SetActive(isVisible);
 3265    }
 266
 267    void InitializeMaterials()
 268    {
 7269        Material[] meshMaterials = new Material[materials.Length];
 56270        for (int i = 0; i < materials.Length; i++)
 271        {
 21272            switch (materials[i].type)
 273            {
 274                case NFTShapeMaterial.MaterialType.BACKGROUND:
 7275                    backgroundMaterial = new Material(materials[i].material);
 7276                    meshMaterials[i] = backgroundMaterial;
 7277                    break;
 278                case NFTShapeMaterial.MaterialType.FRAME:
 7279                    frameMaterial = materials[i].material;
 7280                    meshMaterials[i] = frameMaterial;
 7281                    break;
 282                case NFTShapeMaterial.MaterialType.IMAGE:
 7283                    imageMaterial = new Material(materials[i].material);
 7284                    meshMaterials[i] = imageMaterial;
 285                    break;
 286            }
 287        }
 288
 289
 7290        meshRenderer.materials = meshMaterials;
 291
 7292        if (frameMaterial == null)
 0293            return;
 294
 7295        frameMaterial.shaderKeywords = null;
 296
 7297        if (noiseType == NoiseType.None)
 0298            return;
 299
 7300        switch (noiseType)
 301        {
 302            case NoiseType.ClassicPerlin:
 0303                frameMaterial.EnableKeyword("CNOISE");
 0304                break;
 305            case NoiseType.PeriodicPerlin:
 0306                frameMaterial.EnableKeyword("PNOISE");
 0307                break;
 308            case NoiseType.Simplex:
 7309                frameMaterial.EnableKeyword("SNOISE");
 7310                break;
 311            case NoiseType.SimplexNumericalGrad:
 0312                frameMaterial.EnableKeyword("SNOISE_NGRAD");
 0313                break;
 314            default: // SimplexAnalyticalGrad
 0315                frameMaterial.EnableKeyword("SNOISE_AGRAD");
 316                break;
 317        }
 318
 7319        if (noiseIs3D)
 0320            frameMaterial.EnableKeyword("THREED");
 321
 7322        if (noiseIsFractal)
 0323            frameMaterial.EnableKeyword("FRACTAL");
 7324    }
 325
 326}