forked from Shardstone/trail-into-darkness
154 lines
5.1 KiB
C#
154 lines
5.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using UnityEngine;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
|
|
namespace Jovian.Utilities {
|
|
/// <summary>
|
|
/// <b>Editor use-only.</b><br/>
|
|
/// Allows easy access between different instances. Supports 1 instance per type. <br/>
|
|
/// Add instances and retrieve elsewhere.<br/><br/>
|
|
/// Read more: https://en.wikipedia.org/wiki/Service_locator_pattern
|
|
/// </summary>
|
|
public static class EditorServiceLocator {
|
|
private sealed class ServiceNotFoundException : Exception {
|
|
public ServiceNotFoundException(Type type) : base($"ServiceNotFoundException. Type={type}") { }
|
|
}
|
|
|
|
private static Dictionary<Type, object> serviceContainer = new();
|
|
public static bool IsDirty { get; private set; }
|
|
|
|
#if UNITY_EDITOR
|
|
public static Dictionary<Type, object> ServiceContainer => serviceContainer;
|
|
#endif
|
|
|
|
[RuntimeInitializeOnLoadMethod]
|
|
public static void Init() {
|
|
serviceContainer = new();
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
[InitializeOnEnterPlayMode]
|
|
private static void Reset(EnterPlayModeOptions options) {
|
|
serviceContainer?.Clear();
|
|
IsDirty = true;
|
|
}
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Add an instance to the locator. Will throw an exception if a type already exists in the locator.
|
|
/// <seealso cref="AddOrReplace{T}"/>
|
|
/// </summary>
|
|
[Conditional("UNITY_EDITOR")]
|
|
public static void Add<T>(T service) {
|
|
#if UNITY_EDITOR
|
|
if (service == null) {
|
|
throw new NullReferenceException($"Service is null. Expected instance of type '{typeof(T)}'");
|
|
}
|
|
|
|
serviceContainer.Add(typeof(T), service);
|
|
IsDirty = true;
|
|
#else
|
|
UnityEngine.Debug.LogWarning($"EditorServiceLocator should not be used outside of the Editor");
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add an instance to the locator. Will replace any existing instance without an exception.
|
|
/// An alias for <see cref="Set{T}"/>
|
|
/// </summary>
|
|
[Conditional("UNITY_EDITOR")]
|
|
public static void AddOrReplace<T>(T service) {
|
|
Set(service);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add an instance to the locator. Will replace any existing instance without an exception.
|
|
/// An alias for <see cref="AddOrReplace{T}"/>
|
|
/// </summary>
|
|
[Conditional("UNITY_EDITOR")]
|
|
public static void Set<T>(T service) {
|
|
#if UNITY_EDITOR
|
|
if (service == null) {
|
|
throw new NullReferenceException($"Service is null. Expected instance of type '{typeof(T)}'");
|
|
}
|
|
|
|
serviceContainer[typeof(T)] = service;
|
|
IsDirty = true;
|
|
#else
|
|
UnityEngine.Debug.LogWarning($"EditorServiceLocator should not be used outside of the Editor");
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes any type matching the instance passed in from the locator. This is good practice.
|
|
/// </summary>
|
|
/// <param name="service"></param>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <exception cref="NullReferenceException"></exception>
|
|
[Conditional("UNITY_EDITOR")]
|
|
public static void Remove<T>(T service) {
|
|
#if UNITY_EDITOR
|
|
if (service == null) {
|
|
throw new NullReferenceException($"Service is null. Expected instance of type '{typeof(T)}'");
|
|
}
|
|
|
|
serviceContainer.Remove(typeof(T));
|
|
IsDirty = true;
|
|
#else
|
|
UnityEngine.Debug.LogWarning($"EditorServiceLocator should not be used outside of the Editor");
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves an instance from the locator matching the type. Will throw an exception if nothing is found.
|
|
/// <seealso cref="TryGet{T}(out T)"/>
|
|
/// </summary>
|
|
public static T Get<T>() {
|
|
#if UNITY_EDITOR
|
|
if (serviceContainer.TryGetValue(typeof(T), out object service)) {
|
|
return (T)service;
|
|
}
|
|
#endif
|
|
throw new ServiceNotFoundException(typeof(T));
|
|
}
|
|
|
|
[Obsolete("Use Get<T> or TryGet<T>(out T) since they follow the C# conventions for TryGet")]
|
|
public static T TryGet<T>() {
|
|
#if UNITY_EDITOR
|
|
if (serviceContainer.TryGetValue(typeof(T), out object service)) {
|
|
return (T)service;
|
|
}
|
|
#endif
|
|
return default;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves an instance from the locator matching the type. Returns true/false based on success.
|
|
/// </summary>
|
|
public static bool TryGet<T>(out T instance) {
|
|
#if UNITY_EDITOR
|
|
if (serviceContainer.TryGetValue(typeof(T), out object service)) {
|
|
instance = (T)service;
|
|
return instance != null;
|
|
}
|
|
#endif
|
|
instance = default;
|
|
return false;
|
|
}
|
|
|
|
[Conditional("UNITY_EDITOR")]
|
|
public static void Clear() {
|
|
serviceContainer.Clear();
|
|
IsDirty = true;
|
|
}
|
|
|
|
[Conditional("UNITY_EDITOR")]
|
|
public static void Clean() {
|
|
IsDirty = false;
|
|
}
|
|
}
|
|
} |