using System;
using UnityEngine;
using Framework.Support;
namespace Framework.Services {
/// Manages and provides access to a game object holding the services
public static class ServiceContainer {
/// Name of the game object for game-wide services
public const string GlobalServicesGameObjectName = "Global";
/// Name of the game object for services limited to the scenes
public const string SessionServicesGameObjectName = "Session";
/// Name of the game object for services in the current scene
public const string SceneServicesGameObjectName = "Scene";
/// Retrieves or creates the service of the specified type
/// Component that will be created
/// Scope in which the service will be created
/// The requested component
public static TComponent GetOrCreateComponent(Scope scope)
where TComponent : MonoBehaviour {
GameObject container = GetOrCreate(scope);
TComponent component = container.GetComponent();
if(component == null) {
component = container.AddComponent();
}
return component;
}
/// Retrieves the services root for the specified scope
/// Scope for which the services root will be retrieved
/// The services root for the specified scope
public static GameObject GetOrCreate(Scope scope) {
switch(scope) {
case Scope.Scene: {
bool needDestroyer = GameObjectHelper.IsNullOrDestroyed(sceneServicesGameObject);
GameObject gameObject = getOrCreate(
SceneServicesGameObjectName, ref sceneServicesGameObject
);
if(needDestroyer) {
gameObject.AddComponent();
}
return gameObject;
}
case Scope.Session: {
return getOrCreate(SessionServicesGameObjectName, ref sessionServicesGameObject);
}
case Scope.Global: {
return getOrCreate(GlobalServicesGameObjectName, ref globalServicesGameObject);
}
default: {
throw new ArgumentException("Unsupported scope", "scope");
}
}
}
/// Kills all components in the specified scope
/// Scope in which components will be killed
public static void Kill(Scope scope) {
switch(scope) {
case Scope.Scene: {
kill(SceneServicesGameObjectName, ref sceneServicesGameObject);
break;
}
case Scope.Session: {
kill(SessionServicesGameObjectName, ref sessionServicesGameObject);
break;
}
case Scope.Global: {
kill(GlobalServicesGameObjectName, ref globalServicesGameObject);
break;
}
default: {
throw new ArgumentException("Unsupported scope", "scope");
}
}
}
/// Kills the specified service container
/// Name of the service container that will be killed
/// Field holding the cached service container
private static void kill(string name, ref GameObject cached) {
if(GameObjectHelper.IsNullOrDestroyed(cached)) {
GameObject servicesRoot = ServicesRoot.Get();
if(GameObjectHelper.IsNullOrDestroyed(servicesRoot)) {
return;
}
cached = GameObjectHelper.GetChildByName(servicesRoot, name);
if(GameObjectHelper.IsNullOrDestroyed(cached)) {
return;
}
}
GameObject.Destroy(cached);
cached = null;
}
/// Retrieves or creates a game object under the service root
/// The game object with the specified name
private static GameObject getOrCreate(string name, ref GameObject cached) {
if(GameObjectHelper.IsNullOrDestroyed(cached)) {
GameObject servicesRoot = ServicesRoot.GetOrCreate();
cached = GameObjectHelper.GetChildByName(servicesRoot, name);
if(GameObjectHelper.IsNullOrDestroyed(cached)) {
cached = new GameObject(name);
GameObjectHelper.SetAsChild(servicesRoot, cached);
}
}
return cached;
}
/// Game object in which scene-scoped services will be stored
private static GameObject sceneServicesGameObject;
/// Game object in which session-scoped services will be stored
private static GameObject sessionServicesGameObject;
/// Game object in which global services will be stored
private static GameObject globalServicesGameObject;
}
} // namespace Framework.Services