Website may be up and down over next few months. I'm currently doing a complete overhaul of everything. Going back to simple individual .htm pages, new overall site theme, sanitizing and cleaning up html of all pages and blog posts, attempting to implement a new tooling and publishing system etc etc.

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();
}

A simple performance test for comparing direct file property access or creating a FileInfo object.

The results show that if you are accessing more then one file property FileInfo is the way to go otherwise File.GetCreationTime and related methods have the same performance hit.

100 iterations of c:\windows
directValues –> 00:00:00.2900065
infoValues –> 00:00:00.1611554

void Main()
{
    var folder = "c:\\windows";
    var files = Directory.GetFiles(folder, "*.*", SearchOption.TopDirectoryOnly);

    var stopwatch = new Stopwatch();
    var directValues = 0l;
    var infoValues = 0l;
    for (int i = 0; i < 100; i++)
    {
        stopwatch.Restart();
        stopwatch.Start();
        foreach (var file in files)
        {
            var lastWriteTime = File.GetLastWriteTime(file);
            var creationTime = File.GetCreationTime(file);
        }

        stopwatch.Stop();
        directValues += stopwatch.ElapsedTicks;

        stopwatch.Restart();
        stopwatch.Start();
        foreach (var file in files)
        {
            var info = new FileInfo(file);
            var lastWriteTime = info.LastWriteTime;
            var creationTime = info.CreationTime;
        }

        stopwatch.Stop();
        infoValues += stopwatch.ElapsedTicks;

    }

    "100 iterations of c:\\windows".Dump();
    TimeSpan.FromTicks(directValues).Dump("directValues");
    TimeSpan.FromTicks(infoValues).Dump("infoValues");
}

Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only

/// <summary>Determines whether a value in within a certain range.</summary>
/// <param name="value">The value.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <returns>True if the value is in range.</returns>
public static bool IsInRange(this BaseType value, BaseType min, BaseType max)
{
    return value >= min && value <= max;
}

/// <summary>Determines whether a value in within a certain range.</summary>
/// <param name="value">The value.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <param name="throwException">if set to <c>true</c> will throw a <see cref="IndexOutOfRangeException"/> if the value is out of range.</param>
/// <returns>True if the value is in range.</returns>
/// <exception cref="System.IndexOutOfRangeException">Is thrown if the value is out of range.</exception>
public static bool IsInRange(this BaseType value, BaseType min, BaseType max, bool throwException)
{
    if (!(value >= min && value <= max) && throwException)
    {
        throw new IndexOutOfRangeException();
    }

    return true;
}

/// <summary>Determines whether a value in within a certain range.</summary>
/// <param name="value">The value.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <param name="throwException">if set to <c>true</c> will throw a <see cref="IndexOutOfRangeException"/> if the value is out of range.</param>
/// <param name="message">The message for the <see cref="IndexOutOfRangeException"/> if it is thrown.</param>
/// <returns>True if the value is in range.</returns>
/// <exception cref="System.IndexOutOfRangeException">Is thrown if the value is out of range.</exception>
public static bool IsInRange(this BaseType value, BaseType min, BaseType max, bool throwException, string message)
{
    if (!(value >= min && value <= max) && throwException)
    {
        throw new IndexOutOfRangeException(message);
    }

    return true;
}

When compiling your Unity games & applications to different platforms, there may be times when you need to get the location of special folder locations on the system that your app is running on.

The Environment.GetFolderPath method can be use to retrieve those specific folder locations. Below is a list of folder locations for both Windows 7 and Mac OS X. The source of this information is available here along with code examples.


Desktop (0)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) /Users/yourname/Desktop
Windows7.gif Windows 7 C:\Users\yourname\Desktop

Programs (2)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) n/a
Windows7.gif Windows 7 C:\Users\yourname\AppData\Roaming\Microsoft\Windows\Start Menu\Programs

Personal (5)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) /Users/yourname
Windows7.gif Windows 7 C:\Users\yourname\Documents

MyDocuments (5)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) /Users/yourname
Windows7.gif Windows 7 C:\Users\yourname\Documents

Favorites (6)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) /Users/yourname/Library/Favorites
Windows7.gif Windows 7 C:\Users\yourname\Favorites

Startup (7)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) n/a
Windows7.gif Windows 7 C:\Users\yourname\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

Recent (8)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) n/a
Windows7.gif Windows 7 C:\Users\yourname\AppData\Roaming\Microsoft\Windows\Recent

