using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using StardewModdingAPI.Framework; namespace StardewModdingAPI { /// <summary>Provides general utility extensions.</summary> public static class Extensions { /********* ** Properties *********/ /// <summary>The backing field for <see cref="Random"/>.</summary> private static readonly Random _random = new Random(); /********* ** Accessors *********/ /// <summary>A pseudo-random number generator.</summary> public static Random Random { get { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.Random)}", "1.0", DeprecationLevel.Info); return Extensions._random; } } /********* ** Public methods *********/ /// <summary>Get whether the given key is currently being pressed.</summary> /// <param name="key">The key to check.</param> public static bool IsKeyDown(this Keys key) { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.IsKeyDown)}", "1.0", DeprecationLevel.Info); return Keyboard.GetState().IsKeyDown(key); } /// <summary>Get a random color.</summary> public static Color RandomColour() { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.RandomColour)}", "1.0", DeprecationLevel.Info); return new Color(Extensions.Random.Next(0, 255), Extensions.Random.Next(0, 255), Extensions.Random.Next(0, 255)); } /// <summary>Concatenate an enumeration into a delimiter-separated string.</summary> /// <param name="ienum">The values to concatenate.</param> /// <param name="split">The value separator.</param> [Obsolete("The usage of ToSingular has changed. Please update your call to use ToSingular<T>")] public static string ToSingular(this IEnumerable ienum, string split = ", ") { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.ToSingular)}", "0.39.3", DeprecationLevel.PendingRemoval); return ""; } /// <summary>Concatenate an enumeration into a delimiter-separated string.</summary> /// <typeparam name="T">The enumerated value type.</typeparam> /// <param name="ienum">The values to concatenate.</param> /// <param name="split">The value separator.</param> public static string ToSingular<T>(this IEnumerable<T> ienum, string split = ", ") { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.ToSingular)}", "1.0", DeprecationLevel.Info); //Apparently Keys[] won't split normally :l if (typeof(T) == typeof(Keys)) { return string.Join(split, ienum.ToArray()); } return string.Join(split, ienum); } /// <summary>Get whether the value can be parsed as a number.</summary> /// <param name="o">The value.</param> public static bool IsInt32(this object o) { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.IsInt32)}", "1.0", DeprecationLevel.Info); int i; return int.TryParse(o.ToString(), out i); } /// <summary>Get the numeric representation of a value.</summary> /// <param name="o">The value.</param> public static int AsInt32(this object o) { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.AsInt32)}", "1.0", DeprecationLevel.Info); return int.Parse(o.ToString()); } /// <summary>Get whether the value can be parsed as a boolean.</summary> /// <param name="o">The value.</param> public static bool IsBool(this object o) { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.IsBool)}", "1.0", DeprecationLevel.Info); bool b; return bool.TryParse(o.ToString(), out b); } /// <summary>Get the boolean representation of a value.</summary> /// <param name="o">The value.</param> public static bool AsBool(this object o) { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.AsBool)}", "1.0", DeprecationLevel.Info); return bool.Parse(o.ToString()); } /// <summary>Get a list hash calculated from the hashes of the values it contains.</summary> /// <param name="enumerable">The values to hash.</param> public static int GetHash(this IEnumerable enumerable) { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.GetHash)}", "1.0", DeprecationLevel.Info); var hash = 0; foreach (var v in enumerable) hash ^= v.GetHashCode(); return hash; } /// <summary>Cast a value to the given type. This returns <c>null</c> if the value can't be cast.</summary> /// <typeparam name="T">The type to which to cast.</typeparam> /// <param name="o">The value.</param> public static T Cast<T>(this object o) where T : class { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.Cast)}", "1.0", DeprecationLevel.Info); return o as T; } /// <summary>Get all private types on an object.</summary> /// <param name="o">The object to scan.</param> public static FieldInfo[] GetPrivateFields(this object o) { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.GetPrivateFields)}", "1.0", DeprecationLevel.Info); return o.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static); } /// <summary>Get metadata for a private field.</summary> /// <param name="t">The type to scan.</param> /// <param name="name">The name of the field to find.</param> public static FieldInfo GetBaseFieldInfo(this Type t, string name) { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.GetBaseFieldValue)}", "1.0", DeprecationLevel.Info); return t.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static); } /// <summary>Get the value of a private field.</summary> /// <param name="t">The type to scan.</param> /// <param name="o">The instance for which to get a value.</param> /// <param name="name">The name of the field to find.</param> public static T GetBaseFieldValue<T>(this Type t, object o, string name) where T : class { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.GetBaseFieldValue)}", "1.0", DeprecationLevel.Info); return t.GetBaseFieldInfo(name).GetValue(o) as T; } /// <summary>Set the value of a private field.</summary> /// <param name="t">The type to scan.</param> /// <param name="o">The instance for which to set a value.</param> /// <param name="name">The name of the field to find.</param> /// <param name="newValue">The value to set.</param> public static void SetBaseFieldValue<T>(this Type t, object o, string name, object newValue) where T : class { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.SetBaseFieldValue)}", "1.0", DeprecationLevel.Info); t.GetBaseFieldInfo(name).SetValue(o, newValue as T); } /// <summary>Get a copy of the string with only alphanumeric characters. (Numbers are not removed, despite the name.)</summary> /// <param name="st">The string to copy.</param> public static string RemoveNumerics(this string st) { Program.DeprecationManager.Warn($"{nameof(Extensions)}.{nameof(Extensions.RemoveNumerics)}", "1.0", DeprecationLevel.Info); var s = st; foreach (var c in s) { if (!char.IsLetterOrDigit(c)) s = s.Replace(c.ToString(), ""); } return s; } } }