using UnityEngine; using System.Linq; namespace Crosstales { /// Various extension methods. public static class ExtensionMethods { #region Variables private static readonly Vector3 FLAT_VECTOR = new Vector3(1, 0, 1); #endregion #region Strings /// /// Extension method for strings. /// Converts a string to title case (first letter uppercase). /// /// String-instance. /// Converted string in title case. public static string CTToTitleCase(this string str) { if (str == null) return str; #if UNITY_WSA || UNITY_XBOXONE return toTitleCase(str); #else return System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower()); #endif } #if UNITY_WSA || UNITY_XBOXONE /// /// Converts to title case: each word starts with an upper case. /// private static string toTitleCase(string str) { if (str.Length == 0) return str; System.Text.StringBuilder result = new System.Text.StringBuilder(str); result[0] = char.ToUpper(result[0]); for (int ii = 1; ii < result.Length; ii++) { if (char.IsWhiteSpace(result[ii - 1])) result[ii] = char.ToUpper(result[ii]); else result[ii] = char.ToLower(result[ii]); } return result.ToString(); } #endif /// /// Extension method for strings. /// Reverses a string. /// /// String-instance. /// Reversed string. public static string CTReverse(this string str) { if (str == null) return str; char[] charArray = str.ToCharArray(); System.Array.Reverse(charArray); return new string(charArray); } /// /// Extension method for strings. /// Default: case insensitive 'Replace'. /// /// String-instance. /// String to replace. /// New replacement string. /// StringComparison-method (optional, default: StringComparison.OrdinalIgnoreCase) /// Replaced string. public static string CTReplace(this string str, string oldString, string newString, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase) { if (str == null) return str; if (oldString == null) return str; if (newString == null) return str; bool matchFound; do { int index = str.IndexOf(oldString, comp); matchFound = index >= 0; if (matchFound) { str = str.Remove(index, oldString.Length); str = str.Insert(index, newString); } } while (matchFound); return str; } /// /// Extension method for strings. /// Removes characters from a string /// /// String-instance. /// Characters to remove. /// String without the given characters. public static string CTRemoveChars(this string str, params char[] removeChars) { if (str == null) return str; if (removeChars == null) return str; return removeChars.Aggregate(str, (current, rmChar) => current.Replace($"{rmChar}", string.Empty)); } /// /// Extension method for strings. /// Default: case insensitive 'Equals'. /// /// String-instance. /// String to check. /// StringComparison-method (optional, default: StringComparison.OrdinalIgnoreCase) /// True if the string contains the given string. public static bool CTEquals(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase) { return str?.Equals(toCheck, comp) == true; //if (toCheck == null) // throw new System.ArgumentNullException("toCheck"); } /// /// Extension method for strings. /// Default: case insensitive 'Contains'. /// /// String-instance. /// String to check. /// StringComparison-method (optional, default: StringComparison.OrdinalIgnoreCase) /// True if the string contains the given string. public static bool CTContains(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase) { return str?.IndexOf(toCheck, comp) >= 0; } /// /// Extension method for strings. /// Contains any given string. /// /// String-instance. /// Search terms separated by the given split-character. /// Split-character (optional, default: ' ') /// True if the string contains any parts of the given string. public static bool CTContainsAny(this string str, string searchTerms, char splitChar = ' ') { if (str == null) return false; if (string.IsNullOrEmpty(searchTerms)) return true; char[] split = { splitChar }; return searchTerms.Split(split, System.StringSplitOptions.RemoveEmptyEntries).Any(searchTerm => str.CTContains(searchTerm)); } /// /// Extension method for strings. /// Contains all given strings. /// /// String-instance. /// Search terms separated by the given split-character. /// Split-character (optional, default: ' ') /// True if the string contains all parts of the given string. public static bool CTContainsAll(this string str, string searchTerms, char splitChar = ' ') { if (str == null) return false; if (string.IsNullOrEmpty(searchTerms)) return true; char[] split = { splitChar }; return searchTerms.Split(split, System.StringSplitOptions.RemoveEmptyEntries).All(searchTerm => str.CTContains(searchTerm)); } /// /// Extension method for strings. /// Replaces new lines with a replacement string pattern. /// /// String-instance. /// Replacement string pattern (optional, default: "#nl#"). /// New line string (optional, default: System.Environment.NewLine). /// Replaced string without new lines. public static string CTRemoveNewLines(this string str, string replacement = "#nl#", string newLine = null) { return str?.Replace(string.IsNullOrEmpty(newLine) ? System.Environment.NewLine : newLine, replacement); } /// /// Extension method for strings. /// Replaces a given string pattern with new lines in a string. /// /// String-instance. /// Replacement string pattern (optional, default: "#nl#"). /// New line string (optional, default: System.Environment.NewLine). /// Replaced string with new lines. public static string CTAddNewLines(this string str, string replacement = "#nl#", string newLine = null) { return str?.CTReplace(replacement, string.IsNullOrEmpty(newLine) ? System.Environment.NewLine : newLine); } /// /// Extension method for strings. /// Checks if the string is numeric. /// /// String-instance. /// True if the string is numeric. [System.Obsolete("Please use 'CTIsNumeric' instead.")] public static bool CTisNumeric(this string str) { return CTIsNumeric(str); } /// /// Extension method for strings. /// Checks if the string is numeric. /// /// String-instance. /// True if the string is numeric. public static bool CTIsNumeric(this string str) { return str != null && double.TryParse(str, out double output); } /// /// Extension method for strings. /// Checks if the string is integer. /// /// String-instance. /// True if the string is integer. [System.Obsolete("Please use 'CTIsInteger' instead.")] public static bool CTisInteger(this string str) { return CTIsInteger(str); } /// /// Extension method for strings. /// Checks if the string is integer. /// /// String-instance. /// True if the string is integer. public static bool CTIsInteger(this string str) { if (str == null) return false; return !str.Contains(".") && long.TryParse(str, out long output); } /// /// Extension method for strings. /// Checks if the string is an email address. /// /// String-instance. /// True if the string is an email address. [System.Obsolete("Please use 'CTIsEmail' instead.")] public static bool CTisEmail(this string str) { return CTIsEmail(str); } /// /// Extension method for strings. /// Checks if the string is an email address. /// /// String-instance. /// True if the string is an email address. public static bool CTIsEmail(this string str) { return str != null && Crosstales.Common.Util.BaseConstants.REGEX_EMAIL.IsMatch(str); } /// /// Extension method for strings. /// Checks if the string is a website address. /// /// String-instance. /// True if the string is a website address. [System.Obsolete("Please use 'CTIsWebsite' instead.")] public static bool CTisWebsite(this string str) { return CTIsWebsite(str); } /// /// Extension method for strings. /// Checks if the string is a website address. /// /// String-instance. /// True if the string is a website address. public static bool CTIsWebsite(this string str) { return str != null && Crosstales.Common.Util.BaseConstants.REGEX_URL_WEB.IsMatch(str); } /// /// Extension method for strings. /// Checks if the string is a creditcard. /// /// String-instance. /// True if the string is a creditcard. [System.Obsolete("Please use 'CTIsCreditcard' instead.")] public static bool CTisCreditcard(this string str) { return CTIsCreditcard(str); } /// /// Extension method for strings. /// Checks if the string is a creditcard. /// /// String-instance. /// True if the string is a creditcard. public static bool CTIsCreditcard(this string str) { return str != null && Crosstales.Common.Util.BaseConstants.REGEX_CREDITCARD.IsMatch(str); } /// /// Extension method for strings. /// Checks if the string is an IPv4 address. /// /// String-instance. /// True if the string is an IPv4 address. [System.Obsolete("Please use 'CTIsIPv4' instead.")] public static bool CTisIPv4(this string str) { return CTIsIPv4(str); } /// /// Extension method for strings. /// Checks if the string is an IPv4 address. /// /// String-instance. /// True if the string is an IPv4 address. public static bool CTIsIPv4(this string str) { return str != null && Crosstales.Common.Util.NetworkHelper.isIPv4(str); } /// /// Extension method for strings. /// Checks if the string is alphanumeric. /// /// String-instance. /// True if the string is alphanumeric. [System.Obsolete("Please use 'CTIsAlphanumeric' instead.")] public static bool CTisAlphanumeric(this string str) { return CTIsAlphanumeric(str); } /// /// Extension method for strings. /// Checks if the string is alphanumeric. /// /// String-instance. /// True if the string is alphanumeric. public static bool CTIsAlphanumeric(this string str) { return str != null && Crosstales.Common.Util.BaseConstants.REGEX_ALPHANUMERIC.IsMatch(str); } /// /// Extension method for strings. /// Checks if the string has line endings. /// /// String-instance. /// True if the string has line endings. [System.Obsolete("Please use 'CTHasLineEndings' instead.")] public static bool CThasLineEndings(this string str) { return CTHasLineEndings(str); } /// /// Extension method for strings. /// Checks if the string has line endings. /// /// String-instance. /// True if the string has line endings. public static bool CTHasLineEndings(this string str) { return str != null && Crosstales.Common.Util.BaseConstants.REGEX_LINEENDINGS.IsMatch(str); } /// /// Extension method for strings. /// Checks if the string has invalid characters. /// /// String-instance. /// True if the string has invalid characters. [System.Obsolete("Please use 'CTHasInvalidChars' instead.")] public static bool CThasInvalidChars(this string str) { return CTHasInvalidChars(str); } /// /// Extension method for strings. /// Checks if the string has invalid characters. /// /// String-instance. /// True if the string has invalid characters. public static bool CTHasInvalidChars(this string str) { return str != null && Crosstales.Common.Util.BaseConstants.REGEX_INVALID_CHARS.IsMatch(str); } /// /// Extension method for strings. /// Checks if the string starts with another string. /// /// String-instance. /// String to check. /// StringComparison-method (optional, default: StringComparison.OrdinalIgnoreCase) /// True if the string is integer. public static bool CTStartsWith(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase) { if (str == null) return false; return string.IsNullOrEmpty(toCheck) || str.StartsWith(toCheck, comp); } /// /// Extension method for strings. /// Checks if the string ends with another string. /// /// String-instance. /// String to check. /// StringComparison-method (optional, default: StringComparison.OrdinalIgnoreCase) /// True if the string is integer. public static bool CTEndsWith(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase) { if (str == null) return false; return string.IsNullOrEmpty(toCheck) || str.EndsWith(toCheck, comp); } /// /// Extension method for strings. /// Returns the index of the last occurence of a given string. /// /// String-instance. /// String for the index. /// StringComparison-method (optional, default: StringComparison.OrdinalIgnoreCase) /// The index of the last occurence of the given string if the string is integer. public static int CTLastIndexOf(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase) { if (str == null) throw new System.ArgumentNullException(nameof(str)); return string.IsNullOrEmpty(toCheck) ? 0 : str.LastIndexOf(toCheck, comp); } /// /// Extension method for strings. /// Returns the index of the first occurence of a given string. /// /// String-instance. /// String for the index. /// StringComparison-method (optional, default: StringComparison.OrdinalIgnoreCase) /// The index of the first occurence of the given string if the string is integer. public static int CTIndexOf(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase) { if (str == null) throw new System.ArgumentNullException(nameof(str)); return string.IsNullOrEmpty(toCheck) ? 0 : str.IndexOf(toCheck, comp); } /// /// Extension method for strings. /// Returns the index of the first occurence of a given string. /// /// String-instance. /// String for the index. /// Start index for the check. /// StringComparison-method (optional, default: StringComparison.OrdinalIgnoreCase) /// The index of the first occurence of the given string if the string is integer. public static int CTIndexOf(this string str, string toCheck, int startIndex, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase) { if (str == null) throw new System.ArgumentNullException(nameof(str)); return string.IsNullOrEmpty(toCheck) ? 0 : str.IndexOf(toCheck, startIndex, comp); } /// /// Extension method for strings. /// Converts the value of a string to a Base64-string. /// /// Input string. /// Encoding of the string (optional, default: UTF8). /// String value as converted Base64-string. public static string CTToBase64(this string str, System.Text.Encoding encoding = null) { if (str == null) return null; System.Text.Encoding _encoding = System.Text.Encoding.UTF8; if (encoding != null) _encoding = encoding; return _encoding.GetBytes(str).CTToBase64(); } /// /// Extension method for strings. /// Converts the value of a Base64-string to a string. /// /// Input Base64-string. /// Encoding of the string (optional, default: UTF8). /// Base64-string value as converted string. public static string CTFromBase64(this string str, System.Text.Encoding encoding = null) { if (str == null) return null; System.Text.Encoding _encoding = System.Text.Encoding.UTF8; if (encoding != null) _encoding = encoding; return _encoding.GetString(str.CTFromBase64ToByteArray()); } /// /// Extension method for strings. /// Converts the value of a Base64-string to a byte-array. /// /// Input Base64-string. /// Base64-Byte-array from the Base64-string. public static byte[] CTFromBase64ToByteArray(this string str) { return str == null ? null : System.Convert.FromBase64String(str); } /// /// Extension method for strings. /// Converts the value of a string to a Hex-string (with Unicode support). /// /// Input string. /// Add "0x"-as prefix (optional, default: false). /// String value as converted Hex-string. public static string CTToHex(this string str, bool addPrefix = false) { if (str == null) return null; System.Text.StringBuilder sb = new System.Text.StringBuilder(); if (addPrefix) sb.Append("0x"); byte[] bytes = System.Text.Encoding.Unicode.GetBytes(str); foreach (byte t in bytes) { sb.Append(t.ToString("X2")); } return sb.ToString(); // returns: "48656C6C6F20776F726C64" for "Hello world" } /// /// Extension method for strings. /// Converts the Hex-value of a string to a string (with Unicode support). /// /// Input as Hex-string. /// Hex-string value as converted string. public static string CTHexToString(this string hexString) { if (hexString == null) return null; string _hex = hexString; if (_hex.StartsWith("0x")) _hex = _hex.Substring(2); if (hexString.Length % 2 != 0) throw new System.FormatException($"String seems to be an invalid hex-code: {hexString}"); byte[] bytes = new byte[_hex.Length / 2]; for (int ii = 0; ii < bytes.Length; ii++) { bytes[ii] = System.Convert.ToByte(hexString.Substring(ii * 2, 2), 16); } //return System.Text.Encoding.ASCII.GetString(bytes); return System.Text.Encoding.Unicode.GetString(bytes); // returns: "Hello world" for "48656C6C6F20776F726C64" } /// /// Extension method for strings. /// Converts the Hex-value of a string to a Color32. /// /// Input as Hex-string. /// Hex-string value as Color32. public static Color32 CTHexToColor32(this string hexString) { if (hexString == null) throw new System.ArgumentNullException(nameof(hexString)); string _hex = hexString; if (_hex.StartsWith("0x")) _hex = _hex.Substring(2); if (_hex.StartsWith("#")) _hex = _hex.Substring(1); /* Color color = Color.white; if (ColorUtility.TryParseHtmlString(_hex, out color)) { Debug.LogWarning($"Could not convert string to color: {hexString}"); } return color; */ if (_hex.Length != 6 && _hex.Length != 8) throw new System.FormatException($"String seems to be an invalid color: {_hex}"); byte r = System.Convert.ToByte(_hex.Substring(0, 2), 16); byte g = System.Convert.ToByte(_hex.Substring(2, 2), 16); byte b = System.Convert.ToByte(_hex.Substring(4, 2), 16); byte a = 0xFF; if (_hex.Length == 8) a = System.Convert.ToByte(_hex.Substring(6, 2), 16); Color32 color = new Color32(r, g, b, a); //Debug.Log("Hex orig: '" + _hex + "'"); //Debug.Log("Color: " + color); return color; } /// /// Extension method for strings. /// Converts the Hex-value of a string to a Color. /// /// Input as Hex-string. /// Hex-string value as Color. public static Color CTHexToColor(this string hexString) { return CTHexToColor32(hexString); } /// /// Extension method for strings. /// Converts the value of a string to a byte-array. /// /// Input string. /// Encoding of the string (optional, default: UTF8). /// Byte-array with the string. public static byte[] CTToByteArray(this string str, System.Text.Encoding encoding = null) { if (str == null) return null; System.Text.Encoding _encoding = System.Text.Encoding.UTF8; if (encoding != null) _encoding = encoding; return _encoding.GetBytes(str); } /// /// Extension method for strings. /// Cleans a given text from tags. /// /// Input to clean. /// Clean text without tags. public static string CTClearTags(this string str) { return str != null ? Crosstales.Common.Util.BaseConstants.REGEX_CLEAN_TAGS.Replace(str, string.Empty).Trim() : null; } /// /// Extension method for strings. /// Cleans a given text from multiple spaces. /// /// Input to clean. /// Clean text without multiple spaces. public static string CTClearSpaces(this string str) { return str != null ? Crosstales.Common.Util.BaseConstants.REGEX_CLEAN_SPACES.Replace(str, " ").Trim() : null; } /// /// Extension method for strings. /// Cleans a given text from line endings. /// /// Input to clean. /// Clean text without line endings. public static string CTClearLineEndings(this string str) { return str != null ? Crosstales.Common.Util.BaseConstants.REGEX_LINEENDINGS.Replace(str, string.Empty).Trim() : null; } #endregion #region Arrays /// /// Extension method for arrays. /// Shuffles an array. /// /// Array-instance to shuffle. /// Seed for the PRNG (optional, default: 0 (=standard)) public static void CTShuffle(this T[] array, int seed = 0) { #if UNITY_WSA return; #else if (array == null || array.Length <= 0) throw new System.ArgumentNullException(nameof(array)); System.Random rnd = seed == 0 ? new System.Random() : new System.Random(seed); int n = array.Length; while (n > 1) { int k = rnd.Next(n--); (array[n], array[k]) = (array[k], array[n]); } #endif } /// /// Extension method for arrays. /// Dumps an array to a string. /// /// Array-instance to dump. /// Prefix for every element (optional, default: empty). /// Postfix for every element (optional, default: empty). /// Append new line, otherwise use the given delimiter (optional, default: false). /// Delimiter if appendNewLine is false (optional, default: "; "). /// String with lines for all array entries. public static string CTDump(this T[] array, string prefix = "", string postfix = "", bool appendNewLine = true, string delimiter = "; ") { if (array == null) // || array.Length <= 0) return null; System.Text.StringBuilder sb = new System.Text.StringBuilder(); foreach (T element in array) { if (0 < sb.Length) { sb.Append(appendNewLine ? System.Environment.NewLine : delimiter); } sb.Append(prefix); sb.Append(element); sb.Append(postfix); } return sb.ToString(); } /// /// Extension method for Quaternion-arrays. /// Dumps an array to a string. /// /// Quaternion-array-instance to dump. /// String with lines for all array entries. public static string CTDump(this Quaternion[] array) { if (array == null) // || array.Length <= 0) return null; System.Text.StringBuilder sb = new System.Text.StringBuilder(); foreach (Quaternion element in array) { if (0 < sb.Length) sb.Append(System.Environment.NewLine); sb.Append(element.x); sb.Append(", "); sb.Append(element.y); sb.Append(", "); sb.Append(element.z); sb.Append(", "); sb.Append(element.w); } return sb.ToString(); } /// /// Extension method for Vector2-arrays. /// Dumps an array to a string. /// /// Vector2-array-instance to dump. /// String with lines for all array entries. public static string CTDump(this Vector2[] array) { if (array == null) // || array.Length <= 0) return null; System.Text.StringBuilder sb = new System.Text.StringBuilder(); foreach (Vector2 element in array) { if (0 < sb.Length) sb.Append(System.Environment.NewLine); sb.Append(element.x); sb.Append(", "); sb.Append(element.y); } return sb.ToString(); } /// /// Extension method for Vector3-arrays. /// Dumps an array to a string. /// /// Vector3-array-instance to dump. /// String with lines for all array entries. public static string CTDump(this Vector3[] array) { if (array == null) // || array.Length <= 0) return null; System.Text.StringBuilder sb = new System.Text.StringBuilder(); foreach (Vector3 element in array) { if (0 < sb.Length) sb.Append(System.Environment.NewLine); sb.Append(element.x); sb.Append(", "); sb.Append(element.y); sb.Append(", "); sb.Append(element.z); } return sb.ToString(); } /// /// Extension method for Vector4-arrays. /// Dumps an array to a string. /// /// Vector4-array-instance to dump. /// String with lines for all array entries. public static string CTDump(this Vector4[] array) { if (array == null) // || array.Length <= 0) return null; System.Text.StringBuilder sb = new System.Text.StringBuilder(); foreach (Vector4 element in array) { if (0 < sb.Length) sb.Append(System.Environment.NewLine); sb.Append(element.x); sb.Append(", "); sb.Append(element.y); sb.Append(", "); sb.Append(element.z); sb.Append(", "); sb.Append(element.w); } return sb.ToString(); } /// /// Extension method for arrays. /// Generates a string array with all entries (via ToString). /// /// Array-instance to ToString. /// String array with all entries (via ToString). public static string[] CTToStringArray(this T[] array) { if (array == null) // || array.Length <= 0) throw new System.ArgumentNullException(nameof(array)); string[] result = new string[array.Length]; for (int ii = 0; ii < array.Length; ii++) { result[ii] = null == array[ii] ? "null" : array[ii].ToString(); } return result; } /// /// Extension method for byte-arrays. /// Converts a byte-array to a float-array. /// /// Array-instance to convert. /// Number of bytes to convert (optional). /// Converted float-array. public static float[] CTToFloatArray(this byte[] array, int count = 0) { if (array == null) // || array.Length <= 0) throw new System.ArgumentNullException(nameof(array)); int _count = count; if (_count <= 0) _count = array.Length; float[] floats = new float[_count / 2]; int ii = 0; for (int zz = 0; zz < _count; zz += 2) { floats[ii] = bytesToFloat(array[zz], array[zz + 1]); ii++; } return floats; } /// /// Extension method for float-arrays. /// Converts a float-array to a byte-array. /// /// Array-instance to convert. /// Number of floats to convert (optional). /// Converted byte-array. public static byte[] CTToByteArray(this float[] array, int count = 0) { if (array == null) // || array.Length <= 0) throw new System.ArgumentNullException(nameof(array)); int _count = count; if (_count <= 0) _count = array.Length; byte[] bytes = new byte[_count * 2]; int byteIndex = 0; for (int ii = 0; ii < _count; ii++) { short outsample = (short)(array[ii] * short.MaxValue); bytes[byteIndex] = (byte)(outsample & 0xff); bytes[byteIndex + 1] = (byte)((outsample >> 8) & 0xff); byteIndex += 2; } return bytes; } /// /// Extension method for byte-arrays. /// Converts a byte-array to a Texture. Supported image formats: PNG and JPG. /// /// byte-array-instance to convert. /// Support texture to prevent possible texture garbage (optional). /// Converted Texture. public static Texture2D CTToTexture(this byte[] data, Texture2D supportTexture = null) { if (data == null) throw new System.ArgumentNullException(nameof(data)); Texture2D tex = supportTexture; if (tex == null) tex = new Texture2D(1, 1); // note that the size is overridden tex.LoadImage(data); return tex; } /// /// Extension method for byte-arrays. /// Converts a byte-array to a Sprite. Supported image formats: PNG and JPG. /// /// byte-array-instance to convert. /// Support texture to prevent possible texture garbage (optional). /// Converted Sprite. public static Sprite CTToSprite(this byte[] data, Texture2D supportTexture = null) { if (data == null) throw new System.ArgumentNullException(nameof(data)); if (supportTexture == null) { Texture2D tex = data.CTToTexture(); return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(tex.width / 2, tex.height / 2)); } supportTexture = data.CTToTexture(supportTexture); return Sprite.Create(supportTexture, new Rect(0, 0, supportTexture.width, supportTexture.height), new Vector2(supportTexture.width / 2, supportTexture.height / 2)); } /// /// Extension method for byte-arrays. /// Converts a byte-array to a string. /// /// Input string as byte-array. /// Encoding of the string (optional, default: UTF8). /// Byte-array with the string. public static string CTToString(this byte[] data, System.Text.Encoding encoding = null) { if (data == null) return null; System.Text.Encoding _encoding = encoding ?? System.Text.Encoding.UTF8; return _encoding.GetString(data); } /// /// Extension method for byte-arrays. /// Converts a byte-array to a Base64-string. /// /// Input as byte-array. /// Base64-string from the byte-array. public static string CTToBase64(this byte[] data) { return data == null ? null : System.Convert.ToBase64String(data); } /// /// Extension method for 2D-arrays. /// Returns the column of a 2D-array as array. /// /// Input as 2D-array. /// Desired column of the 2D-array /// Column of a 2D-array as array. public static T[] GetColumn(this T[,] matrix, int columnNumber) { return Enumerable.Range(0, matrix.GetLength(0)).Select(x => matrix[x, columnNumber]).ToArray(); } /// /// Extension method for 2D-arrays. /// Returns the row of a 2D-array as array. /// /// Input as 2D-array. /// Desired row of the 2D-array /// Row of a 2D-array as array. public static T[] GetRow(this T[,] matrix, int rowNumber) { return Enumerable.Range(0, matrix.GetLength(1)).Select(x => matrix[rowNumber, x]).ToArray(); } #endregion #region Lists /// /// Extension method for IList. /// Shuffles a List. /// /// IList-instance to shuffle. /// Seed for the PRNG (optional, default: 0 (=standard)) public static void CTShuffle(this System.Collections.Generic.IList list, int seed = 0) { #if UNITY_WSA return; #else if (list == null) throw new System.ArgumentNullException(nameof(list)); System.Random rnd = seed == 0 ? new System.Random() : new System.Random(seed); int n = list.Count; while (n > 1) { int k = rnd.Next(n--); (list[n], list[k]) = (list[k], list[n]); } #endif } /// /// Extension method for IList. /// Dumps a list to a string. /// /// IList-instance to dump. /// Prefix for every element (optional, default: empty). /// Postfix for every element (optional, default: empty). /// Append new line, otherwise use the given delimiter (optional, default: false). /// Delimiter if appendNewLine is false (optional, default: "; "). /// String with lines for all list entries. public static string CTDump(this System.Collections.Generic.IList list, string prefix = "", string postfix = "", bool appendNewLine = true, string delimiter = "; ") { if (list == null) return null; System.Text.StringBuilder sb = new System.Text.StringBuilder(); foreach (T element in list) { if (0 < sb.Length) { sb.Append(appendNewLine ? System.Environment.NewLine : delimiter); } sb.Append(prefix); sb.Append(element); sb.Append(postfix); } return sb.ToString(); } /// /// Extension method for Quaternion-IList. /// Dumps a list to a string. /// /// Quaternion-IList-instance to dump. /// String with lines for all list entries. public static string CTDump(this System.Collections.Generic.IList list) { if (list == null) return null; System.Text.StringBuilder sb = new System.Text.StringBuilder(); foreach (Quaternion element in list) { if (0 < sb.Length) sb.Append(System.Environment.NewLine); sb.Append(element.x); sb.Append(", "); sb.Append(element.y); sb.Append(", "); sb.Append(element.z); sb.Append(", "); sb.Append(element.w); } return sb.ToString(); } /// /// Extension method for Vector2-IList. /// Dumps a list to a string. /// /// Vector2-IList-instance to dump. /// String with lines for all list entries. public static string CTDump(this System.Collections.Generic.IList list) { if (list == null) return null; System.Text.StringBuilder sb = new System.Text.StringBuilder(); foreach (Vector2 element in list) { if (0 < sb.Length) sb.Append(System.Environment.NewLine); sb.Append(element.x); sb.Append(", "); sb.Append(element.y); } return sb.ToString(); } /// /// Extension method for Vector3-IList. /// Dumps a list to a string. /// /// Vector3-IList-instance to dump. /// String with lines for all list entries. public static string CTDump(this System.Collections.Generic.IList list) { if (list == null) return null; System.Text.StringBuilder sb = new System.Text.StringBuilder(); foreach (Vector3 element in list) { if (0 < sb.Length) sb.Append(System.Environment.NewLine); sb.Append(element.x); sb.Append(", "); sb.Append(element.y); sb.Append(", "); sb.Append(element.z); } return sb.ToString(); } /// /// Extension method for Vector4-IList. /// Dumps a list to a string. /// /// Vector4-IList-instance to dump. /// String with lines for all list entries. public static string CTDump(this System.Collections.Generic.IList list) { if (list == null) return null; System.Text.StringBuilder sb = new System.Text.StringBuilder(); foreach (Vector4 element in list) { if (0 < sb.Length) sb.Append(System.Environment.NewLine); sb.Append(element.x); sb.Append(", "); sb.Append(element.y); sb.Append(", "); sb.Append(element.z); sb.Append(", "); sb.Append(element.w); } return sb.ToString(); } /// /// Extension method for IList. /// Generates a string list with all entries (via ToString). /// /// IList-instance to ToString. /// String list with all entries (via ToString). public static System.Collections.Generic.List CTToString(this System.Collections.Generic.IList list) { if (list == null) throw new System.ArgumentNullException(nameof(list)); System.Collections.Generic.List result = new System.Collections.Generic.List(list.Count); result.AddRange(list.Select(element => null == element ? "null" : element.ToString())); return result; } #endregion #region Dictionaries /// /// Extension method for IDictionary. /// Dumps a dictionary to a string. /// /// IDictionary-instance to dump. /// Prefix for every element (optional, default: empty). /// Postfix for every element (optional, default: empty). /// Append new line, otherwise use the given delimiter (optional, default: false). /// Delimiter if appendNewLine is false (optional, default: "; "). /// String with lines for all dictionary entries. public static string CTDump(this System.Collections.Generic.IDictionary dict, string prefix = "", string postfix = "", bool appendNewLine = true, string delimiter = "; ") { if (dict == null) return null; System.Text.StringBuilder sb = new System.Text.StringBuilder(); foreach (System.Collections.Generic.KeyValuePair kvp in dict) { if (0 < sb.Length) { sb.Append(appendNewLine ? System.Environment.NewLine : delimiter); } sb.Append(prefix); sb.Append("Key = "); sb.Append(kvp.Key); sb.Append(", Value = "); sb.Append(kvp.Value); sb.Append(postfix); } return sb.ToString(); } /// /// Extension method for IDictionary. /// Adds a dictionary to an existing one. /// /// IDictionary-instance. /// Dictionary to add. public static void CTAddRange(this System.Collections.Generic.IDictionary dict, System.Collections.Generic.IDictionary collection) { if (dict == null) throw new System.ArgumentNullException(nameof(dict)); if (collection == null) throw new System.ArgumentNullException(nameof(collection)); foreach (System.Collections.Generic.KeyValuePair item in collection) { if (!dict.ContainsKey(item.Key)) { dict.Add(item.Key, item.Value); } else { // handle duplicate key issue here Debug.LogWarning($"Duplicate key found: {item.Key}"); } } } #endregion #region Streams /// /// Extension method for Stream. /// Reads the full content of a Stream. /// /// Stream-instance to read. /// Byte-array of the Stream content. public static byte[] CTReadFully(this System.IO.Stream input) { if (input == null) throw new System.ArgumentNullException(nameof(input)); using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) { input.CopyTo(ms); return ms.ToArray(); } } #endregion #region Color /// /// Extension method for Color32. /// Converts the value of a color to a RGB Hex-string. /// /// Color to convert. /// Color value as Hex (format "RRGGBB"). public static string CTToHexRGB(this Color32 input) { return CTToHexRGB((Color)input); } /// /// Extension method for Color. /// Converts the value of a color to a RGB Hex-string. /// /// Color to convert. /// Color value as Hex (format "RRGGBB"). public static string CTToHexRGB(this Color input) { if (input == null) throw new System.ArgumentNullException(nameof(input)); string hexColor = ColorUtility.ToHtmlStringRGB(input); //if (hexColor.Length != 6) // Debug.LogError("HEX invalid: " + hexColor); return hexColor; /* Color32 color = input; string hexColor = $"{(color.r + 0x01):X2}{(color.g + 0x01):X2}{(color.b + 0x01):X2}"; Debug.LogWarning("HEX: " + hexColor); if (hexColor.Length != 6) Debug.LogError("HEX invalid: " + hexColor); return hexColor; */ } /// /// Extension method for Color32. /// Converts the value of a color to a RGBA Hex-string. /// /// Color to convert. /// Color value as Hex (format "RRGGBBAA"). public static string CTToHexRGBA(this Color32 input) { return CTToHexRGBA((Color)input); } /// /// Extension method for Color. /// Converts the value of a color to a RGBA Hex-string. /// /// Color to convert. /// Color value as Hex (format "RRGGBBAA"). public static string CTToHexRGBA(this Color input) { if (input == null) throw new System.ArgumentNullException(nameof(input)); return ColorUtility.ToHtmlStringRGBA(input); } /// /// Extension method for Color32. /// Convert it to a Vector3. /// /// Color-instance to convert. /// Vector3 from color. public static Vector3 CTVector3(this Color32 color) { return CTVector3((Color)color); } /// /// Extension method for Color. /// Convert it to a Vector3. /// /// Color-instance to convert. /// Vector3 from color. public static Vector3 CTVector3(this Color color) { if (color == null) throw new System.ArgumentNullException(nameof(color)); return new Vector3(color.r, color.g, color.b); } /// /// Extension method for Color32. /// Convert it to a Vector4. /// /// Color-instance to convert. /// Vector4 from color. public static Vector4 CTVector4(this Color32 color) { return CTVector4((Color)color); } /// /// Extension method for Color. /// Convert it to a Vector4. /// /// Color-instance to convert. /// Vector4 from color. public static Vector4 CTVector4(this Color color) { if (color == null) throw new System.ArgumentNullException(nameof(color)); return new Vector4(color.r, color.g, color.b, color.a); } #endregion #region Vector2 /// /// Allows you to multiply two Vector2s together, something Unity sorely lacks by default. /// /// First vector /// Second vector /// The ax*bx, ay*by result. public static Vector2 CTMultiply(this Vector2 a, Vector2 b) { return new Vector2(a.x * b.x, a.y * b.y); } #endregion #region Vector3 /// /// Allows you to multiply two Vector3s together, something Unity sorely lacks by default. /// /// First vector /// Second vector /// The ax*bx, ay*by, az*bz result. public static Vector3 CTMultiply(this Vector3 a, Vector3 b) { return new Vector3(a.x * b.x, a.y * b.y, a.z * b.z); } /// /// Returns a Vector3 with a 0 y-axis. This is useful for keeping entities oriented perpendicular to the ground. /// public static Vector3 CTFlatten(this Vector3 a) { return a.CTMultiply(FLAT_VECTOR); } /// /// Extension method for Vector3. /// Convert it to a Quaternion. /// /// Vector3-instance to convert. /// Quaternion from euler angles. public static Quaternion CTQuaternion(this Vector3 eulerAngle) { return Quaternion.Euler(eulerAngle); } /// /// Extension method for Vector3. /// Convert it to a Color. /// /// Vector3-instance to convert (RGB = xyz). /// Alpha-value of the color (optional, default: 1). /// Color from RGB. public static Color CTColorRGB(this Vector3 rgb, float alpha = 1f) { return new Color(Mathf.Clamp01(rgb.x), Mathf.Clamp01(rgb.y), Mathf.Clamp01(rgb.z), Mathf.Clamp01(alpha)); } #endregion #region Vector4 /// /// Allows you to multiply two Vector4s together, something Unity sorely lacks by default. /// /// First vector /// Second vector /// The ax*bx, ay*by, az*bz, aw*bw result. public static Vector4 CTMultiply(this Vector4 a, Vector4 b) { return new Vector4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); } /// /// Extension method for Vector4. /// Convert it to a Quaternion. /// /// Vector4-instance to convert. /// Quaternion from Vector4. public static Quaternion CTQuaternion(this Vector4 angle) { return new Quaternion(angle.x, angle.y, angle.z, angle.w); } /// /// Extension method for Vector4. /// Convert it to a Color. /// /// Vector4-instance to convert (RGBA = xyzw). /// Color from RGBA. public static Color CTColorRGBA(this Vector4 rgba) { return new Color(Mathf.Clamp01(rgba.x), Mathf.Clamp01(rgba.y), Mathf.Clamp01(rgba.z), Mathf.Clamp01(rgba.w)); } #endregion #region Quaternion /// /// Extension method for Quaternion. /// Convert it to a Vector3. /// /// Quaternion-instance to convert. /// Vector3 from Quaternion. public static Vector3 CTVector3(this Quaternion angle) { return angle.eulerAngles; } /// /// Extension method for Quaternion. /// Convert it to a Vector4. /// /// Quaternion-instance to convert. /// Vector4 from Quaternion. public static Vector4 CTVector4(this Quaternion angle) { return new Vector4(angle.x, angle.y, angle.z, angle.w); } #endregion #region Canvas /// /// Extension method for Canvas. /// Convert current resolution scale. /// /// Canvas to convert. /// Vector3 with the correct scale. public static Vector3 CTCorrectLossyScale(this Canvas canvas) { if (canvas == null) throw new System.ArgumentNullException(nameof(canvas)); if (!Application.isPlaying) return Vector3.one; if (canvas.renderMode == RenderMode.ScreenSpaceCamera) { UnityEngine.UI.CanvasScaler scaler = canvas.GetComponent(); if (scaler && scaler.enabled) { scaler.enabled = false; Vector3 before = canvas.GetComponent().lossyScale; scaler.enabled = true; Vector3 after = canvas.GetComponent().lossyScale; return new Vector3(after.x / before.x, after.y / before.y, after.z / before.z); } return Vector3.one; } return canvas.GetComponent().lossyScale; } #endregion #region RectTransform /// /// Extension method for RectTransform. /// Sets the local corners of a RectTransform to a given array. /// /// RectTransform-instance. /// Corners for the RectTransform. /// Relevant canvas. /// Inset from the corners (optional, default: 0). /// Automatically adjust scaling (optional, default: false). public static void CTGetLocalCorners(this RectTransform transform, Vector3[] fourCornersArray, Canvas canvas, float inset = 0, bool corrected = false) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); if (fourCornersArray == null) throw new System.ArgumentNullException(nameof(fourCornersArray)); if (canvas == null) throw new System.ArgumentNullException(nameof(canvas)); transform.GetLocalCorners(fourCornersArray); if (corrected) { Vector3 uis = canvas.CTCorrectLossyScale(); fourCornersArray[0].x /= uis.x; fourCornersArray[0].y /= uis.y; fourCornersArray[1].x /= uis.x; fourCornersArray[1].y /= uis.y; fourCornersArray[2].x /= uis.x; fourCornersArray[2].y /= uis.y; fourCornersArray[3].x /= uis.x; fourCornersArray[3].y /= uis.y; } if (inset != 0) { Vector3 uis = canvas.CTCorrectLossyScale(); fourCornersArray[0].x += inset * uis.x; fourCornersArray[0].y += inset * uis.y; fourCornersArray[1].x += inset * uis.x; fourCornersArray[1].y -= inset * uis.y; fourCornersArray[2].x -= inset * uis.x; fourCornersArray[2].y -= inset * uis.y; fourCornersArray[3].x -= inset * uis.x; fourCornersArray[3].y += inset * uis.y; } } /// /// Extension method for RectTransform. /// Returns the local corners of a RectTransform. /// /// RectTransform-instance. /// Relevant canvas. /// Inset from the corners (optional, default: 0). /// Automatically adjust scaling (optional, default: false). /// Array of the four local corners of the RectTransform. public static Vector3[] CTGetLocalCorners(this RectTransform transform, Canvas canvas, float inset = 0, bool corrected = false) { Vector3[] fourCornersArray = new Vector3[4]; CTGetLocalCorners(transform, fourCornersArray, canvas, inset, corrected); return fourCornersArray; } /// /// Extension method for RectTransform. /// Sets the world corners of a RectTransform to a given array. /// /// RectTransform-instance. /// Corners for the RectTransform. /// Relevant canvas. /// Inset from the corners (optional, default: 0). /// Automatically adjust scaling (optional, default: false). public static void CTGetScreenCorners(this RectTransform transform, Vector3[] fourCornersArray, Canvas canvas, float inset = 0, bool corrected = false) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); if (fourCornersArray == null) throw new System.ArgumentNullException(nameof(fourCornersArray)); if (canvas == null) throw new System.ArgumentNullException(nameof(canvas)); // if screen space overlay mode then world corners are already in screen space // if screen space camera mode then screen settings are in world and need to be converted to screen transform.GetWorldCorners(fourCornersArray); if (canvas.renderMode == RenderMode.ScreenSpaceCamera) { for (int ii = 0; ii < 4; ii++) { fourCornersArray[ii] = canvas.worldCamera.WorldToScreenPoint(fourCornersArray[ii]); fourCornersArray[ii].z = 0; } } if (corrected) { Vector3 uis = canvas.CTCorrectLossyScale(); fourCornersArray[0].x /= uis.x; fourCornersArray[0].y /= uis.y; fourCornersArray[1].x /= uis.x; fourCornersArray[1].y /= uis.y; fourCornersArray[2].x /= uis.x; fourCornersArray[2].y /= uis.y; fourCornersArray[3].x /= uis.x; fourCornersArray[3].y /= uis.y; } if (inset != 0) { Vector3 uis = canvas.CTCorrectLossyScale(); fourCornersArray[0].x += inset * uis.x; fourCornersArray[0].y += inset * uis.y; fourCornersArray[1].x += inset * uis.x; fourCornersArray[1].y -= inset * uis.y; fourCornersArray[2].x -= inset * uis.x; fourCornersArray[2].y -= inset * uis.y; fourCornersArray[3].x -= inset * uis.x; fourCornersArray[3].y += inset * uis.y; } } /// /// Extension method for RectTransform. /// Returns the screen (world) corners of a RectTransform. /// /// RectTransform-instance. /// Relevant canvas. /// Inset from the corners (optional, default: 0). /// Automatically adjust scaling (optional, default: false). /// Array of the four screen (world) corners of the RectTransform. public static Vector3[] CTGetScreenCorners(this RectTransform transform, Canvas canvas, float inset = 0, bool corrected = false) { Vector3[] fourCornersArray = new Vector3[4]; CTGetScreenCorners(transform, fourCornersArray, canvas, inset, corrected); return fourCornersArray; } /// /// Extension method for RectTransform. /// Returns the bounds of a RectTransform including the children. /// /// RectTransform to calculate the bounds. /// Scale of the UI (optional, default: 1.0). /// Bounds of the RectTransform. public static Bounds CTGetBounds(this RectTransform transform, float uiScaleFactor = 1f) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); //Debug.Log($"Root: {transform.anchoredPosition}"); Rect rect; Bounds bounds = new Bounds(transform.anchoredPosition, new Vector3((rect = transform.rect).width, rect.height, 0.0f) * uiScaleFactor); if (transform.childCount > 0) { foreach (Bounds childBounds in from RectTransform child in transform select new Bounds(child.anchoredPosition, new Vector3(child.rect.width, child.rect.height, 0.0f) * uiScaleFactor)) { bounds.Encapsulate(childBounds); } } return bounds; } /// /// Extension method for RectTransform. /// Sets the Left-property of a RectTransform. /// /// RectTransform to set the Left-property. /// Value for the Left-property. public static void CTSetLeft(this RectTransform transform, float value) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); transform.offsetMin = new Vector2(value, transform.offsetMin.y); } /// /// Extension method for RectTransform. /// Sets the Right-property of a RectTransform. /// /// RectTransform to set the Right-property. /// Value for the Right-property. public static void CTSetRight(this RectTransform transform, float value) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); transform.offsetMax = new Vector2(value, transform.offsetMax.y); } /// /// Extension method for RectTransform. /// Sets the Top-property of a RectTransform. /// /// RectTransform to set the Top-property. /// Value for the Top-property. public static void CTSetTop(this RectTransform transform, float value) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); transform.offsetMax = new Vector2(transform.offsetMax.x, value); } /// /// Extension method for RectTransform. /// Sets the Bottom-property of a RectTransform. /// /// RectTransform to set the Bottom-property. /// Value for the Bottom-property. public static void CTSetBottom(this RectTransform transform, float value) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); transform.offsetMin = new Vector2(transform.offsetMin.x, value); } /// /// Extension method for RectTransform. /// Gets the Left-property of a RectTransform. /// /// RectTransform to get the Left-property. /// Left-property of the RectTransform. public static float CTGetLeft(this RectTransform transform) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); return transform.offsetMin.x; } /// /// Extension method for RectTransform. /// Gets the Right-property of a RectTransform. /// /// RectTransform to get the Right-property. /// Right-property of the RectTransform. public static float CTGetRight(this RectTransform transform) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); return transform.offsetMax.x; } /// /// Extension method for RectTransform. /// Gets the Top-property of a RectTransform. /// /// RectTransform to get the Top-property. /// Top-property of the RectTransform. public static float CTGetTop(this RectTransform transform) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); return transform.offsetMax.y; } /// /// Extension method for RectTransform. /// Gets the Bottom-property of a RectTransform. /// /// RectTransform to get the Bottom-property. /// Bottom-property of the RectTransform. public static float CTGetBottom(this RectTransform transform) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); return transform.offsetMin.y; } /// /// Extension method for RectTransform. /// Gets the Left/Right/Top/Bottom-properties of a RectTransform. /// /// RectTransform to get the Left/Right/Top/Bottom-properties. /// Left/Right/Top/Bottom-properties of the RectTransform as Vector4. public static Vector4 CTGetLRTB(this RectTransform transform) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); Vector2 offsetMax; return new Vector4(transform.offsetMin.x, (offsetMax = transform.offsetMax).x, offsetMax.y, transform.offsetMin.y); } /// /// Extension method for RectTransform. /// Sets the Left/Right/Top/Bottom-properties of a RectTransform. /// /// RectTransform to set the Left/Right/Top/Bottom-properties. /// Left/Right/Top/Bottom-properties as Vector4. public static void CTSetLRTB(this RectTransform transform, Vector4 lrtb) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); transform.offsetMin = new Vector2(lrtb.x, lrtb.w); transform.offsetMax = new Vector2(lrtb.y, lrtb.z); } #endregion #region Component /// /// Extension method for Component. /// Recursively searches all children of a parent Component for specific named GameObjects /// /// Parent of the current children. /// Name of the GameObject. /// Maximal depth of the search (default 0, optional). /// List of GameObjects with the given name or empty list. public static System.Collections.Generic.List CTFindAll(this Component component, string name, int maxDepth = 0) { if (component == null) throw new System.ArgumentNullException(nameof(component)); if (name == null) throw new System.ArgumentNullException(nameof(name)); System.Collections.Generic.List children = new System.Collections.Generic.List(); System.Collections.Generic.List childrenTf = getAllChildren(component.transform, maxDepth); foreach (var child in childrenTf) { children.Add(child.gameObject); } return children.Where(child => child.name == name).ToList(); } /// /// Extension method for Component. /// Recursively searches all children of a parent Component for specific named GameObjects /// /// Parent of the current children. /// Name of the GameObject. /// List of GameObjects with the given name or empty list. public static System.Collections.Generic.List CTFindAll(this Component component, string name) where T : Component { if (component == null) throw new System.ArgumentNullException(nameof(component)); if (name == null) throw new System.ArgumentNullException(nameof(name)); T[] children = component.GetComponentsInChildren(); return children.Where(child => child.name == name).ToList(); } #endregion #region MonoBehaviour /// /// Extension method for MonoBehaviour. /// Recursively searches all children of a parent MonoBehaviour for specific named GameObject /// /// Parent of the current children. /// Name of the GameObject. /// GameObject with the given name or null. public static GameObject CTFind(this MonoBehaviour mb, string name) { if (mb == null) throw new System.ArgumentNullException(nameof(mb)); return mb.transform.CTFind(name).gameObject; } /// /// Extension method for MonoBehaviour. /// Recursively searches all children of a parent MonoBehaviour for specific named GameObject and returns a component. /// /// Parent of the current children. /// Name of the GameObject. /// Component with the given type or null. public static T CTFind(this MonoBehaviour mb, string name) { if (mb == null) throw new System.ArgumentNullException(nameof(mb)); return mb.transform.CTFind(name); } #endregion #region GameObject /// /// Extension method for GameObject. /// Recursively searches all children of a parent GameObject for specific named GameObject /// /// Parent of the current children. /// Name of the GameObject. /// GameObject with the given name or null. public static GameObject CTFind(this GameObject go, string name) { if (go == null) throw new System.ArgumentNullException(nameof(go)); return go.transform.CTFind(name).gameObject; } /// /// Extension method for GameObject. /// Recursively searches all children of a parent GameObject for specific named GameObject and returns a component. /// /// Parent of the current children. /// Name of the GameObject. /// Component with the given type or null. public static T CTFind(this GameObject go, string name) { if (go == null) throw new System.ArgumentNullException(nameof(go)); return go.transform.CTFind(name); } /// /// Extension method for GameObject. /// Returns the bounds of a GameObject including the children. /// /// GameObject to calculate the bounds. /// Bounds of the GameObject. public static Bounds CTGetBounds(this GameObject go) { if (go == null) throw new System.ArgumentNullException(nameof(go)); Renderer[] renderers = go.GetComponentsInChildren(); if (renderers.Length == 0) return new Bounds(go.transform.position, Vector3.zero); Bounds b = renderers[0].bounds; foreach (Renderer r in renderers) { b.Encapsulate(r.bounds); } return b; } #endregion #region Transform /// /// Extension method for Transform. /// Recursively searches all children of a parent transform for specific named transform /// /// Parent of the current children. /// Name of the transform. /// Transform with the given name or null. public static Transform CTFind(this Transform transform, string name) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); if (name == null) throw new System.ArgumentNullException(nameof(name)); return deepSearch(transform, name); } /// /// Extension method for Transform. /// Recursively searches all children of a parent transform for specific named transform and returns a component. /// /// Parent of the current children. /// Name of the transform. /// Component with the given type or null. public static T CTFind(this Transform transform, string name) { if (transform == null) throw new System.ArgumentNullException(nameof(transform)); Transform tf = transform.CTFind(name); return tf != null ? tf.gameObject.GetComponent() : default; } #endregion #region Sprite /// /// Extension method for Sprite. /// Converts a Sprite to a PNG byte-array. /// /// Sprite to convert. /// Converted Sprite as PNG byte-array. public static byte[] CTToPNG(this Sprite sprite) { if (sprite == null) throw new System.ArgumentNullException(nameof(sprite)); return sprite.texture.CTToPNG(); } /// /// Extension method for Sprite. /// Converts a Sprite to a JPG byte-array. /// /// Sprite to convert. /// Converted Sprite as JPG byte-array. public static byte[] CTToJPG(this Sprite sprite) { if (sprite == null) throw new System.ArgumentNullException(nameof(sprite)); return sprite.texture.CTToJPG(); } /// /// Extension method for Sprite. /// Converts a Sprite to a TGA byte-array. /// /// Sprite to convert. /// Converted Sprite as TGA byte-array. public static byte[] CTToTGA(this Sprite sprite) { if (sprite == null) throw new System.ArgumentNullException(nameof(sprite)); return sprite.texture.CTToTGA(); } /// /// Extension method for Sprite. /// Converts a Sprite to a EXR byte-array. /// /// Sprite to convert. /// Converted Sprite as EXR byte-array. public static byte[] CTToEXR(this Sprite sprite) { if (sprite == null) throw new System.ArgumentNullException(nameof(sprite)); return sprite.texture.CTToEXR(); } #endregion #region Texture /// /// Extension method for Texture. /// Converts a Texture to a PNG byte-array. /// /// Texture to convert. /// Converted Texture as PNG byte-array. public static byte[] CTToPNG(this Texture2D texture) { if (texture == null) throw new System.ArgumentNullException(nameof(texture)); return texture.EncodeToPNG(); } /// /// Extension method for Texture. /// Converts a Texture to a JPG byte-array. /// /// Texture to convert. /// Converted Texture as JPG byte-array. public static byte[] CTToJPG(this Texture2D texture) { if (texture == null) throw new System.ArgumentNullException(nameof(texture)); return texture.EncodeToJPG(); } /// /// Extension method for Texture. /// Converts a Texture to a TGA byte-array. /// /// Texture to convert. /// Converted Texture as TGA byte-array. public static byte[] CTToTGA(this Texture2D texture) { if (texture == null) throw new System.ArgumentNullException(nameof(texture)); return texture.EncodeToTGA(); } /// /// Extension method for Texture. /// Converts a Texture to a EXR byte-array. /// /// Texture to convert. /// Converted Texture as EXR byte-array. public static byte[] CTToEXR(this Texture2D texture) { if (texture == null) throw new System.ArgumentNullException(nameof(texture)); return texture.EncodeToEXR(); } /// /// Extension method for Texture. /// Converts a Texture to a Sprite. /// /// Texture to convert. /// Pixels per unit for the Sprite (optional, default: 100). /// Converted Texture as Sprite. public static Sprite CTToSprite(this Texture2D texture, float pixelsPerUnit = 100f) { if (texture == null) throw new System.ArgumentNullException(nameof(texture)); return Sprite.Create(texture, new Rect(0f, 0f, texture.width, texture.height), new Vector2(0.5f, 0.5f), pixelsPerUnit); } /// /// Extension method for Texture. /// Rotates a Texture by 90 degrees. /// /// Texture to rotate. /// Rotated Texture. public static Texture2D CTRotate90(this Texture2D texture) { if (texture == null) throw new System.ArgumentNullException(nameof(texture)); Color32[] origpix = texture.GetPixels32(0); Color32[] newpix = new Color32[texture.width * texture.height]; for (int cc = 0; cc < texture.height; cc++) { for (int rr = 0; rr < texture.width; rr++) { newpix[texture.width * texture.height - (texture.height * rr + texture.height) + cc] = origpix[texture.width * texture.height - (texture.width * cc + texture.width) + rr]; } } Texture2D newtex = new Texture2D(texture.height, texture.width, texture.format, false); newtex.SetPixels32(newpix, 0); newtex.Apply(); return newtex; } /// /// Extension method for Texture. /// Rotates a Texture by 180 degrees. /// /// Texture to rotate. /// Rotated Texture. public static Texture2D CTRotate180(this Texture2D texture) { if (texture == null) throw new System.ArgumentNullException(nameof(texture)); Color32[] origpix = texture.GetPixels32(0); Color32[] newpix = new Color32[texture.width * texture.height]; for (int ii = 0; ii < origpix.Length; ii++) { newpix[origpix.Length - ii - 1] = origpix[ii]; } Texture2D newtex = new Texture2D(texture.width, texture.height, texture.format, false); newtex.SetPixels32(newpix, 0); newtex.Apply(); return newtex; } /// /// Extension method for Texture. /// Rotates a Texture by 270 degrees. /// /// Texture to rotate. /// Rotated Texture. public static Texture2D CTRotate270(this Texture2D texture) { if (texture == null) throw new System.ArgumentNullException(nameof(texture)); Color32[] origpix = texture.GetPixels32(0); Color32[] newpix = new Color32[texture.width * texture.height]; int ii = 0; for (int cc = 0; cc < texture.height; cc++) { for (int rr = 0; rr < texture.width; rr++) { newpix[texture.width * texture.height - (texture.height * rr + texture.height) + cc] = origpix[ii]; ii++; } } Texture2D newtex = new Texture2D(texture.height, texture.width, texture.format, false); newtex.SetPixels32(newpix, 0); newtex.Apply(); return newtex; } /// /// Extension method for Texture. /// Convert a Texture to a Texture2D /// /// Texture to convert. /// Converted Texture2D. public static Texture2D CTToTexture2D(this Texture texture) { if (texture == null) throw new System.ArgumentNullException(nameof(texture)); return Texture2D.CreateExternalTexture( texture.width, texture.height, TextureFormat.RGB24, false, false, texture.GetNativeTexturePtr()); } #if CT_WEBCAM /// /// Extension method for WebCamTexture. /// Convert a WebCamTexture to a Texture2D /// /// WebCamTexture to convert. /// Converted Texture2D. public static Texture2D CTToTexture2D(this WebCamTexture texture) { if (texture == null) throw new System.ArgumentNullException(nameof(texture)); Texture2D texture2D = new Texture2D(texture.width, texture.height); if (texture.isPlaying) { Color32[] data = new Color32[texture.width * texture.height]; texture.GetPixels32(data); texture2D.SetPixels32(data, 0); texture2D.Apply(); } return texture2D; } #endif /// /// Extension method for Texture. /// Flips a Texture2D horizontally /// /// Texture to flip. /// Horizontally flipped Texture2D. public static Texture2D CTFlipHorizontal(this Texture2D texture) { Texture2D flipped = new Texture2D(texture.width, texture.height); int width = texture.width; int height = texture.height; for (int xx = 0; xx < width; xx++) { for (int yy = 0; yy < height; yy++) { flipped.SetPixel(width - xx - 1, yy, texture.GetPixel(xx, yy)); } } flipped.Apply(); return flipped; } /// /// Extension method for Texture. /// Flips a Texture2D vertically /// /// Texture to flip. /// Vertically flipped Texture2D. public static Texture2D CTFlipVertical(this Texture2D texture) { Texture2D flipped = new Texture2D(texture.width, texture.height); int width = texture.width; int height = texture.height; for (int xx = 0; xx < width; xx++) { for (int yy = 0; yy < height; yy++) { flipped.SetPixel(xx, height - yy - 1, texture.GetPixel(xx, yy)); } } flipped.Apply(); return flipped; } #endregion #region AudioSource /// /// Extension method for AudioSource. /// Determines if an AudioSource has an active clip. /// /// AudioSource to check. /// True if the AudioSource has an active clip. public static bool CTHasActiveClip(this AudioSource source) { if (source == null) return false; if (source.clip == null) return false; bool loop; int timeSamples; return (source.isPlaying || (loop = source.loop) || (!loop && (timeSamples = source.timeSamples) > 0 && timeSamples < source.clip.samples - 1024)); } #endregion #region C# specific #if (!UNITY_WSA && !UNITY_WEBGL && !UNITY_XBOXONE) || UNITY_EDITOR /// /// Extension method for Thread. /// Aborts a Thread safely and optional silently /// /// Thread to abort. /// Silently abort the Thread (optional, default: true). public static void CTAbort(this System.Threading.Thread thread, bool silent = true) { if (thread == null) return; if (thread.IsAlive) { try { thread.Abort(); } catch (System.Exception ex) { if (!silent) Debug.LogWarning(ex); } } } #endif #endregion #region Unity specific /// /// Extension method for Renderer. /// Determines if the renderer is visible from a certain camera. /// /// Renderer to test the visibility. /// Camera for the test. /// True if the renderer is visible by the given camera. public static bool CTIsVisibleFrom(this Renderer renderer, Camera camera) { if (renderer == null) throw new System.ArgumentNullException(nameof(renderer)); if (camera == null) throw new System.ArgumentNullException(nameof(camera)); Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera); return GeometryUtility.TestPlanesAABB(planes, renderer.bounds); } #endregion #region Private methods private static Transform deepSearch(Transform parent, string name) { Transform tf = parent.Find(name); if (tf != null) return tf; foreach (Transform child in parent) { tf = deepSearch(child, name); if (tf != null) return tf; } return null; } private static System.Collections.Generic.List getAllChildren(this Transform parent, int maxDepth = 0, System.Collections.Generic.List transformList = null, int depth = 0) { if (transformList == null) transformList = new System.Collections.Generic.List(); if (maxDepth != 0) depth++; if (depth <= maxDepth) { foreach (Transform child in parent) { transformList.Add(child); child.getAllChildren(maxDepth, transformList, depth); } } return transformList; } private static float bytesToFloat(byte firstByte, byte secondByte) { // convert two bytes to one short (little endian) and convert it to range from -1 to (just below) 1 return (short)((secondByte << 8) | firstByte) / Crosstales.Common.Util.BaseConstants.FLOAT_32768; } #endregion /* /// /// Perform a deep Copy of the object. /// /// The type of object being copied. /// The object instance to copy. /// The copied object. public static T Clone(this T source) { if (!typeof(T).IsSerializable) { throw new ArgumentException("The type must be serializable.", "source"); } // Don't serialize a null object, simply return the default for that object if (Object.ReferenceEquals(source, null)) { return default(T); } IFormatter formatter = new BinaryFormatter(); Stream stream = new MemoryStream(); using (stream) { formatter.Serialize(stream, source); stream.Seek(0, SeekOrigin.Begin); return (T)formatter.Deserialize(stream); } } */ /* /// /// Clone a List with elememts containing a copy constructor. /// /// List-instance to clone. /// Clones list. public static List CTClone(this List listToClone) where T : ICopyable { List newList = new List(listToClone.Count); listToClone.ForEach((item) => { newList.Add(new T(item)); }); return newList; //return listToClone.Select(item => (T)item.Clone()).ToList(); } */ /* public static string[] CTToUppercase(string[] array) { if (array == null || array.Length <= 0) throw new ArgumentNullException("array"); string[] result = new string[array.Length]; for (int ii = 0; ii < array.Length; ii++) { result[ii] = array[ii].ToUpper(); } return result; } public static string[] CTToLowercase(string[] array) { if (array == null || array.Length <= 0) throw new ArgumentNullException("array"); string[] result = new string[array.Length]; for (int ii = 0; ii < array.Length; ii++) { result[ii] = array[ii].ToLower(); } return result; } */ } } // © 2016-2023 crosstales LLC (https://www.crosstales.com)