SendTo (9)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) n/a
Windows7.gif Windows 7 C:\Users\yourname\AppData\Roaming\Microsoft\Windows\SendTo

StartMenu (11)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) n/a
Windows7.gif Windows 7 C:\Users\yourname\AppData\Roaming\Microsoft\Windows\Start Menu

MyMusic (13)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) /Users/yourname/Music
Windows7.gif Windows 7 C:\Users\yourname\Music

DesktopDirectory (16)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) /Users/yourname/Desktop
Windows7.gif Windows 7 C:\Users\yourname\Desktop

MyComputer (17)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) n/a
Windows7.gif Windows 7 n/a

Templates (21)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) /Users/yourname/Templates
Windows7.gif Windows 7 C:\Users\yourname\AppData\Roaming\Microsoft\Windows\Templates

ApplicationData (26)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) /Users/yourname/.config
Windows7.gif Windows 7 C:\Users\yourname\AppData\Roaming

LocalApplicationData (28)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) /Users/username/.local/share (inside unity)
/Applications/Unity/MonoDevelop.app/Contents/MacOS/../Frameworks/Mono.framework/Versions/Current/share
Windows7.gif Windows 7 C:\Users\yourname\AppData\Local

InternetCache (32)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) /Users/yourname/Library/Caches
Windows7.gif Windows 7 C:\Users\yourname\AppData\Local\Microsoft\Windows\Temporary Internet Files

Cookies (33)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) n/a
Windows7.gif Windows 7 C:\Users\yourname\AppData\Roaming\Microsoft\Windows\Cookies

History (34)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) n/a
Windows7.gif Windows 7 C:\Users\yourname\AppData\Local\Microsoft\Windows\History

CommonApplicationData (35)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) /usr/share
Windows7.gif Windows 7 C:\ProgramData

System (37)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) n/a
Windows7.gif Windows 7 C:\Windows\system32

ProgramFiles (38)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) /Applications
Windows7.gif Windows 7 C:\Program Files
or C:\Program Files (x86)

MyPictures (39)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) /Users/yourname/Pictures
Windows7.gif Windows 7 C:\Users\yourname\Pictures

CommonProgramFiles (43)
Apple.gif Mac OS X 10.6.8 (Snow Leopard) n/a
Windows7.gif Windows 7 C:\Program Files\Common Files
or C:\Program Files (x86)\Common Files

Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only

/// <summary>
/// Clamps the specified value.
/// </summary>
/// <param name="value">The value to be clamped.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <returns>The clamped value.</returns>
public static BaseType Clamp(this BaseType value, BaseType min, BaseType max)
{
    if (value < min)
    {
        return min;
    }

    if (value > max)
    {
        return max;
    }

    return value;
}

Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only

/// <summary>
/// Determines weather or not all the characters in a string are all the same.
/// </summary>
/// <param name="value">The value to check for.</param>
/// <returns>true is all characters are the same, otherwise false.</returns>
public static bool AllTheSame(this string value)
{
#if UNITY3D
    if (!StringExtensionMethods.IsNullOrWhiteSpace(value))
#else
    if (!string.IsNullOrWhiteSpace(value))
#endif
    {
        var clone = new string(value[0], value.Length);
        return clone == value;
    }

    return false;
}

#if UNITY3D
public static bool IsNullOrWhiteSpace(this string value)
{
    if (value == null)
    {
        return true;
    }

    for (var i = 0; i < value.Length; i++)
    {
        if (!char.IsWhiteSpace(value[i]))
        {
            return false;
        }
    }

    return true;
}
#endif
}

Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only

namespace System.Collections
{
    /// <summary>
    /// Provides extension methods for the IList interface.
    /// </summary>
    public static class IListExtensionMethods
    {
        /// <summary>Swaps the specified items in a list.</summary>
        /// <param name="list">The list.</param>
        /// <param name="indexA">The index of item A.</param>
        /// <param name="indexB">The index of item B.</param>
        /// <param name="remove">If set to <c>true</c> items will be removed and re-inserted.</param>
        public static void Swap(this IList list, int indexA, int indexB, bool remove)
        {
            if (indexA == indexB)
            {
                return;
            }

            indexA.IsInRange(0, list.Count - 1, true, "indexA is out of range.");
            indexB.IsInRange(0, list.Count - 1, true, "indexB is out of range.");

            if (remove)
            {
                var first = Math.Min(indexA, indexB);
                var second = Math.Max(indexA, indexB);
                
                var tempA = list[first];
                var tempB = list[second];

                list.RemoveAt(second);
                list.RemoveAt(first);
               
                list.Insert(first, tempB);
                list.Insert(second, tempA);
            }
            else
            {
                var temp = list[indexA];
                list[indexA] = list[indexB];
                list[indexB] = temp;
            }
        }

