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)