Provides a helper method for instantiating all types within the app domain that implement an interface

/// <summary>
/// Initializes a collection of types that implement an interface.
/// </summary>
/// <typeparam name="T">The interface type to check for.</typeparam>
/// <param name="loadingErrors">The loading errors that may have occurred.</param>
/// <returns>A list of type <see cref="T"/>.</returns>
public IEnumerable<T> GetPlugins<T>(out IEnumerable<Exception> loadingErrors)
{
    // search for types in each assembly that implement the type
    var fullName = typeof(T).FullName;
    var list = new List<T>();
    var errors = new List<Exception>();

    // search through all assemblies
    foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
    {
        // search through all types
        foreach (var type in asm.GetTypes())
        {
            // ignore abstract classes
            if (type.IsAbstract)
            {
                continue;
            }

            // get interfaces that the type implements
            foreach (var inter in type.GetInterfaces())
            {
                try
                {
                    // check if type implements interface
                    if (string.CompareOrdinal(inter.FullName, fullName) == 0)
                    {
                        // create/add type to list
                        var obj = asm.CreateInstance(type.FullName);
                        var instance = (T)obj;
                        list.Add(instance);
                    }
                }
                catch (Exception ex)
                {
                    // record error
                    errors.Add(ex);
                }
            }
        }
    }

    loadingErrors = errors;
    return list;
}

/// <summary>
/// Determines whether the renderer is visible from the specified camera.
/// </summary>
/// <param name="renderer">The renderer to check for visibility.</param>
/// <param name="camera">The camera to check against.</param>
/// <returns>true if the renderer is visible to the camera; otherwise false.</returns>
public static bool IsVisibleFrom(this Renderer renderer, Camera camera)
{
    var planes = GeometryUtility.CalculateFrustumPlanes(camera);
    return GeometryUtility.TestPlanesAABB(planes, renderer.bounds);
}

Will try to fetch then remove an item at index, returning true if succeeded.

/// <summary>Retrieves and removes an item from the list.</summary>
/// <typeparam name="T">The type that the generic list contains.</typeparam>
/// <param name="list">The list.</param>
/// <param name="index">The index of the item to be pulled out of the list.</param>
/// <param name="value">The value that was retrieved from the list.</param>
/// <returns>true if successful; otherwise false.</returns>
public static bool TryPullItemAt<T>(this IList<T> list, int index, out T value)
{
    try
    {
        value = list[index];
        list.RemoveAt(index);
        return true;
    }
    catch
    {
        value = default(T);
        return false;
    }
}

The code below allows you to set and automatically restore the GUI.enabled state when used with a using block similar to GUILayout.HorizontialScope.

/// <summary>
/// Provides  a class for setting and restoring GUI.enabled.
/// </summary>
public class GuiEnabled : IDisposable
{
    /// <summary>
    /// Gets or sets a value indicating the state that is to be restored.
    /// </summary>  
    public bool StateToBeRestored { get; set; }

    /// <summary>
    /// Initializes a new instance of the <see cref="GuiEnabled"/> class.
    /// </summary>
    /// <param name="stateToBeRestored">Value indicating the state that is to be restored.</param>
    public GuiEnabled(bool stateToBeRestored)                                            
    {
        this.StateToBeRestored = stateToBeRestored;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="GuiEnabled"/> class.
    /// </summary>
    /// <param name="stateToBeRestored">If set to <c>true</c> the GUI.enabled state will be restored to this value.</param>
    /// <param name="setState">Immediatley sets the value of GUI.enabled to this state.</param>
    public GuiEnabled(bool stateToBeRestored, bool setState) : this(stateToBeRestored)
    {
        GUI.enabled = setState;
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
        GUI.enabled = this.StateToBeRestored;
    }
}

Here is an simple use case

GUILayout.Button("Enabled button");
using (var enabled = new GuiEnabled(GUI.enabled, false))
{
    GUILayout.Button("Disabled button");
    //if (someCondition)
    //{   
        // setting to false means after we exit the using block GUI.enabled will be set to false. 
    //    enabled.StateToBeRestored = false; 
    //}
}
GUILayout.Button("Enabled button");

Provides a helper method for determining weather two value ranges intersect.

LINQPad v4 C# sample RangeIntersection.linq (5.18 kb)

/// <summary>
/// Check for the intersection between two sets of ranges.
/// </summary>
/// <param name="range1Start">The start of the first range.</param>
/// <param name="range1End">The end of the first reage.</param>
/// <param name="range2Start">The start of the second range.</param>
/// <param name="range2End">The end of the second range.</param>
/// <returns>true if the two ranges intersect with each other; otherwise false.</returns>
public static bool RangeIntersection(int range1Start, int range1End, int range2Start, int range2End)
{
    var r1Start = range1Start;
    var r1End = range1End;
    var r2Start = range2Start;
    var r2End = range2End;

    if (range1Start > range1End)
    {
        r1Start = range1End;
        r1End = range1Start;
    }

    if (range2Start > range2End)
    {
        r2Start = range2End;
        r2End = range2Start;
    }

    var greatestStart = r1Start > r2Start ? r1Start : r2Start;
    var smallestEnd = r1End < r2End ? r1End : r2End;
    return !(greatestStart > smallestEnd);
}

RangeChecking