        /// <summary>Swaps the specified items in a list.</summary>
        /// <param name="list">The list.</param>
        /// <param name="indexA">The index of item A.</param>
        /// <param name="indexB">The index of item B.</param>
        /// <remarks>Items are swapped and not removed or inserted.</remarks>
        public static void Swap(this IList list, int indexA, int indexB)
        {
            Swap(list, indexA, indexB, false);
        }

        /// <summary>Swaps the specified items in a list and return true if successful.</summary>
        /// <param name="list">The list.</param>
        /// <param name="indexA">The index of item A.</param>
        /// <param name="indexB">The index of item B.</param>
        /// <remarks>Items are swapped and not removed or inserted.</remarks>
        /// <returns>true if successful.</returns>
        public static bool TrySwap(this IList list, int indexA, int indexB)
        {
            try
            {
                Swap(list, indexA, indexB);
            }
            catch
            {
                return false;
            }

            return true;
        }

        /// <summary>Swaps the specified items in a list and return true if successful.</summary>
        /// <param name="list">The list.</param>
        /// <param name="indexA">The index of item A.</param>
        /// <param name="indexB">The index of item B.</param>
        /// <param name="remove">If set to <c>true</c> items will be removes and re-inserted.</param>
        /// <returns>true if successful.</returns>
        public static bool TrySwap(this IList list, int indexA, int indexB, bool remove)
        {
            try
            {
                Swap(list, indexA, indexB, remove);
            }
            catch
            {
                return false;
            }

            return true;
        }
    }
}

Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only

/// <summary>
/// Removes a range of entries inside an array.
/// </summary>
/// <typeparam name="T">Specifies the generic type of the array.</typeparam>
/// <param name="array">The destination array.</param>
/// <param name="index">The start index where entries will be removed from.</param>
/// <param name="length">The number of entries to be removed.</param>
/// <returns>
/// Returns the resized and updated destination array.
/// </returns>
/// <exception cref="ArgumentOutOfRangeException">index</exception>
public static T[] RemoveRange<T>(this T[] array, int index, int length)
{
    if (length < 1)
    {
        return array;
    }

    if (index < 0 || index > array.Length - 1)
    {
        throw new ArgumentOutOfRangeException("index");
    }

    if (index + length > array.Length - 1)
    {
        Array.Resize(ref array, index);
        return array;
    }

    var endLength = Math.Max(0, Math.Min(array.Length - index, array.Length - (index + length)));
    var tempArray = new T[endLength];
    Array.Copy(array, index + length, tempArray, 0, endLength);
    Array.Resize(ref array, array.Length - length);
    tempArray.CopyTo(array, array.Length - endLength);
    return array;
}

Full repo available at https://bitbucket.org/createdbyx/codefarts.utilities-extension-methods-only

/// <summary>
/// Moves the specified entries in the array by a set ammount.
/// </summary>
/// <typeparam name="T">Specifies the generic type of the array.</typeparam>
/// <param name="array">The destination array.</param>
/// <param name="index">The start index where entries will be moved from.</param>
/// <param name="length">The number of entries to be moved.</param>
/// <param name="shift">The ammount and direction to move the specified entries.</param>
/// <returns>
/// Returns the resized and updated destination array.
/// </returns>
/// <exception cref="ArgumentOutOfRangeException">length;'length' argument must be greater then 0.</exception>
/// <remarks><p>To move entries to the left (towards 0) specify a negative shift value and a positive shift value to move entries to the right.</p>
/// <example>
/// <code>
/// var items = new[] { 0, 1, 2, 3, 4 };
/// items = items.Move(3, 2, -1);
/// </code>
/// Result should be { 0, 1, 3, 4, 4 }
/// </example></remarks>
public static T[] Move<T>(this T[] array, int index, int length, int shift)
{
    if (length <= 0)
    {
        throw new ArgumentOutOfRangeException("length", "'length' argument must be greater then 0.");
    }

    if (shift > 0 && index + length + shift > array.Length - 1)
    {
        Array.Resize(ref array, array.Length + (index + length + shift - array.Length));
    }

    if (index + shift < 0)
    {
        length += index + shift;
        index = -(index + shift);
    }

    length = Math.Min(array.Length - index, length);
    if (length > 0)
    {
        Array.Copy(array, index, array, index + shift, length);
    }        

    return array;
}

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