< Summary

Class:DCL.Helpers.UtilsDummyJsonUtilityFromArray[T]
Assembly:Utils
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Helpers/Utils/Utils.cs
Covered lines:0
Uncovered lines:2
Coverable lines:2
Total lines:775
Line coverage:0% (0 of 2)
Covered branches:0
Total branches:0
Covered methods:0
Total methods:1
Method coverage:0% (0 of 1)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
GetFromJsonArray(...)0%2100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Helpers/Utils/Utils.cs

#LineLine coverage
 1#if UNITY_WEBGL && !UNITY_EDITOR
 2#define WEB_PLATFORM
 3#endif
 4
 5using Cysharp.Threading.Tasks;
 6using System;
 7using System.Collections;
 8using System.Collections.Generic;
 9using System.Linq;
 10using System.Reflection;
 11using DCL.Configuration;
 12using DG.Tweening;
 13using Google.Protobuf.Collections;
 14using Newtonsoft.Json;
 15using System.Text.RegularExpressions;
 16using System.Threading;
 17using TMPro;
 18using UnityEngine;
 19using UnityEngine.Assertions;
 20using UnityEngine.EventSystems;
 21using UnityEngine.Networking;
 22using UnityEngine.UI;
 23using Object = UnityEngine.Object;
 24using UnityEngine.Rendering.Universal;
 25using static Decentraland.Sdk.Ecs6.ComponentBodyPayload;
 26
 27namespace DCL.Helpers
 28{
 29    public static class Utils
 30    {
 31        public static Dictionary<string, Material> staticMaterials;
 32
 33        public static Material EnsureResourcesMaterial(string path)
 34        {
 35            if (staticMaterials == null) { staticMaterials = new Dictionary<string, Material>(); }
 36
 37            if (!staticMaterials.ContainsKey(path))
 38            {
 39                Material material = Resources.Load(path) as Material;
 40
 41                if (material != null) { staticMaterials.Add(path, material); }
 42
 43                return material;
 44            }
 45
 46            return staticMaterials[path];
 47        }
 48
 49        public static void QuitApplication()
 50        {
 51#if UNITY_EDITOR
 52
 53            // Application.Quit() does not work in the editor so
 54            // UnityEditor.EditorApplication.isPlaying need to be set to false to end the game
 55            UnityEditor.EditorApplication.isPlaying = false;
 56#else
 57            Application.Quit();
 58#endif
 59        }
 60
 61        public static void CleanMaterials(Renderer r)
 62        {
 63            if (r != null)
 64            {
 65                foreach (Material m in r.materials)
 66                {
 67                    if (m != null) { Material.Destroy(m); }
 68                }
 69            }
 70        }
 71
 72        public static ScriptableRendererFeature ToggleRenderFeature<T>(this UniversalRenderPipelineAsset asset, bool ena
 73        {
 74            var type = asset.GetType();
 75            var propertyInfo = type.GetField("m_RendererDataList", BindingFlags.Instance | BindingFlags.NonPublic);
 76
 77            if (propertyInfo == null) { return null; }
 78
 79            var scriptableRenderData = (ScriptableRendererData[])propertyInfo.GetValue(asset);
 80
 81            if (scriptableRenderData != null && scriptableRenderData.Length > 0)
 82            {
 83                foreach (var renderData in scriptableRenderData)
 84                {
 85                    foreach (var rendererFeature in renderData.rendererFeatures)
 86                    {
 87                        if (rendererFeature is T)
 88                        {
 89                            rendererFeature.SetActive(enable);
 90
 91                            return rendererFeature;
 92                        }
 93                    }
 94                }
 95            }
 96
 97            return null;
 98        }
 99
 100        public static Vector2[] FloatArrayToV2List(RepeatedField<float> uvs)
 101        {
 102            Vector2[] uvsResult = new Vector2[uvs.Count / 2];
 103            int uvsResultIndex = 0;
 104
 105            for (int i = 0; i < uvs.Count;)
 106            {
 107                Vector2 tmpUv = Vector2.zero;
 108                tmpUv.x = uvs[i++];
 109                tmpUv.y = uvs[i++];
 110
 111                uvsResult[uvsResultIndex++] = tmpUv;
 112            }
 113
 114            return uvsResult;
 115        }
 116
 117        public static Vector2[] FloatArrayToV2List(IList<float> uvs)
 118        {
 119            Vector2[] uvsResult = new Vector2[uvs.Count / 2];
 120            int uvsResultIndex = 0;
 121
 122            for (int i = 0; i < uvs.Count;) { uvsResult[uvsResultIndex++] = new Vector2(uvs[i++], uvs[i++]); }
 123
 124            return uvsResult;
 125        }
 126
 127        public static Vector2Int StringToVector2Int(string coords)
 128        {
 129            string[] coordSplit = coords.Split(',');
 130
 131            if (coordSplit.Length == 2 && int.TryParse(coordSplit[0], out int x) && int.TryParse(coordSplit[1], out int 
 132
 133            return Vector2Int.zero;
 134        }
 135
 136        private const int MAX_TRANSFORM_VALUE = 10000;
 137        private const float MIN_TRANSFORM_SCALE_Z_VALUE = 0.00001f;
 138
 139        public static void CapGlobalValuesToMax(this Transform transform)
 140        {
 141            bool positionOutsideBoundaries = transform.position.sqrMagnitude > MAX_TRANSFORM_VALUE * MAX_TRANSFORM_VALUE
 142            bool scaleOutsideBoundaries = transform.lossyScale.sqrMagnitude > MAX_TRANSFORM_VALUE * MAX_TRANSFORM_VALUE;
 143
 144            //Extra check to prevent rendering artifacts when bloom is on
 145            //More description: https://github.com/decentraland/unity-renderer/issues/5698
 146            bool scaleZAxisBelowMinimum = Mathf.Abs(transform.localScale.z) < MIN_TRANSFORM_SCALE_Z_VALUE;
 147
 148            if (positionOutsideBoundaries || scaleOutsideBoundaries || scaleZAxisBelowMinimum)
 149            {
 150                Vector3 newPosition = transform.position;
 151
 152                if (positionOutsideBoundaries)
 153                {
 154                    if (Mathf.Abs(newPosition.x) > MAX_TRANSFORM_VALUE)
 155                        newPosition.x = MAX_TRANSFORM_VALUE * Mathf.Sign(newPosition.x);
 156
 157                    if (Mathf.Abs(newPosition.y) > MAX_TRANSFORM_VALUE)
 158                        newPosition.y = MAX_TRANSFORM_VALUE * Mathf.Sign(newPosition.y);
 159
 160                    if (Mathf.Abs(newPosition.z) > MAX_TRANSFORM_VALUE)
 161                        newPosition.z = MAX_TRANSFORM_VALUE * Mathf.Sign(newPosition.z);
 162                }
 163
 164                Vector3 newScale = transform.lossyScale;
 165
 166                if (scaleOutsideBoundaries || scaleZAxisBelowMinimum)
 167                {
 168                    if (Mathf.Abs(newScale.x) > MAX_TRANSFORM_VALUE)
 169                        newScale.x = MAX_TRANSFORM_VALUE * Mathf.Sign(newScale.x);
 170
 171                    if (Mathf.Abs(newScale.y) > MAX_TRANSFORM_VALUE)
 172                        newScale.y = MAX_TRANSFORM_VALUE * Mathf.Sign(newScale.y);
 173
 174                    if (Mathf.Abs(newScale.z) > MAX_TRANSFORM_VALUE)
 175                        newScale.z = MAX_TRANSFORM_VALUE * Mathf.Sign(newScale.z);
 176                    else if (scaleZAxisBelowMinimum)
 177                        newScale.z = MIN_TRANSFORM_SCALE_Z_VALUE * Mathf.Sign(newScale.z == 0 ? 1 : newScale.z);
 178                }
 179
 180                SetTransformGlobalValues(transform, newPosition, transform.rotation, newScale, scaleOutsideBoundaries ||
 181            }
 182        }
 183
 184        public static void SetTransformGlobalValues(Transform transform, Vector3 newPos, Quaternion newRot, Vector3 newS
 185        {
 186            transform.position = newPos;
 187            transform.rotation = newRot;
 188
 189            if (setScale)
 190            {
 191                transform.localScale = Vector3.one;
 192                var m = transform.worldToLocalMatrix;
 193
 194                m.SetColumn(0, new Vector4(m.GetColumn(0).magnitude, 0f));
 195                m.SetColumn(1, new Vector4(0f, m.GetColumn(1).magnitude));
 196                m.SetColumn(2, new Vector4(0f, 0f, m.GetColumn(2).magnitude));
 197                m.SetColumn(3, new Vector4(0f, 0f, 0f, 1f));
 198
 199                transform.localScale = m.MultiplyPoint(newScale);
 200            }
 201        }
 202
 203        public static void ResetLocalTRS(this Transform t)
 204        {
 205            t.localPosition = Vector3.zero;
 206            t.localRotation = Quaternion.identity;
 207            t.localScale = Vector3.one;
 208        }
 209
 210        public static void SetToMaxStretch(this RectTransform t)
 211        {
 212            t.anchorMin = Vector2.zero;
 213            t.offsetMin = Vector2.zero;
 214            t.anchorMax = Vector2.one;
 215            t.offsetMax = Vector2.one;
 216            t.sizeDelta = Vector2.zero;
 217            t.anchoredPosition = Vector2.zero;
 218        }
 219
 220        public static void SetToCentered(this RectTransform t)
 221        {
 222            t.anchorMin = Vector2.one * 0.5f;
 223            t.offsetMin = Vector2.one * 0.5f;
 224            t.anchorMax = Vector2.one * 0.5f;
 225            t.offsetMax = Vector2.one * 0.5f;
 226            t.sizeDelta = Vector2.one * 100;
 227        }
 228
 229        public static void SetToBottomLeft(this RectTransform t)
 230        {
 231            t.anchorMin = Vector2.zero;
 232            t.offsetMin = Vector2.zero;
 233            t.anchorMax = Vector2.zero;
 234            t.offsetMax = Vector2.zero;
 235            t.sizeDelta = Vector2.one * 100;
 236        }
 237
 238        public static void ForceUpdateLayout(this RectTransform rt, bool delayed = true)
 239        {
 240            if (!rt.gameObject.activeInHierarchy)
 241                return;
 242
 243            if (delayed)
 244                CoroutineStarter.Start(ForceUpdateLayoutRoutine(rt));
 245            else
 246            {
 247                InverseTransformChildTraversal<RectTransform>(
 248                    (x) => { ForceRebuildLayoutImmediate(x); },
 249                    rt);
 250            }
 251        }
 252
 253        /// <summary>
 254        /// Reimplementation of the LayoutRebuilder.ForceRebuildLayoutImmediate() function (Unity UI API) for make it mo
 255        /// </summary>
 256        /// <param name="rectTransformRoot">Root from which to rebuild.</param>
 257        public static void ForceRebuildLayoutImmediate(RectTransform rectTransformRoot)
 258        {
 259            if (rectTransformRoot == null)
 260                return;
 261
 262            // NOTE(Santi): It seems to be very much cheaper to execute the next instructions manually than execute dire
 263            //              'LayoutRebuilder.ForceRebuildLayoutImmediate()', that theorically already contains these ins
 264            var layoutElements = rectTransformRoot.GetComponentsInChildren(typeof(ILayoutElement), true).ToList();
 265            layoutElements.RemoveAll(e => (e is Behaviour && !((Behaviour)e).isActiveAndEnabled) || e is TextMeshProUGUI
 266
 267            foreach (var layoutElem in layoutElements)
 268            {
 269                (layoutElem as ILayoutElement).CalculateLayoutInputHorizontal();
 270                (layoutElem as ILayoutElement).CalculateLayoutInputVertical();
 271            }
 272
 273            var layoutControllers = rectTransformRoot.GetComponentsInChildren(typeof(ILayoutController), true).ToList();
 274            layoutControllers.RemoveAll(e => e is Behaviour && !((Behaviour)e).isActiveAndEnabled);
 275
 276            foreach (var layoutCtrl in layoutControllers)
 277            {
 278                (layoutCtrl as ILayoutController).SetLayoutHorizontal();
 279                (layoutCtrl as ILayoutController).SetLayoutVertical();
 280            }
 281        }
 282
 283        private static IEnumerator ForceUpdateLayoutRoutine(RectTransform rt)
 284        {
 285            yield return null;
 286
 287            InverseTransformChildTraversal<RectTransform>(
 288                (x) => { ForceRebuildLayoutImmediate(x); },
 289                rt);
 290        }
 291
 292        public static void InverseTransformChildTraversal<TComponent>(Action<TComponent> action, Transform startTransfor
 293            where TComponent: Component
 294        {
 295            if (startTransform == null)
 296                return;
 297
 298            foreach (Transform t in startTransform) { InverseTransformChildTraversal(action, t); }
 299
 300            var component = startTransform.GetComponent<TComponent>();
 301
 302            if (component != null) { action.Invoke(component); }
 303        }
 304
 305        public static void ForwardTransformChildTraversal<TComponent>(Func<TComponent, bool> action, Transform startTran
 306            where TComponent: Component
 307        {
 308            Assert.IsTrue(startTransform != null, "startTransform must not be null");
 309
 310            var component = startTransform.GetComponent<TComponent>();
 311
 312            if (component != null)
 313            {
 314                if (!action.Invoke(component))
 315                    return;
 316            }
 317
 318            foreach (Transform t in startTransform) { ForwardTransformChildTraversal(action, t); }
 319        }
 320
 321        public static T GetOrCreateComponent<T>(this GameObject gameObject) where T: Component
 322        {
 323            T component = gameObject.GetComponent<T>();
 324
 325            if (!component) { return gameObject.AddComponent<T>(); }
 326
 327            return component;
 328        }
 329
 330        public static IWebRequestAsyncOperation FetchTexture(string textureURL, bool isReadable, Action<Texture2D> OnSuc
 331        {
 332            void SuccessInternal(IWebRequestAsyncOperation request)
 333            {
 334                OnSuccess?.Invoke(DownloadHandlerTexture.GetContent(request.webRequest));
 335            }
 336
 337            var asyncOp = Environment.i.platform.webRequest.GetTexture(
 338                url: textureURL,
 339                OnSuccess: SuccessInternal,
 340                OnFail: OnFail,
 341                isReadable: isReadable);
 342
 343            return asyncOp;
 344        }
 345
 346        public static bool SafeFromJsonOverwrite(string json, object objectToOverwrite)
 347        {
 348            try { JsonUtility.FromJsonOverwrite(json, objectToOverwrite); }
 349            catch (ArgumentException e)
 350            {
 351                Debug.LogError("ArgumentException Fail!... Json = " + json + " " + e.ToString());
 352                return false;
 353            }
 354
 355            return true;
 356        }
 357
 358        public static T FromJsonWithNulls<T>(string json)
 359        {
 360            return JsonConvert.DeserializeObject<T>(json);
 361        }
 362
 363        public static T SafeFromJson<T>(string json)
 364        {
 365            ProfilingEvents.OnMessageDecodeStart?.Invoke("Misc");
 366
 367            T returningValue = default(T);
 368
 369            if (!string.IsNullOrEmpty(json))
 370            {
 371                try { returningValue = JsonUtility.FromJson<T>(json); }
 372                catch (ArgumentException e) { Debug.LogError("ArgumentException Fail!... Json = " + json + " " + e.ToStr
 373            }
 374
 375            ProfilingEvents.OnMessageDecodeEnds?.Invoke("Misc");
 376
 377            return returningValue;
 378        }
 379
 380        public static TModel SafeUnimplemented<TComponent, TModel>(PayloadOneofCase expected, PayloadOneofCase actual)
 381        {
 382            Debug.LogError($"Payload provided for SDK6 {typeof(TComponent).Name} component is not a {expected} but {actu
 383            return default(TModel);
 384        }
 385
 386        public static GameObject AttachPlaceholderRendererGameObject(Transform targetTransform)
 387        {
 388            var placeholderRenderer = GameObject.CreatePrimitive(PrimitiveType.Cube).GetComponent<MeshRenderer>();
 389
 390            placeholderRenderer.material = Resources.Load<Material>("Materials/AssetLoading");
 391            placeholderRenderer.transform.SetParent(targetTransform);
 392            placeholderRenderer.transform.localPosition = Vector3.zero;
 393            placeholderRenderer.name = "PlaceholderRenderer";
 394
 395            return placeholderRenderer.gameObject;
 396        }
 397
 398        public static void SafeDestroy(Object obj)
 399        {
 400            if (obj is Transform)
 401                return;
 402
 403#if UNITY_EDITOR
 404            if (Application.isPlaying)
 405                Object.Destroy(obj);
 406            else
 407                Object.DestroyImmediate(obj, false);
 408#else
 409                UnityEngine.Object.Destroy(obj);
 410#endif
 411        }
 412
 413        /**
 414         * Transforms a grid position into a world-relative 3d position
 415         */
 416        public static Vector3 GridToWorldPosition(float xGridPosition, float yGridPosition)
 417        {
 418            return new Vector3(
 419                x: xGridPosition * ParcelSettings.PARCEL_SIZE,
 420                y: 0f,
 421                z: yGridPosition * ParcelSettings.PARCEL_SIZE
 422            );
 423        }
 424
 425        /**
 426         * Transforms a world position into a grid position
 427         */
 428        public static Vector2Int WorldToGridPosition(Vector3 worldPosition)
 429        {
 430            return new Vector2Int(
 431                (int)Mathf.Floor(worldPosition.x / ParcelSettings.PARCEL_SIZE),
 432                (int)Mathf.Floor(worldPosition.z / ParcelSettings.PARCEL_SIZE)
 433            );
 434        }
 435
 436        public static Vector2 WorldToGridPositionUnclamped(Vector3 worldPosition)
 437        {
 438            return new Vector2(
 439                worldPosition.x / ParcelSettings.PARCEL_SIZE,
 440                worldPosition.z / ParcelSettings.PARCEL_SIZE
 441            );
 442        }
 443
 444        public static bool AproxComparison(this Color color1, Color color2, float tolerance = 0.01f) // tolerance of rou
 445        {
 446            if (Mathf.Abs(color1.r - color2.r) < tolerance
 447                && Mathf.Abs(color1.g - color2.g) < tolerance
 448                && Mathf.Abs(color1.b - color2.b) < tolerance) { return true; }
 449
 450            return false;
 451        }
 452
 453        public static T ParseJsonArray<T>(string jsonArray) where T: IEnumerable =>
 454            DummyJsonUtilityFromArray<T>.GetFromJsonArray(jsonArray);
 455
 456        [Serializable]
 457        private class DummyJsonUtilityFromArray<T> where T: IEnumerable //UnityEngine.JsonUtility is really fast but can
 458        {
 459            [SerializeField]
 460            private T value;
 461
 462            public static T GetFromJsonArray(string jsonArray)
 463            {
 0464                var newJson = $"{{ \"value\": {jsonArray}}}";
 0465                return JsonUtility.FromJson<DummyJsonUtilityFromArray<T>>(newJson).value;
 466            }
 467        }
 468
 469        private static int lockedInFrame = -1;
 470
 471        public static bool LockedThisFrame() =>
 472            lockedInFrame == Time.frameCount;
 473
 474        private static bool isCursorLocked;
 475
 476        //NOTE(Brian): Made as an independent flag because the CI doesn't work well with the Cursor.lockState check.
 477        public static bool IsCursorLocked
 478        {
 479            get => isCursorLocked;
 480
 481            private set
 482            {
 483                if (isCursorLocked == value) return;
 484                isCursorLocked = value;
 485                OnCursorLockChanged?.Invoke(isCursorLocked);
 486            }
 487        }
 488
 489        public static event Action<bool> OnCursorLockChanged;
 490
 491        public static void LockCursor()
 492        {
 493#if WEB_PLATFORM
 494            //TODO(Brian): Encapsulate all this mechanism to a new MouseLockController and branch
 495            //             behaviour using strategy pattern instead of this.
 496            if (IsCursorLocked)
 497            {
 498                return;
 499            }
 500#endif
 501            Cursor.visible = false;
 502            IsCursorLocked = true;
 503            Cursor.lockState = CursorLockMode.Locked;
 504            lockedInFrame = Time.frameCount;
 505
 506            EventSystem.current?.SetSelectedGameObject(null);
 507        }
 508
 509        public static void UnlockCursor()
 510        {
 511#if WEB_PLATFORM
 512            //TODO(Brian): Encapsulate all this mechanism to a new MouseLockController and branch
 513            //             behaviour using strategy pattern instead of this.
 514            if (!IsCursorLocked)
 515            {
 516                return;
 517            }
 518#endif
 519            Cursor.visible = true;
 520            IsCursorLocked = false;
 521            Cursor.lockState = CursorLockMode.None;
 522
 523            EventSystem.current?.SetSelectedGameObject(null);
 524        }
 525
 526#region BROWSER_ONLY
 527        //TODO(Brian): Encapsulate all this mechanism to a new MouseLockController and branch
 528        //             behaviour using strategy pattern instead of this.
 529        // NOTE: This should come from browser's pointerlockchange callback
 530        public static void BrowserSetCursorState(bool locked)
 531        {
 532            Cursor.lockState = locked ? CursorLockMode.Locked : CursorLockMode.None;
 533
 534            IsCursorLocked = locked;
 535            Cursor.visible = !locked;
 536        }
 537#endregion
 538
 539        public static void DestroyAllChild(this Transform transform)
 540        {
 541            foreach (Transform child in transform) { Object.Destroy(child.gameObject); }
 542        }
 543
 544        public static List<Vector2Int> GetBottomLeftZoneArray(Vector2Int bottomLeftAnchor, Vector2Int size)
 545        {
 546            List<Vector2Int> coords = new List<Vector2Int>();
 547
 548            for (int x = bottomLeftAnchor.x; x < bottomLeftAnchor.x + size.x; x++)
 549            {
 550                for (int y = bottomLeftAnchor.y; y < bottomLeftAnchor.y + size.y; y++) { coords.Add(new Vector2Int(x, y)
 551            }
 552
 553            return coords;
 554        }
 555
 556        public static List<Vector2Int> GetCenteredZoneArray(Vector2Int center, Vector2Int size)
 557        {
 558            List<Vector2Int> coords = new List<Vector2Int>();
 559
 560            for (int x = center.x - size.x; x < center.x + size.x; x++)
 561            {
 562                for (int y = center.y - size.y; y < center.y + size.y; y++) { coords.Add(new Vector2Int(x, y)); }
 563            }
 564
 565            return coords;
 566        }
 567
 568        public static void DrawRectGizmo(Rect rect, Color color, float duration)
 569        {
 570            Vector3 tl2 = new Vector3(rect.xMin, rect.yMax, 0);
 571            Vector3 bl2 = new Vector3(rect.xMin, rect.yMin, 0);
 572            Vector3 tr2 = new Vector3(rect.xMax, rect.yMax, 0);
 573            Vector3 br2 = new Vector3(rect.xMax, rect.yMin, 0);
 574
 575            Debug.DrawLine(tl2, bl2, color, duration);
 576            Debug.DrawLine(tl2, tr2, color, duration);
 577            Debug.DrawLine(bl2, br2, color, duration);
 578            Debug.DrawLine(tr2, br2, color, duration);
 579        }
 580
 581        public static string ToUpperFirst(this string value)
 582        {
 583            if (!string.IsNullOrEmpty(value))
 584            {
 585                var capital = char.ToUpper(value[0]);
 586                value = capital + value.Substring(1);
 587            }
 588
 589            return value;
 590        }
 591
 592        public static Vector3 Sanitize(Vector3 value)
 593        {
 594            float x = float.IsInfinity(value.x) ? 0 : value.x;
 595            float y = float.IsInfinity(value.y) ? 0 : value.y;
 596            float z = float.IsInfinity(value.z) ? 0 : value.z;
 597
 598            return new Vector3(x, y, z);
 599        }
 600
 601        public static bool CompareFloats(float a, float b, float precision = 0.1f)
 602        {
 603            return Mathf.Abs(a - b) < precision;
 604        }
 605
 606        public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple, out T1 key, out T2 value)
 607        {
 608            key = tuple.Key;
 609            value = tuple.Value;
 610        }
 611
 612        /// <summary>
 613        /// Set a layer to the given transform and its child
 614        /// </summary>
 615        /// <param name="transform"></param>
 616        public static void SetLayerRecursively(Transform transform, int layer)
 617        {
 618            transform.gameObject.layer = layer;
 619
 620            foreach (Transform child in transform) { SetLayerRecursively(child, layer); }
 621        }
 622
 623        /// <summary>
 624        /// Converts a linear float (between 0 and 1) into an exponential curve fitting for audio volume.
 625        /// </summary>
 626        /// <param name="volume">Linear volume float</param>
 627        /// <returns>Exponential volume curve float</returns>
 628        public static float ToVolumeCurve(float volume)
 629        {
 630            return volume * (2f - volume);
 631        }
 632
 633        /// <summary>
 634        /// Takes a linear volume value between 0 and 1, converts to exponential curve and maps to a value fitting for a
 635        /// </summary>
 636        /// <param name="volume">Linear volume (0 to 1)</param>
 637        /// <returns>Value for audio mixer group volume</returns>
 638        public static float ToAudioMixerGroupVolume(float volume)
 639        {
 640            return (ToVolumeCurve(volume) * 80f) - 80f;
 641        }
 642
 643        public static IEnumerator Wait(float delay, Action onFinishCallback)
 644        {
 645            yield return new WaitForSeconds(delay);
 646            onFinishCallback.Invoke();
 647        }
 648
 649        public static string GetHierarchyPath(this Transform transform)
 650        {
 651            if (transform.parent == null)
 652                return transform.name;
 653
 654            return $"{transform.parent.GetHierarchyPath()}/{transform.name}";
 655        }
 656
 657        public static bool TryFindChildRecursively(this Transform transform, string name, out Transform foundChild)
 658        {
 659            foundChild = transform.Find(name);
 660
 661            if (foundChild != null)
 662                return true;
 663
 664            foreach (Transform child in transform)
 665            {
 666                if (TryFindChildRecursively(child, name, out foundChild))
 667                    return true;
 668            }
 669
 670            return false;
 671        }
 672
 673        public static bool IsPointerOverUIElement(Vector3 mousePosition)
 674        {
 675            if (EventSystem.current == null)
 676                return false;
 677
 678            var eventData = new PointerEventData(EventSystem.current);
 679            eventData.position = mousePosition;
 680            var results = new List<RaycastResult>();
 681            EventSystem.current.RaycastAll(eventData, results);
 682            return results.Count > 1;
 683        }
 684
 685        public static bool IsPointerOverUIElement()
 686        {
 687            return IsPointerOverUIElement(Input.mousePosition);
 688        }
 689
 690        public static string UnixTimeStampToLocalTime(ulong unixTimeStampMilliseconds)
 691        {
 692            DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 693            dtDateTime = dtDateTime.AddMilliseconds(unixTimeStampMilliseconds).ToLocalTime();
 694            return $"{dtDateTime.Hour}:{dtDateTime.Minute:D2}";
 695        }
 696
 697        public static DateTime UnixToDateTimeWithTime(ulong unixTimeStampMilliseconds)
 698        {
 699            DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 700            dtDateTime = dtDateTime.AddMilliseconds(unixTimeStampMilliseconds).ToLocalTime();
 701            return dtDateTime;
 702        }
 703
 704        private static readonly Regex COORDINATES_REGEX = new Regex(@"^(-?\d+),(-?\d+)$");
 705
 706        public static Vector2Int ConvertStringToVector(string input)
 707        {
 708            Match match = COORDINATES_REGEX.Match(input.Replace(" ",""));
 709
 710            if (!int.TryParse(match.Groups[1].Value, out int x) || !int.TryParse(match.Groups[2].Value, out int y))
 711            {
 712                Debug.LogError("Coordinates parsing error for coords " + input);
 713                return new Vector2Int(0, 0);
 714            }
 715
 716            return new Vector2Int(x, y);
 717        }
 718
 719        public static Color GetRandomColorInGradient(Color minColor, Color maxColor)
 720        {
 721            Color.RGBToHSV(minColor, out float startH, out float startS, out float startV);
 722            Color.RGBToHSV(maxColor, out float endH, out float _, out float _);
 723            return Color.HSVToRGB(UnityEngine.Random.Range(startH, endH), startS, startV);
 724        }
 725
 726        public static UniTask ToUniTaskInstantCancelation(this Tween tween, bool completeWhenCancel = false, Cancellatio
 727        {
 728            cancellationToken.RegisterWithoutCaptureExecutionContext(() =>
 729            {
 730                // We cannot use the built in TweenCancelBehavior because we are manually killing the tween
 731                if (completeWhenCancel)
 732                    tween.Complete(false);
 733
 734                tween.Kill();
 735            });
 736
 737            return tween.ToUniTask(tweenCancelBehaviour: completeWhenCancel ? TweenCancelBehaviour.Complete : TweenCance
 738        }
 739
 740        public static List<T> RemoveDuplicatesFromList<T>(List<T> items)
 741        {
 742            List<T> result = new List<T>();
 743            for (int i = 0; i < items.Count; i++)
 744            {
 745                bool duplicate = false;
 746                for (int z = 0; z < i; z++)
 747                {
 748                    if (Equals(items[z], items[i]))
 749                    {
 750                        duplicate = true;
 751                        break;
 752                    }
 753                }
 754                if (!duplicate)
 755                {
 756                    result.Add(items[i]);
 757                }
 758            }
 759            return result;
 760        }
 761
 762        public static T[] RemoveDuplicatesFromArray<T>(T[] s)
 763        {
 764            HashSet<T> set = new HashSet<T>(s);
 765            T[] result = new T[set.Count];
 766            set.CopyTo(result);
 767            return result;
 768        }
 769
 770        public static bool CanBeUnEquipped(this WearableItem wearable) =>
 771            wearable.data.category != WearableLiterals.Categories.BODY_SHAPE &&
 772            wearable.data.category != WearableLiterals.Categories.EYES &&
 773            wearable.data.category != WearableLiterals.Categories.MOUTH;
 774    }
 775}

Methods/Properties

GetFromJsonArray(System.String)