        /// <summary>Retrieves and removes an item from the list.</summary>
        /// <typeparam name="T">The type that the generic list contains.</typeparam>
        /// <param name="list">The list.</param>
        /// <param name="index">The index of the item to be pulled out of the list.</param>
        public static T PullItemAt<T>(this IList<T> list, int index)
        {
            var item = list[index];
            list.RemoveAt(index);
            return item;
        }

/// <summary>
/// Adds items to a <see cref="ObservableCollection{T}"/>.
/// </summary>
/// <typeparam name="T">The generic type that the generic observable collection stores.</typeparam>
/// <param name="list">The list where items will be added to.</param>
/// <param name="items">The items to be added.</param>
public static void AddRange<T>(this ObservableCollection<T> list, IEnumerable<T> items)
{
    foreach (var item in items)
    {
        list.Add(item);
    }
}

/// <summary>
/// Tries to get a value from the generic list.
/// </summary>
/// <typeparam name="T">The type that the generic list contains.</typeparam>
/// <param name="list">The generic list reference.</param>
/// <param name="predicate">The predicate used to find the desired element.</param>
/// <param name="item">The item to be returned if the <see cref="predicate"/> argument finds a match.</param>
/// <returns>true if a item was found; otherwise false.</returns>
public static bool TryGet<T>(this IList<T> list, Func<T, bool> predicate, out T item)
{
    var result = list.Where(predicate).ToArray();
    item = result.FirstOrDefault();
    return result.Length != 0;
}

/// <summary>
/// Tries to get a value from the generic list.
/// </summary>
/// <typeparam name="T">The type that the generic list contains.</typeparam>
/// <typeparam name="S">The type that the selector function will return.</typeparam>
/// <param name="list">The generic list reference.</param>
/// <param name="predicate">The predicate used to find the desired element.</param>
/// <param name="selector">The selector function used to retrieve a value from the matched item. determined by the <see cref="predicate"/> argument.</param>
/// <param name="item">The item to be returned if the <see cref="predicate"/> argument finds a match.</param>
/// <returns>true if a item was found; otherwise false.</returns>
public static bool TryGet<T, S>(this IList<T> list, Func<T, bool> predicate, Func<T, S> selector, out S item)
{
    var result = list.Where(predicate).ToArray();
    item = selector(result.FirstOrDefault());
    return result.Length != 0;
}

When writing editor scripts involving EditorWindow’s it is often important to initialize and cleanup your code when the window is shown and hidden. Specifically it is important to differentiate between the OnDisable and OnDestroy methods if you need to perform some kind of cleanup before the window is closed or disposed of. OnDestroy is called when the user closes the window, where as OnDisable is called after unity recompiles scripts. Think of the OnDestroy method as a close event for the window but the window still resides in memory, where the OnDisable method signals that the window is about to be unloaded from memory such as during a script recompile.

This differentiation is important when you need to save data to disk before the window is destroyed during a recompile. OnDestroy will not get called during recompile only OnDisable does. The OnEnable method is typically intended as a initialization method where you can load data related to the window.

I only wish the Unity team had made these methods more descriptive ala .NET window forms naming scheme. OnDestroy & OnDisable are not the most descriptive for what they do as well as being somewhat similar in spelling. But I digress.


public static string GetMD5HashFromFile(string fileName)
{
    byte[] retVal;
    using (var file = new FileStream(fileName, FileMode.Open))
    {
        var md5 = new MD5CryptoServiceProvider();
        retVal = md5.ComputeHash(file);
    }

    var sb = new StringBuilder();
    for (var i = 0; i < retVal.Length; i++)
    {
        sb.Append(retVal[i].ToString("x2"));
    }

    return sb.ToString();
}

Created by: X

Just another personal website in this crazy online world

Name of author Dean Lunz (aka Created by: X)
Computer programming nerd, and tech geek.
About Me -- Resume