This code is designed to hook into unity’s EditorApplication.update delegate.
IRun.cs
namespace CBX.CoreProjectCode.Interfaces
{
using CBX.CoreProjectCode.Models;
/// <summary>
/// Provides a interface for running a <see cref="CallbackModel{T}"/> type.
/// </summary>
public interface IRun
{
/// <summary>
/// Runs the <see cref="CallbackModel{T}"/> type.
/// </summary>
void Run();
}
}
CallbackModel.cs
namespace CBX.CoreProjectCode.Models
{
using System;
using CBX.CoreProjectCode.Interfaces;
/// <summary>
/// Provides a modal for callbacks.
/// </summary>
/// <typeparam name="T">The generic type used to represent the data type.</typeparam>
public class CallbackModel<T> : IRun
{
/// <summary>
/// A reference to a callback method.
/// </summary>
public Action<T> Callback;
/// <summary>
/// A reference to some data that will be passed to the callback method.
/// </summary>
public T Data;
/// <summary>
/// Implements <see cref="IRun.Run"/> to run the callback.
/// </summary>
public void Run()
{
this.Callback(this.Data);
}
}
}
EditorCallbackService.cs
namespace CBX.CoreProjectCode.Services
{
using System;
using System.Collections.Generic;
using CBX.CoreProjectCode.Interfaces;
using CBX.CoreProjectCode.Models;
/// <summary>
/// The editor callback service.
/// </summary>
public class EditorCallbackService
{
/// <summary>
/// Holds a singleton instance of the <see cref="EditorCallbackService"/> type.
/// </summary>
private static EditorCallbackService service;
/// <summary>
/// Holds a list of <see cref="CallbackModel{T}"/> types that implement <see cref="IRun"/>.
/// </summary>
private readonly Stack<IRun> callbacks;
/// <summary>
/// Initializes a new instance of the <see cref="EditorCallbackService"/> class.
/// </summary>
public EditorCallbackService()
{
this.callbacks = new Stack<IRun>();
}
/// <summary>
/// Returns a singleton instance of the <see cref="EditorCallbackService"/> type.
/// </summary>
public static EditorCallbackService Instance
{
get
{
// if no service yet exists create one
return service ?? (service = new EditorCallbackService());
}
}
/// <summary>
/// Runs any callbacks that have been registered.
/// </summary>
public void Run()
{
while (this.callbacks.Count > 0)
{
var cb = this.callbacks.Pop();
cb.Run();
}
}
/// <summary>
/// Registers a <see cref="Action{T}"/> callback.
/// </summary>
/// <typeparam name="T">The type of data that the <see cref="callback"/> takes as a parameter.</typeparam>
/// <param name="callback">A reference to a callback.</param>
public void Register<T>(Action<T> callback)
{
this.Register(callback, default(T));
}
/// <summary>
/// Registers a <see cref="Action{T}"/> callback.
/// </summary>
/// <typeparam name="T">
/// The type of data that the <see cref="callback"/> takes as a parameter.
/// </typeparam>
/// <param name="callback">
/// A reference to a callback.
/// </param>
/// <param name="data">
/// The data that will be passed as a parameter when the <see cref="callback"/> is invoked.
/// </param>
public void Register<T>(Action<T> callback, T data)
{
if (callback == null)
{
throw new ArgumentNullException("callback");
}
var modal = new CallbackModel<T> { Callback = callback, Data = data };
this.callbacks.Push(modal);
}
/// <summary>
/// Registers a <see cref="Action"/> callback.
/// </summary>
/// <param name="callback">A reference to a callback.</param>
public void Register(Action callback)
{
this.Register<object>(x => callback(), null);
}
}
}
Usage scenario …
[InitializeOnLoad]
public class EditorInitialization
{
/// <summary>
/// Holds a value indicating whether the RunCallbacks method has been called at least once before.
/// </summary>
private static bool ranOnce;
/// <summary>
/// Initializes static members of the <see cref="EditorInitialization"/> class.
/// </summary>
static EditorInitialization()
{
EditorApplication.update += RunCallbacks;
}
private static void RunCallbacks()
{
if (!ranOnce)
{
// setup the settings system
SetupSettings();
// load localization strings
LoadLocalizationData();
ranOnce = true;
return;
}
// invoke callbacks from editor callback service
EditorCallbackService.Instance.Run();
}
}