421 lines
16 KiB
C#
421 lines
16 KiB
C#
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
|
||
}
|
||
}
|