421 lines
16 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using UnityEngine;
using VContainer.Internal;
#if VCONTAINER_ECS_INTEGRATION
using Unity.Entities;
#endif
namespace VContainer.Unity
{
public readonly struct EntryPointsBuilder
{
public static void EnsureDispatcherRegistered(IContainerBuilder containerBuilder)
{
if (containerBuilder.Exists(typeof(EntryPointDispatcher), false)) return;
containerBuilder.Register<EntryPointDispatcher>(Lifetime.Scoped);
containerBuilder.RegisterEntryPointExceptionHandler(UnityEngine.Debug.LogException);
containerBuilder.RegisterBuildCallback(container =>
{
container.Resolve<EntryPointDispatcher>().Dispatch();
});
}
readonly IContainerBuilder containerBuilder;
readonly Lifetime lifetime;
public EntryPointsBuilder(IContainerBuilder containerBuilder, Lifetime lifetime)
{
this.containerBuilder = containerBuilder;
this.lifetime = lifetime;
}
public RegistrationBuilder Add<T>()
=> containerBuilder.Register<T>(lifetime).AsImplementedInterfaces();
public void OnException(Action<Exception> exceptionHandler)
=> containerBuilder.RegisterEntryPointExceptionHandler(exceptionHandler);
}
public readonly struct ComponentsBuilder
{
readonly IContainerBuilder containerBuilder;
readonly Transform parentTransform;
public ComponentsBuilder(IContainerBuilder containerBuilder, Transform parentTransform = null)
{
this.containerBuilder = containerBuilder;
this.parentTransform = parentTransform;
}
public RegistrationBuilder AddInstance<TInterface>(TInterface component)
{
return containerBuilder.RegisterComponent(component);
}
public ComponentRegistrationBuilder AddInHierarchy<T>()
=> containerBuilder.RegisterComponentInHierarchy<T>()
.UnderTransform(parentTransform);
public ComponentRegistrationBuilder AddOnNewGameObject<T>(Lifetime lifetime, string newGameObjectName = null)
where T : Component
=> containerBuilder.RegisterComponentOnNewGameObject<T>(lifetime, newGameObjectName)
.UnderTransform(parentTransform);
public ComponentRegistrationBuilder AddInNewPrefab<T>(T prefab, Lifetime lifetime)
where T : Component
=> containerBuilder.RegisterComponentInNewPrefab(prefab, lifetime)
.UnderTransform(parentTransform);
}
public static class ContainerBuilderUnityExtensions
{
public static void UseEntryPoints(
this IContainerBuilder builder,
Action<EntryPointsBuilder> configuration)
{
builder.UseEntryPoints(Lifetime.Singleton, configuration);
}
public static void UseEntryPoints(
this IContainerBuilder builder,
Lifetime lifetime,
Action<EntryPointsBuilder> configuration)
{
EntryPointsBuilder.EnsureDispatcherRegistered(builder);
configuration(new EntryPointsBuilder(builder, lifetime));
}
public static void UseComponents(this IContainerBuilder builder, Action<ComponentsBuilder> configuration)
{
configuration(new ComponentsBuilder(builder));
}
public static void UseComponents(
this IContainerBuilder builder,
Transform root,
Action<ComponentsBuilder> configuration)
{
configuration(new ComponentsBuilder(builder, root));
}
public static RegistrationBuilder RegisterEntryPoint<T>(
this IContainerBuilder builder,
Lifetime lifetime = Lifetime.Singleton)
{
EntryPointsBuilder.EnsureDispatcherRegistered(builder);
return builder.Register<T>(lifetime).AsImplementedInterfaces();
}
public static RegistrationBuilder RegisterEntryPoint<TInterface>(
this IContainerBuilder builder,
Func<IObjectResolver, TInterface> implementationConfiguration,
Lifetime lifetime)
{
EntryPointsBuilder.EnsureDispatcherRegistered(builder);
return builder.Register(new FuncRegistrationBuilder(container => implementationConfiguration(container),
typeof(TInterface), lifetime)).AsImplementedInterfaces();
}
public static void RegisterEntryPointExceptionHandler(
this IContainerBuilder builder,
Action<Exception> exceptionHandler)
{
builder.Register(c => new EntryPointExceptionHandler(exceptionHandler), Lifetime.Scoped);
}
public static RegistrationBuilder RegisterComponent<TInterface>(
this IContainerBuilder builder,
TInterface component)
{
var registrationBuilder = new ComponentRegistrationBuilder(component).As(typeof(TInterface));
// Force inject execution
builder.RegisterBuildCallback(container => container.Resolve<TInterface>());
return builder.Register(registrationBuilder);
}
public static ComponentRegistrationBuilder RegisterComponentInHierarchy(
this IContainerBuilder builder,
Type type)
{
var lifetimeScope = (LifetimeScope)builder.ApplicationOrigin;
var scene = lifetimeScope.gameObject.scene;
var registrationBuilder = new ComponentRegistrationBuilder(scene, type);
// Force inject execution
builder.RegisterBuildCallback(
container =>
{
container.Resolve(
registrationBuilder.InterfaceTypes != null
? registrationBuilder.InterfaceTypes[0]
: registrationBuilder.ImplementationType
);
}
);
return builder.Register(registrationBuilder);
}
public static ComponentRegistrationBuilder RegisterComponentInHierarchy<T>(this IContainerBuilder builder)
{
return builder.RegisterComponentInHierarchy(typeof(T));
}
public static ComponentRegistrationBuilder RegisterComponentOnNewGameObject(
this IContainerBuilder builder,
Type type,
Lifetime lifetime,
string newGameObjectName = null)
{
return builder.Register(new ComponentRegistrationBuilder(newGameObjectName, type, lifetime));
}
public static ComponentRegistrationBuilder RegisterComponentOnNewGameObject<T>(
this IContainerBuilder builder,
Lifetime lifetime,
string newGameObjectName = null)
where T : Component
{
return builder.RegisterComponentOnNewGameObject(typeof(T), lifetime, newGameObjectName);
}
public static ComponentRegistrationBuilder RegisterComponentInNewPrefab(
this IContainerBuilder builder,
Type interfaceType,
Component prefab,
Lifetime lifetime)
{
var componentRegistrationBuilder = builder.Register(new ComponentRegistrationBuilder(_ => prefab, prefab.GetType(), lifetime));
componentRegistrationBuilder.As(interfaceType);
return componentRegistrationBuilder;
}
public static ComponentRegistrationBuilder RegisterComponentInNewPrefab<T>(
this IContainerBuilder builder,
T prefab,
Lifetime lifetime)
where T : Component
{
return builder.RegisterComponentInNewPrefab(typeof(T), prefab, lifetime);
}
public static ComponentRegistrationBuilder RegisterComponentInNewPrefab<T>(
this IContainerBuilder builder,
Func<IObjectResolver, T> prefab,
Lifetime lifetime)
where T : Component
{
return builder.Register(new ComponentRegistrationBuilder(prefab, typeof(T), lifetime));
}
public static ComponentRegistrationBuilder RegisterComponentInNewPrefab<TInterface, TImplement>(
this IContainerBuilder builder,
Func<IObjectResolver, TImplement> prefab,
Lifetime lifetime)
where TImplement : Component, TInterface
{
var componentRegistrationBuilder = builder.Register(new ComponentRegistrationBuilder(prefab, typeof(TImplement), lifetime));
componentRegistrationBuilder.As<TInterface>();
return componentRegistrationBuilder;
}
#if VCONTAINER_ECS_INTEGRATION
public readonly struct NewWorldBuilder
{
readonly IContainerBuilder containerBuilder;
readonly string worldName;
readonly Lifetime worldLifetime;
public NewWorldBuilder(IContainerBuilder containerBuilder, string worldName, Lifetime worldLifetime)
{
this.containerBuilder = containerBuilder;
this.worldName = worldName;
this.worldLifetime = worldLifetime;
containerBuilder.RegisterNewWorld(worldName, worldLifetime);
}
public SystemRegistrationBuilder Add<T>() where T : ComponentSystemBase
=> containerBuilder.RegisterSystemIntoWorld<T>(worldName);
#if UNITY_2022_2_OR_NEWER
public UnmanagedSystemRegistrationBuilder AddUnmanaged<T>(T system) where T : unmanaged, ISystem
=> containerBuilder.RegisterUnmanagedSystemIntoWorld<T>(worldName);
#endif
}
public readonly struct DefaultWorldBuilder
{
readonly IContainerBuilder containerBuilder;
public DefaultWorldBuilder(IContainerBuilder containerBuilder)
{
this.containerBuilder = containerBuilder;
}
public RegistrationBuilder Add<T>() where T : ComponentSystemBase
=> containerBuilder.RegisterSystemFromDefaultWorld<T>();
#if UNITY_2022_2_OR_NEWER
public RegistrationBuilder AddUnmanaged<T>() where T : unmanaged, ISystem
=> containerBuilder.RegisterUnmanagedSystemFromDefaultWorld<T>();
#endif
}
// Use exisiting world
public static void UseDefaultWorld(this IContainerBuilder builder, Action<DefaultWorldBuilder> configuration)
{
var systems = new DefaultWorldBuilder(builder);
configuration(systems);
}
public static RegistrationBuilder RegisterSystemFromDefaultWorld<T>(this IContainerBuilder builder)
where T : ComponentSystemBase
=> RegisterSystemFromWorld<T>(builder, World.DefaultGameObjectInjectionWorld);
#if UNITY_2022_2_OR_NEWER
public static RegistrationBuilder RegisterUnmanagedSystemFromDefaultWorld<T>(this IContainerBuilder builder)
where T : unmanaged, ISystem
=> RegisterUnmanagedSystemFromWorld<T>(builder, World.DefaultGameObjectInjectionWorld);
#endif
public static RegistrationBuilder RegisterSystemFromWorld<T>(this IContainerBuilder builder, World world)
where T : ComponentSystemBase
{
#if UNITY_2022_2_OR_NEWER
var system = world.GetExistingSystemManaged<T>();
#else
var system = world.GetExistingSystem<T>();
#endif
if (system is null)
throw new ArgumentException($"{typeof(T).FullName} is not in the world {world}");
return builder.RegisterComponent(system)
.As(typeof(ComponentSystemBase), typeof(T));
}
#if UNITY_2022_2_OR_NEWER
public static RegistrationBuilder RegisterUnmanagedSystemFromWorld<T>(this IContainerBuilder builder, World world)
where T : unmanaged, ISystem
{
var system = world.Unmanaged.GetExistingUnmanagedSystem<T>();
if (system == SystemHandle.Null)
throw new ArgumentException($"{typeof(T).FullName} is not in the world {world}");
Type refType = typeof(UnmanagedSystemReference<>);
Type target = refType.MakeGenericType(typeof(T));
var reference = (UnmanagedSystemReference)Activator.CreateInstance(target, system, world);
return builder.RegisterComponent(reference)
.As(target);
}
#endif
// Use custom world
public static void UseNewWorld(
this IContainerBuilder builder,
string worldName,
Lifetime lifetime,
Action<NewWorldBuilder> configuration)
{
var systems = new NewWorldBuilder(builder, worldName, lifetime);
configuration(systems);
}
public static RegistrationBuilder RegisterNewWorld(
this IContainerBuilder builder,
string worldName,
Lifetime lifetime,
Action<World> configuration = null)
{
builder.Register<WorldConfigurationHelper>(lifetime)
.WithParameter(typeof(string), worldName);
return builder.Register(new WorldRegistrationBuilder(worldName, lifetime, configuration));
}
public static SystemRegistrationBuilder RegisterSystemIntoWorld<T>(
this IContainerBuilder builder,
string worldName)
where T : ComponentSystemBase
{
var registrationBuilder = new SystemRegistrationBuilder(typeof(T), worldName)
.IntoGroup<SimulationSystemGroup>();
return builder.Register(registrationBuilder);
}
public static SystemRegistrationBuilder RegisterSystemIntoWorld<T, T1>(
this IContainerBuilder builder,
string worldName)
where T : ComponentSystemBase
where T1 : ComponentSystemGroup
{
var registrationBuilder = new SystemRegistrationBuilder(typeof(T), worldName)
.IntoGroup<T1>();
return builder.Register(registrationBuilder);
}
#if UNITY_2022_2_OR_NEWER
public static UnmanagedSystemRegistrationBuilder RegisterUnmanagedSystemIntoWorld<T>(
this IContainerBuilder builder,
string worldName)
where T : unmanaged, ISystem
{
var registrationBuilder = new UnmanagedSystemRegistrationBuilder(typeof(T), worldName)
.IntoGroup<SimulationSystemGroup>();
return builder.Register(registrationBuilder);
}
public static UnmanagedSystemRegistrationBuilder RegisterUnmanagedSystemIntoWorld<T, T1>(
this IContainerBuilder builder,
string worldName)
where T : unmanaged, ISystem
where T1 : ComponentSystemGroup
{
var registrationBuilder = new UnmanagedSystemRegistrationBuilder(typeof(T), worldName)
.IntoGroup<T1>();
return builder.Register(registrationBuilder);
}
#endif
public static SystemRegistrationBuilder RegisterSystemIntoDefaultWorld<T>(this IContainerBuilder builder)
where T : ComponentSystemBase
{
var registrationBuilder = new SystemRegistrationBuilder(typeof(T), null)
.IntoGroup<SimulationSystemGroup>();
return builder.Register(registrationBuilder);
}
public static SystemRegistrationBuilder RegisterSystemIntoDefaultWorld<T, T1>(this IContainerBuilder builder)
where T : ComponentSystemBase
where T1 : ComponentSystemGroup
{
var registrationBuilder = new SystemRegistrationBuilder(typeof(T), null)
.IntoGroup<T1>();
return builder.Register(registrationBuilder);
}
#if UNITY_2022_2_OR_NEWER
public static UnmanagedSystemRegistrationBuilder RegisterUnmanagedSystemIntoDefaultWorld<T>(this IContainerBuilder builder)
where T : unmanaged, ISystem
{
var registrationBuilder = new UnmanagedSystemRegistrationBuilder(typeof(T), null)
.IntoGroup<SimulationSystemGroup>();
return builder.Register(registrationBuilder);
}
public static UnmanagedSystemRegistrationBuilder RegisterUnmanagedSystemIntoDefaultWorld<T, T1>(this IContainerBuilder builder)
where T : unmanaged, ISystem
where T1 : ComponentSystemGroup
{
var registrationBuilder = new UnmanagedSystemRegistrationBuilder(typeof(T), null)
.IntoGroup<T1>();
return builder.Register(registrationBuilder);
}
#endif
#endif
}
}