Initial commit: Unity WordConnect project
This commit is contained in:
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public sealed class ActionInstaller : IInstaller
|
||||
{
|
||||
public static implicit operator ActionInstaller(Action<IContainerBuilder> installation)
|
||||
=> new ActionInstaller(installation);
|
||||
|
||||
readonly Action<IContainerBuilder> configuration;
|
||||
|
||||
public ActionInstaller(Action<IContainerBuilder> configuration)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public void Install(IContainerBuilder builder)
|
||||
{
|
||||
configuration(builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48336697de89414886abfd92d2ac9218
|
||||
timeCreated: 1593187294
|
||||
@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using VContainer.Internal;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
struct ComponentDestination
|
||||
{
|
||||
public Transform Parent;
|
||||
public Func<IObjectResolver, Transform> ParentFinder;
|
||||
public bool DontDestroyOnLoad;
|
||||
|
||||
public Transform GetParent(IObjectResolver resolver)
|
||||
{
|
||||
if (Parent != null)
|
||||
return Parent;
|
||||
if (ParentFinder != null)
|
||||
return ParentFinder(resolver);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ApplyDontDestroyOnLoadIfNeeded(Component component)
|
||||
{
|
||||
if (DontDestroyOnLoad)
|
||||
{
|
||||
UnityEngine.Object.DontDestroyOnLoad(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ComponentRegistrationBuilder : RegistrationBuilder
|
||||
{
|
||||
readonly object instance;
|
||||
readonly Func<IObjectResolver, Component> prefabFinder;
|
||||
readonly string gameObjectName;
|
||||
|
||||
ComponentDestination destination;
|
||||
Scene scene;
|
||||
|
||||
internal ComponentRegistrationBuilder(object instance)
|
||||
: base(instance.GetType(), Lifetime.Singleton)
|
||||
{
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
internal ComponentRegistrationBuilder(in Scene scene, Type implementationType)
|
||||
: base(implementationType, Lifetime.Singleton)
|
||||
{
|
||||
this.scene = scene;
|
||||
}
|
||||
|
||||
internal ComponentRegistrationBuilder(
|
||||
Func<IObjectResolver, Component> prefabFinder,
|
||||
Type implementationType,
|
||||
Lifetime lifetime)
|
||||
: base(implementationType, lifetime)
|
||||
{
|
||||
this.prefabFinder = prefabFinder;
|
||||
}
|
||||
|
||||
internal ComponentRegistrationBuilder(
|
||||
string gameObjectName,
|
||||
Type implementationType,
|
||||
Lifetime lifetime)
|
||||
: base(implementationType, lifetime)
|
||||
{
|
||||
this.gameObjectName = gameObjectName;
|
||||
}
|
||||
|
||||
public override Registration Build()
|
||||
{
|
||||
IInstanceProvider provider;
|
||||
|
||||
if (instance != null)
|
||||
{
|
||||
var injector = InjectorCache.GetOrBuild(ImplementationType);
|
||||
provider = new ExistingComponentProvider(instance, injector, Parameters, destination.DontDestroyOnLoad);
|
||||
}
|
||||
else if (scene.IsValid())
|
||||
{
|
||||
provider = new FindComponentProvider(ImplementationType, Parameters, in scene, in destination);
|
||||
}
|
||||
else if (prefabFinder != null)
|
||||
{
|
||||
var injector = InjectorCache.GetOrBuild(ImplementationType);
|
||||
provider = new PrefabComponentProvider(prefabFinder, injector, Parameters, in destination);
|
||||
}
|
||||
else
|
||||
{
|
||||
var injector = InjectorCache.GetOrBuild(ImplementationType);
|
||||
provider = new NewGameObjectProvider(ImplementationType, injector, Parameters, in destination, gameObjectName);
|
||||
}
|
||||
return new Registration(ImplementationType, Lifetime, InterfaceTypes, provider);
|
||||
}
|
||||
|
||||
public ComponentRegistrationBuilder UnderTransform(Transform parent)
|
||||
{
|
||||
destination.Parent = parent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComponentRegistrationBuilder UnderTransform(Func<Transform> parentFinder)
|
||||
{
|
||||
destination.ParentFinder = _ => parentFinder();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComponentRegistrationBuilder UnderTransform(Func<IObjectResolver, Transform> parentFinder)
|
||||
{
|
||||
destination.ParentFinder = parentFinder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComponentRegistrationBuilder DontDestroyOnLoad()
|
||||
{
|
||||
destination.DontDestroyOnLoad = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8d9071a8a0a4915bc374a6691d9aebd
|
||||
timeCreated: 1592589484
|
||||
@ -0,0 +1,420 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e9b811ca5454c89a0905e0127ea62b8
|
||||
timeCreated: 1593020228
|
||||
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
sealed class AsyncLoopItem : IPlayerLoopItem
|
||||
{
|
||||
readonly Action action;
|
||||
|
||||
public AsyncLoopItem(Action action)
|
||||
{
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
action();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 792f76fbc1dd409887297cdfe8aa3aa9
|
||||
timeCreated: 1653803074
|
||||
@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using VContainer.Internal;
|
||||
#if VCONTAINER_ECS_INTEGRATION
|
||||
using Unity.Entities;
|
||||
#endif
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public sealed class EntryPointDispatcher : IDisposable
|
||||
{
|
||||
readonly IObjectResolver container;
|
||||
readonly CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
[Inject]
|
||||
public EntryPointDispatcher(IObjectResolver container)
|
||||
{
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
public void Dispatch()
|
||||
{
|
||||
PlayerLoopHelper.EnsureInitialized();
|
||||
|
||||
var exceptionHandler = container.ResolveOrDefault<EntryPointExceptionHandler>();
|
||||
|
||||
var initializables = container.Resolve<ContainerLocal<IReadOnlyList<IInitializable>>>().Value;
|
||||
for (var i = 0; i < initializables.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
initializables[i].Initialize();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptionHandler != null)
|
||||
exceptionHandler.Publish(ex);
|
||||
else
|
||||
UnityEngine.Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
var postInitializables = container.Resolve<ContainerLocal<IReadOnlyList<IPostInitializable>>>().Value;
|
||||
for (var i = 0; i < postInitializables.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
postInitializables[i].PostInitialize();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptionHandler != null)
|
||||
exceptionHandler.Publish(ex);
|
||||
else
|
||||
UnityEngine.Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
var startables = container.Resolve<ContainerLocal<IReadOnlyList<IStartable>>>().Value;
|
||||
if (startables.Count > 0)
|
||||
{
|
||||
var loopItem = new StartableLoopItem(startables, exceptionHandler);
|
||||
disposable.Add(loopItem);
|
||||
PlayerLoopHelper.Dispatch(PlayerLoopTiming.Startup, loopItem);
|
||||
}
|
||||
|
||||
var postStartables = container.Resolve<ContainerLocal<IReadOnlyList<IPostStartable>>>().Value;
|
||||
if (postStartables.Count > 0)
|
||||
{
|
||||
var loopItem = new PostStartableLoopItem(postStartables, exceptionHandler);
|
||||
disposable.Add(loopItem);
|
||||
PlayerLoopHelper.Dispatch(PlayerLoopTiming.PostStartup, loopItem);
|
||||
}
|
||||
|
||||
var fixedTickables = container.Resolve<ContainerLocal<IReadOnlyList<IFixedTickable>>>().Value;
|
||||
if (fixedTickables.Count > 0)
|
||||
{
|
||||
var loopItem = new FixedTickableLoopItem(fixedTickables, exceptionHandler);
|
||||
disposable.Add(loopItem);
|
||||
PlayerLoopHelper.Dispatch(PlayerLoopTiming.FixedUpdate, loopItem);
|
||||
}
|
||||
|
||||
var postFixedTickables = container.Resolve<ContainerLocal<IReadOnlyList<IPostFixedTickable>>>().Value;
|
||||
if (postFixedTickables.Count > 0)
|
||||
{
|
||||
var loopItem = new PostFixedTickableLoopItem(postFixedTickables, exceptionHandler);
|
||||
disposable.Add(loopItem);
|
||||
PlayerLoopHelper.Dispatch(PlayerLoopTiming.PostFixedUpdate, loopItem);
|
||||
}
|
||||
|
||||
var tickables = container.Resolve<ContainerLocal<IReadOnlyList<ITickable>>>().Value;
|
||||
if (tickables.Count > 0)
|
||||
{
|
||||
var loopItem = new TickableLoopItem(tickables, exceptionHandler);
|
||||
disposable.Add(loopItem);
|
||||
PlayerLoopHelper.Dispatch(PlayerLoopTiming.Update, loopItem);
|
||||
}
|
||||
|
||||
var postTickables = container.Resolve<ContainerLocal<IReadOnlyList<IPostTickable>>>().Value;
|
||||
if (postTickables.Count > 0)
|
||||
{
|
||||
var loopItem = new PostTickableLoopItem(postTickables, exceptionHandler);
|
||||
disposable.Add(loopItem);
|
||||
PlayerLoopHelper.Dispatch(PlayerLoopTiming.PostUpdate, loopItem);
|
||||
}
|
||||
|
||||
var lateTickables = container.Resolve<ContainerLocal<IReadOnlyList<ILateTickable>>>().Value;
|
||||
if (lateTickables.Count > 0)
|
||||
{
|
||||
var loopItem = new LateTickableLoopItem(lateTickables, exceptionHandler);
|
||||
disposable.Add(loopItem);
|
||||
PlayerLoopHelper.Dispatch(PlayerLoopTiming.LateUpdate, loopItem);
|
||||
}
|
||||
|
||||
var postLateTickables = container.Resolve<ContainerLocal<IReadOnlyList<IPostLateTickable>>>().Value;
|
||||
if (postLateTickables.Count > 0)
|
||||
{
|
||||
var loopItem = new PostLateTickableLoopItem(postLateTickables, exceptionHandler);
|
||||
disposable.Add(loopItem);
|
||||
PlayerLoopHelper.Dispatch(PlayerLoopTiming.PostLateUpdate, loopItem);
|
||||
}
|
||||
|
||||
#if VCONTAINER_UNITASK_INTEGRATION || UNITY_2021_3_OR_NEWER
|
||||
var asyncStartables = container.Resolve<ContainerLocal<IReadOnlyList<IAsyncStartable>>>().Value;
|
||||
if (asyncStartables.Count > 0)
|
||||
{
|
||||
var loopItem = new AsyncStartableLoopItem(asyncStartables, exceptionHandler);
|
||||
disposable.Add(loopItem);
|
||||
PlayerLoopHelper.Dispatch(PlayerLoopTiming.Startup, loopItem);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VCONTAINER_ECS_INTEGRATION
|
||||
container.Resolve<ContainerLocal<IEnumerable<ComponentSystemBase>>>();
|
||||
|
||||
var worldHelpers = container.Resolve<ContainerLocal<IReadOnlyList<WorldConfigurationHelper>>>().Value;
|
||||
for (var i = 0; i < worldHelpers.Count; i++)
|
||||
{
|
||||
worldHelpers[i].SortSystems();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Dispose() => disposable.Dispose();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8b5d8a26f2d409fb1de359daa251bde
|
||||
timeCreated: 1614397266
|
||||
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
sealed class EntryPointExceptionHandler
|
||||
{
|
||||
readonly Action<Exception> handler;
|
||||
|
||||
public EntryPointExceptionHandler(Action<Exception> handler)
|
||||
{
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public void Publish(Exception ex)
|
||||
{
|
||||
handler.Invoke(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b60c8fd4709435d82c04a947e096fa3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,7 @@
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public interface IInstaller
|
||||
{
|
||||
void Install(IContainerBuilder builder);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22d89c28d4364858a331cd5f669e58b7
|
||||
timeCreated: 1593187294
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7d46367acb94de1966baea5febbf70c
|
||||
timeCreated: 1637900702
|
||||
@ -0,0 +1,44 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
sealed class ExistingComponentProvider : IInstanceProvider
|
||||
{
|
||||
readonly object instance;
|
||||
readonly IInjector injector;
|
||||
readonly IReadOnlyList<IInjectParameter> customParameters;
|
||||
readonly bool dontDestroyOnLoad;
|
||||
|
||||
public ExistingComponentProvider(
|
||||
object instance,
|
||||
IInjector injector,
|
||||
IReadOnlyList<IInjectParameter> customParameters,
|
||||
bool dontDestroyOnLoad = false)
|
||||
{
|
||||
this.instance = instance;
|
||||
this.customParameters = customParameters;
|
||||
this.injector = injector;
|
||||
this.dontDestroyOnLoad = dontDestroyOnLoad;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public object SpawnInstance(IObjectResolver resolver)
|
||||
{
|
||||
injector.Inject(instance, resolver, customParameters);
|
||||
if (dontDestroyOnLoad)
|
||||
{
|
||||
if (instance is UnityEngine.Object component)
|
||||
{
|
||||
UnityEngine.Object.DontDestroyOnLoad(component);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new VContainerException(instance.GetType(),
|
||||
$"Cannot apply `DontDestroyOnLoad`. {instance.GetType().Name} is not a UnityEngine.Object");
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3eaf1bb53ea4494484290e95207cc8f3
|
||||
timeCreated: 1620020530
|
||||
@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using VContainer.Internal;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
sealed class FindComponentProvider : IInstanceProvider
|
||||
{
|
||||
readonly Type componentType;
|
||||
readonly IReadOnlyList<IInjectParameter> customParameters;
|
||||
ComponentDestination destination;
|
||||
Scene scene;
|
||||
|
||||
public FindComponentProvider(
|
||||
Type componentType,
|
||||
IReadOnlyList<IInjectParameter> customParameters,
|
||||
in Scene scene,
|
||||
in ComponentDestination destination)
|
||||
{
|
||||
this.componentType = componentType;
|
||||
this.customParameters = customParameters;
|
||||
this.scene = scene;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public object SpawnInstance(IObjectResolver resolver)
|
||||
{
|
||||
var component = default(Component);
|
||||
|
||||
var parent = destination.GetParent(resolver);
|
||||
if (parent != null)
|
||||
{
|
||||
component = parent.GetComponentInChildren(componentType, true);
|
||||
if (component == null)
|
||||
{
|
||||
throw new VContainerException(componentType, $"{componentType} is not in the parent {parent.name} : {this}");
|
||||
}
|
||||
}
|
||||
else if (scene.IsValid())
|
||||
{
|
||||
using (ListPool<GameObject>.Get(out var gameObjectBuffer))
|
||||
{
|
||||
scene.GetRootGameObjects(gameObjectBuffer);
|
||||
foreach (var gameObject in gameObjectBuffer)
|
||||
{
|
||||
component = gameObject.GetComponentInChildren(componentType, true);
|
||||
if (component != null) break;
|
||||
}
|
||||
}
|
||||
if (component == null)
|
||||
{
|
||||
throw new VContainerException(componentType, $"{componentType} is not in this scene {scene.path} : {this}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new VContainerException(componentType, $"Invalid Component find target {this}");
|
||||
}
|
||||
|
||||
if (component is MonoBehaviour monoBehaviour)
|
||||
{
|
||||
var injector = InjectorCache.GetOrBuild(monoBehaviour.GetType());
|
||||
injector.Inject(monoBehaviour, resolver, customParameters);
|
||||
}
|
||||
|
||||
destination.ApplyDontDestroyOnLoadIfNeeded(component);
|
||||
return component;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8feb76212733400e80e88bc385685993
|
||||
timeCreated: 1619932417
|
||||
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
sealed class NewGameObjectProvider : IInstanceProvider
|
||||
{
|
||||
readonly Type componentType;
|
||||
readonly IInjector injector;
|
||||
readonly IReadOnlyList<IInjectParameter> customParameters;
|
||||
readonly string newGameObjectName;
|
||||
ComponentDestination destination;
|
||||
|
||||
public NewGameObjectProvider(
|
||||
Type componentType,
|
||||
IInjector injector,
|
||||
IReadOnlyList<IInjectParameter> customParameters,
|
||||
in ComponentDestination destination,
|
||||
string newGameObjectName = null)
|
||||
{
|
||||
this.componentType = componentType;
|
||||
this.customParameters = customParameters;
|
||||
this.injector = injector;
|
||||
this.destination = destination;
|
||||
this.newGameObjectName = newGameObjectName;
|
||||
}
|
||||
|
||||
public object SpawnInstance(IObjectResolver resolver)
|
||||
{
|
||||
var name = string.IsNullOrEmpty(newGameObjectName)
|
||||
? componentType.Name
|
||||
: newGameObjectName;
|
||||
var gameObject = new GameObject(name);
|
||||
gameObject.SetActive(false);
|
||||
|
||||
var parent = destination.GetParent(resolver);
|
||||
if (parent != null)
|
||||
{
|
||||
gameObject.transform.SetParent(parent);
|
||||
}
|
||||
var component = gameObject.AddComponent(componentType);
|
||||
|
||||
injector.Inject(component, resolver, customParameters);
|
||||
destination.ApplyDontDestroyOnLoadIfNeeded(component);
|
||||
|
||||
component.gameObject.SetActive(true);
|
||||
return component;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f18c3e4b45d349ca8f1d388dca5bc8b8
|
||||
timeCreated: 1619933144
|
||||
@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
sealed class PrefabComponentProvider : IInstanceProvider
|
||||
{
|
||||
readonly IInjector injector;
|
||||
readonly IReadOnlyList<IInjectParameter> customParameters;
|
||||
readonly Func<IObjectResolver, Component> prefabFinder;
|
||||
ComponentDestination destination;
|
||||
|
||||
public PrefabComponentProvider(
|
||||
Func<IObjectResolver, Component> prefabFinder,
|
||||
IInjector injector,
|
||||
IReadOnlyList<IInjectParameter> customParameters,
|
||||
in ComponentDestination destination)
|
||||
{
|
||||
this.injector = injector;
|
||||
this.customParameters = customParameters;
|
||||
this.prefabFinder = prefabFinder;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public object SpawnInstance(IObjectResolver resolver)
|
||||
{
|
||||
var prefab = prefabFinder(resolver);
|
||||
var parent = destination.GetParent(resolver);
|
||||
|
||||
var wasActive = prefab.gameObject.activeSelf;
|
||||
using (new ObjectResolverUnityExtensions.PrefabDirtyScope(prefab.gameObject))
|
||||
{
|
||||
if (wasActive)
|
||||
{
|
||||
prefab.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
var component = parent != null
|
||||
? UnityEngine.Object.Instantiate(prefab, parent)
|
||||
: UnityEngine.Object.Instantiate(prefab);
|
||||
|
||||
if (VContainerSettings.Instance != null && VContainerSettings.Instance.RemoveClonePostfix)
|
||||
component.name = prefab.name;
|
||||
|
||||
try
|
||||
{
|
||||
injector.Inject(component, resolver, customParameters);
|
||||
destination.ApplyDontDestroyOnLoadIfNeeded(component);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (wasActive)
|
||||
{
|
||||
prefab.gameObject.SetActive(true);
|
||||
component.gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
return component;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51a9e9ed532b41898ab9e5f82ea2781f
|
||||
timeCreated: 1619932830
|
||||
@ -0,0 +1,81 @@
|
||||
#if VCONTAINER_ECS_INTEGRATION
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Entities;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public sealed class SystemInstanceProvider<T> : IInstanceProvider where T : ComponentSystemBase
|
||||
{
|
||||
readonly Type systemType;
|
||||
readonly IInjector injector;
|
||||
readonly IReadOnlyList<IInjectParameter> customParameters;
|
||||
readonly string worldName;
|
||||
readonly Type systemGroupType;
|
||||
|
||||
World world;
|
||||
T instance;
|
||||
|
||||
public SystemInstanceProvider(
|
||||
Type systemType,
|
||||
string worldName,
|
||||
Type systemGroupType,
|
||||
IInjector injector,
|
||||
IReadOnlyList<IInjectParameter> customParameters)
|
||||
{
|
||||
this.systemType = systemType;
|
||||
this.worldName = worldName;
|
||||
this.systemGroupType = systemGroupType;
|
||||
this.injector = injector;
|
||||
this.customParameters = customParameters;
|
||||
}
|
||||
|
||||
public object SpawnInstance(IObjectResolver resolver)
|
||||
{
|
||||
if (world is null)
|
||||
world = GetWorld(resolver);
|
||||
|
||||
if (instance is null)
|
||||
{
|
||||
instance = (T) injector.CreateInstance(resolver, customParameters);
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
world.AddSystemManaged(instance);
|
||||
#else
|
||||
world.AddSystem(instance);
|
||||
#endif
|
||||
|
||||
if (systemGroupType != null)
|
||||
{
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
var systemGroup = (ComponentSystemGroup)world.GetOrCreateSystemManaged(systemGroupType);
|
||||
#else
|
||||
var systemGroup = (ComponentSystemGroup)world.GetOrCreateSystem(systemGroupType);
|
||||
#endif
|
||||
systemGroup.AddSystemToUpdateList(instance);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
return world.GetExistingSystemManaged(systemType);
|
||||
#else
|
||||
return world.GetExistingSystem(systemType);
|
||||
#endif
|
||||
}
|
||||
|
||||
World GetWorld(IObjectResolver resolver)
|
||||
{
|
||||
if (worldName is null && World.DefaultGameObjectInjectionWorld != null)
|
||||
return World.DefaultGameObjectInjectionWorld;
|
||||
|
||||
var worlds = resolver.Resolve<IEnumerable<World>>();
|
||||
foreach (var world in worlds)
|
||||
{
|
||||
if (world.Name == worldName)
|
||||
return world;
|
||||
}
|
||||
throw new VContainerException(systemType, $"World `{worldName}` is not registered");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: baa43b4b3a9a4d1895436d98f4c539e4
|
||||
timeCreated: 1595083942
|
||||
@ -0,0 +1,71 @@
|
||||
#if VCONTAINER_ECS_INTEGRATION && UNITY_2022_2_OR_NEWER
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Entities;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public sealed class UnmanagedSystemInstanceProvider : IInstanceProvider
|
||||
{
|
||||
readonly Type systemType;
|
||||
readonly IInjector injector;
|
||||
readonly IReadOnlyList<IInjectParameter> customParameters;
|
||||
readonly string worldName;
|
||||
readonly Type systemGroupType;
|
||||
|
||||
private World world;
|
||||
private UnmanagedSystemReference instance;
|
||||
|
||||
public UnmanagedSystemInstanceProvider(
|
||||
Type systemType,
|
||||
string worldName,
|
||||
Type systemGroupType,
|
||||
IInjector injector,
|
||||
IReadOnlyList<IInjectParameter> customParameters)
|
||||
{
|
||||
this.systemType = systemType;
|
||||
this.worldName = worldName;
|
||||
this.systemGroupType = systemGroupType;
|
||||
this.injector = injector;
|
||||
this.customParameters = customParameters;
|
||||
}
|
||||
|
||||
public object SpawnInstance(IObjectResolver resolver)
|
||||
{
|
||||
if (world is null)
|
||||
world = GetWorld(resolver);
|
||||
|
||||
if (instance is null)
|
||||
{
|
||||
SystemHandle handle = world.GetOrCreateSystem(systemType);
|
||||
injector.Inject(handle, resolver, customParameters);
|
||||
|
||||
if (systemGroupType is not null)
|
||||
{
|
||||
var systemGroup = (ComponentSystemGroup) world.GetOrCreateSystemManaged(systemGroupType);
|
||||
systemGroup.AddSystemToUpdateList(handle);
|
||||
}
|
||||
Type refType = typeof(UnmanagedSystemReference<>);
|
||||
Type target = refType.MakeGenericType(systemType);
|
||||
instance = (UnmanagedSystemReference)Activator.CreateInstance(target, handle, world);
|
||||
return instance;
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private World GetWorld(IObjectResolver resolver)
|
||||
{
|
||||
if (worldName is null && World.DefaultGameObjectInjectionWorld != null)
|
||||
return World.DefaultGameObjectInjectionWorld;
|
||||
|
||||
var worlds = resolver.Resolve<IEnumerable<World>>();
|
||||
foreach (World w in worlds)
|
||||
{
|
||||
if (w.Name == worldName)
|
||||
return w;
|
||||
}
|
||||
throw new VContainerException(systemType, $"World `{worldName}` is not Created");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3e078788acd49f292b76c0a778b1a45
|
||||
timeCreated: 1671719884
|
||||
@ -0,0 +1,48 @@
|
||||
#if VCONTAINER_ECS_INTEGRATION
|
||||
using System;
|
||||
using Unity.Entities;
|
||||
using UnityEngine.LowLevel;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public sealed class WorldInstanceProvider : IInstanceProvider
|
||||
{
|
||||
readonly string name;
|
||||
readonly Action<World> initialization;
|
||||
|
||||
public WorldInstanceProvider(string name, Action<World> initialization = null)
|
||||
{
|
||||
this.name = name;
|
||||
this.initialization = initialization;
|
||||
}
|
||||
|
||||
public object SpawnInstance(IObjectResolver resolver)
|
||||
{
|
||||
var world = new World(name);
|
||||
if (initialization != null)
|
||||
{
|
||||
initialization(world);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
world.CreateSystemManaged<InitializationSystemGroup>();
|
||||
world.CreateSystemManaged<SimulationSystemGroup>();
|
||||
world.CreateSystemManaged<PresentationSystemGroup>();
|
||||
|
||||
ScriptBehaviourUpdateOrder.RemoveWorldFromCurrentPlayerLoop(world);
|
||||
ScriptBehaviourUpdateOrder.AppendWorldToCurrentPlayerLoop(world);
|
||||
#else
|
||||
world.CreateSystem<InitializationSystemGroup>();
|
||||
world.CreateSystem<SimulationSystemGroup>();
|
||||
world.CreateSystem<PresentationSystemGroup>();
|
||||
|
||||
ScriptBehaviourUpdateOrder.RemoveWorldFromCurrentPlayerLoop(world);
|
||||
ScriptBehaviourUpdateOrder.AddWorldToCurrentPlayerLoop(world);
|
||||
#endif
|
||||
}
|
||||
return world;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c152c2c135444258b6b6bc730bdb1f64
|
||||
timeCreated: 1595059160
|
||||
@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using VContainer.Internal;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public sealed class VContainerParentTypeReferenceNotFound : Exception
|
||||
{
|
||||
public readonly Type ParentType;
|
||||
|
||||
public VContainerParentTypeReferenceNotFound(Type parentType, string message)
|
||||
: base(message)
|
||||
{
|
||||
ParentType = parentType;
|
||||
}
|
||||
}
|
||||
|
||||
partial class LifetimeScope
|
||||
{
|
||||
static readonly List<LifetimeScope> WaitingList = new List<LifetimeScope>();
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
#else
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
#endif
|
||||
static void SubscribeSceneEvents()
|
||||
{
|
||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
}
|
||||
|
||||
static void EnqueueAwake(LifetimeScope lifetimeScope)
|
||||
{
|
||||
WaitingList.Add(lifetimeScope);
|
||||
}
|
||||
|
||||
static void CancelAwake(LifetimeScope lifetimeScope)
|
||||
{
|
||||
WaitingList.Remove(lifetimeScope);
|
||||
}
|
||||
|
||||
static void AwakeWaitingChildren(LifetimeScope awakenParent)
|
||||
{
|
||||
if (WaitingList.Count <= 0) return;
|
||||
|
||||
using (ListPool<LifetimeScope>.Get(out var buffer))
|
||||
{
|
||||
for (var i = WaitingList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var waitingScope = WaitingList[i];
|
||||
if (waitingScope.parentReference.Type == awakenParent.GetType())
|
||||
{
|
||||
waitingScope.parentReference.Object = awakenParent;
|
||||
WaitingList.RemoveAt(i);
|
||||
buffer.Add(waitingScope);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var waitingScope in buffer)
|
||||
{
|
||||
waitingScope.Awake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
{
|
||||
if (WaitingList.Count <= 0)
|
||||
return;
|
||||
|
||||
using (ListPool<LifetimeScope>.Get(out var buffer))
|
||||
{
|
||||
for (var i = WaitingList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var waitingScope = WaitingList[i];
|
||||
if (waitingScope.gameObject.scene == scene)
|
||||
{
|
||||
WaitingList.RemoveAt(i);
|
||||
buffer.Add(waitingScope);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var waitingScope in buffer)
|
||||
{
|
||||
waitingScope.Awake(); // Re-throw if parent not found
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69462a1b64a3d4de2bcbd8707dd57ca1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,375 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using VContainer.Diagnostics;
|
||||
using VContainer.Internal;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
[DefaultExecutionOrder(-5000)]
|
||||
public partial class LifetimeScope : MonoBehaviour, IDisposable
|
||||
{
|
||||
public readonly struct ParentOverrideScope : IDisposable
|
||||
{
|
||||
public ParentOverrideScope(LifetimeScope nextParent)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
GlobalOverrideParents.Push(nextParent);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
GlobalOverrideParents.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct ExtraInstallationScope : IDisposable
|
||||
{
|
||||
public ExtraInstallationScope(IInstaller installer)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
GlobalExtraInstallers.Push(installer);
|
||||
}
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
GlobalExtraInstallers.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
public ParentReference parentReference;
|
||||
|
||||
[SerializeField]
|
||||
public bool autoRun = true;
|
||||
|
||||
[SerializeField]
|
||||
protected List<GameObject> autoInjectGameObjects;
|
||||
|
||||
string scopeName;
|
||||
|
||||
static readonly Stack<LifetimeScope> GlobalOverrideParents = new Stack<LifetimeScope>();
|
||||
static readonly Stack<IInstaller> GlobalExtraInstallers = new Stack<IInstaller>();
|
||||
static readonly object SyncRoot = new object();
|
||||
|
||||
public static LifetimeScope Create(IInstaller installer = null, string name = null)
|
||||
{
|
||||
var gameObject = new GameObject(name ?? "LifetimeScope");
|
||||
gameObject.SetActive(false);
|
||||
var newScope = gameObject.AddComponent<LifetimeScope>();
|
||||
if (installer != null)
|
||||
{
|
||||
newScope.localExtraInstallers.Add(installer);
|
||||
}
|
||||
gameObject.SetActive(true);
|
||||
return newScope;
|
||||
}
|
||||
|
||||
public static LifetimeScope Create(Action<IContainerBuilder> configuration, string name = null)
|
||||
=> Create(new ActionInstaller(configuration), name);
|
||||
|
||||
public static ParentOverrideScope EnqueueParent(LifetimeScope parent)
|
||||
=> new ParentOverrideScope(parent);
|
||||
|
||||
public static ExtraInstallationScope Enqueue(Action<IContainerBuilder> installing)
|
||||
=> new ExtraInstallationScope(new ActionInstaller(installing));
|
||||
|
||||
public static ExtraInstallationScope Enqueue(IInstaller installer)
|
||||
=> new ExtraInstallationScope(installer);
|
||||
|
||||
[Obsolete("LifetimeScope.PushParent is obsolete. Use LifetimeScope.EnqueueParent instead.", false)]
|
||||
public static ParentOverrideScope PushParent(LifetimeScope parent) => new ParentOverrideScope(parent);
|
||||
|
||||
[Obsolete("LifetimeScope.Push is obsolete. Use LifetimeScope.Enqueue instead.", false)]
|
||||
public static ExtraInstallationScope Push(Action<IContainerBuilder> installing) => Enqueue(installing);
|
||||
|
||||
[Obsolete("LifetimeScope.Push is obsolete. Use LifetimeScope.Enqueue instead.", false)]
|
||||
public static ExtraInstallationScope Push(IInstaller installer) => Enqueue(installer);
|
||||
|
||||
public static LifetimeScope Find<T>(Scene scene) where T : LifetimeScope => Find(typeof(T), scene);
|
||||
public static LifetimeScope Find<T>() where T : LifetimeScope => Find(typeof(T));
|
||||
|
||||
static LifetimeScope Find(Type type, Scene scene)
|
||||
{
|
||||
using (ListPool<GameObject>.Get(out var buffer))
|
||||
{
|
||||
scene.GetRootGameObjects(buffer);
|
||||
foreach (var gameObject in buffer)
|
||||
{
|
||||
var found = gameObject.GetComponentInChildren(type) as LifetimeScope;
|
||||
if (found != null)
|
||||
return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static LifetimeScope Find(Type type)
|
||||
{
|
||||
#if UNITY_2022_1_OR_NEWER
|
||||
return (LifetimeScope)FindAnyObjectByType(type);
|
||||
#else
|
||||
return (LifetimeScope)FindObjectOfType(type);
|
||||
#endif
|
||||
}
|
||||
|
||||
public IObjectResolver Container { get; private set; }
|
||||
public LifetimeScope Parent { get; private set; }
|
||||
|
||||
public bool IsRoot => VContainerSettings.Instance != null &&
|
||||
VContainerSettings.Instance.IsRootLifetimeScopeInstance(this);
|
||||
|
||||
readonly List<IInstaller> localExtraInstallers = new List<IInstaller>();
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
if (VContainerSettings.DiagnosticsEnabled && string.IsNullOrEmpty(scopeName))
|
||||
{
|
||||
scopeName = $"{name} ({gameObject.GetInstanceID()})";
|
||||
}
|
||||
try
|
||||
{
|
||||
if (autoRun)
|
||||
{
|
||||
Build();
|
||||
}
|
||||
}
|
||||
catch (VContainerParentTypeReferenceNotFound) when(!IsRoot)
|
||||
{
|
||||
if (WaitingList.Contains(this))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
EnqueueAwake(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
{
|
||||
DisposeCore();
|
||||
}
|
||||
|
||||
protected virtual void Configure(IContainerBuilder builder) { }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DisposeCore();
|
||||
if (this != null)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public void DisposeCore()
|
||||
{
|
||||
Container?.Dispose();
|
||||
Container = null;
|
||||
CancelAwake(this);
|
||||
if (VContainerSettings.DiagnosticsEnabled)
|
||||
{
|
||||
DiagnositcsContext.RemoveCollector(scopeName);
|
||||
}
|
||||
}
|
||||
|
||||
public void Build()
|
||||
{
|
||||
if (Parent == null)
|
||||
Parent = GetRuntimeParent();
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
if (VContainerSettings.Instance != null && Parent.IsRoot)
|
||||
{
|
||||
if (Parent.Container == null)
|
||||
Parent.Build();
|
||||
}
|
||||
|
||||
// ReSharper disable once PossibleNullReferenceException
|
||||
Parent.Container.CreateScope(builder =>
|
||||
{
|
||||
builder.RegisterBuildCallback(SetContainer);
|
||||
builder.ApplicationOrigin = this;
|
||||
builder.Diagnostics = VContainerSettings.DiagnosticsEnabled ? DiagnositcsContext.GetCollector(scopeName) : null;
|
||||
InstallTo(builder);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var builder = new ContainerBuilder
|
||||
{
|
||||
ApplicationOrigin = this,
|
||||
Diagnostics = VContainerSettings.DiagnosticsEnabled ? DiagnositcsContext.GetCollector(scopeName) : null,
|
||||
};
|
||||
builder.RegisterBuildCallback(SetContainer);
|
||||
InstallTo(builder);
|
||||
builder.Build();
|
||||
}
|
||||
|
||||
AwakeWaitingChildren(this);
|
||||
}
|
||||
|
||||
void SetContainer(IObjectResolver container)
|
||||
{
|
||||
Container = container;
|
||||
AutoInjectAll();
|
||||
}
|
||||
|
||||
public TScope CreateChild<TScope>(IInstaller installer = null, string childScopeName = null)
|
||||
where TScope : LifetimeScope
|
||||
{
|
||||
var childGameObject = new GameObject(childScopeName ?? "LifetimeScope (Child)");
|
||||
childGameObject.SetActive(false);
|
||||
if (IsRoot)
|
||||
{
|
||||
DontDestroyOnLoad(childGameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
childGameObject.transform.SetParent(transform, false);
|
||||
}
|
||||
var child = childGameObject.AddComponent<TScope>();
|
||||
if (installer != null)
|
||||
{
|
||||
child.localExtraInstallers.Add(installer);
|
||||
}
|
||||
child.parentReference.Object = this;
|
||||
childGameObject.SetActive(true);
|
||||
return child;
|
||||
}
|
||||
|
||||
public LifetimeScope CreateChild(IInstaller installer = null, string childScopeName = null)
|
||||
=> CreateChild<LifetimeScope>(installer, childScopeName);
|
||||
|
||||
public TScope CreateChild<TScope>(Action<IContainerBuilder> installation, string childScopeName = null)
|
||||
where TScope : LifetimeScope
|
||||
=> CreateChild<TScope>(new ActionInstaller(installation), childScopeName);
|
||||
|
||||
public LifetimeScope CreateChild(Action<IContainerBuilder> installation, string childScopeName = null)
|
||||
=> CreateChild<LifetimeScope>(new ActionInstaller(installation), childScopeName);
|
||||
|
||||
public TScope CreateChildFromPrefab<TScope>(TScope prefab, IInstaller installer = null)
|
||||
where TScope : LifetimeScope
|
||||
{
|
||||
var wasActive = prefab.gameObject.activeSelf;
|
||||
using (new ObjectResolverUnityExtensions.PrefabDirtyScope(prefab.gameObject))
|
||||
{
|
||||
if (wasActive)
|
||||
{
|
||||
prefab.gameObject.SetActive(false);
|
||||
}
|
||||
var child = Instantiate(prefab, transform, false);
|
||||
if (installer != null)
|
||||
{
|
||||
child.localExtraInstallers.Add(installer);
|
||||
}
|
||||
child.parentReference.Object = this;
|
||||
if (wasActive)
|
||||
{
|
||||
prefab.gameObject.SetActive(true);
|
||||
child.gameObject.SetActive(true);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
public TScope CreateChildFromPrefab<TScope>(TScope prefab, Action<IContainerBuilder> installation)
|
||||
where TScope : LifetimeScope
|
||||
=> CreateChildFromPrefab(prefab, new ActionInstaller(installation));
|
||||
|
||||
void InstallTo(IContainerBuilder builder)
|
||||
{
|
||||
Configure(builder);
|
||||
|
||||
foreach (var installer in localExtraInstallers)
|
||||
{
|
||||
installer.Install(builder);
|
||||
}
|
||||
localExtraInstallers.Clear();
|
||||
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (var installer in GlobalExtraInstallers)
|
||||
{
|
||||
installer.Install(builder);
|
||||
}
|
||||
}
|
||||
|
||||
builder.RegisterInstance<LifetimeScope>(this).AsSelf();
|
||||
EntryPointsBuilder.EnsureDispatcherRegistered(builder);
|
||||
}
|
||||
|
||||
protected virtual LifetimeScope FindParent() => null;
|
||||
|
||||
LifetimeScope GetRuntimeParent()
|
||||
{
|
||||
if (IsRoot) return null;
|
||||
|
||||
if (parentReference.Object != null)
|
||||
return parentReference.Object;
|
||||
|
||||
// Find via implementation
|
||||
var implParent = FindParent();
|
||||
if (implParent != null)
|
||||
{
|
||||
if (parentReference.Type != null && parentReference.Type != implParent.GetType()) {
|
||||
UnityEngine.Debug.LogWarning($"FindParent returned {implParent.GetType()} but parent reference type is {parentReference.Type}. This may be unintentional.");
|
||||
}
|
||||
return implParent;
|
||||
}
|
||||
|
||||
// Find in scene via type
|
||||
if (parentReference.Type != null && parentReference.Type != GetType())
|
||||
{
|
||||
var found = Find(parentReference.Type);
|
||||
if (found != null && found.Container != null)
|
||||
{
|
||||
return found;
|
||||
}
|
||||
throw new VContainerParentTypeReferenceNotFound(
|
||||
parentReference.Type,
|
||||
$"{name} could not found parent reference of type : {parentReference.Type}");
|
||||
}
|
||||
|
||||
lock (SyncRoot)
|
||||
{
|
||||
if (GlobalOverrideParents.Count > 0)
|
||||
{
|
||||
return GlobalOverrideParents.Peek();
|
||||
}
|
||||
}
|
||||
|
||||
// Find root from settings
|
||||
if (VContainerSettings.Instance != null)
|
||||
{
|
||||
return VContainerSettings.Instance.GetOrCreateRootLifetimeScopeInstance();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
void AutoInjectAll()
|
||||
{
|
||||
if (autoInjectGameObjects == null)
|
||||
return;
|
||||
|
||||
foreach (var target in autoInjectGameObjects)
|
||||
{
|
||||
if (target != null) // Check missing reference
|
||||
{
|
||||
Container.InjectGameObject(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b2c62ac3bcd44fb9e09835581422057
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,292 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using VContainer.Internal;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public static class ObjectResolverUnityExtensions
|
||||
{
|
||||
public readonly struct PrefabDirtyScope : IDisposable
|
||||
{
|
||||
readonly GameObject _prefab;
|
||||
readonly bool _madeDirty;
|
||||
|
||||
public PrefabDirtyScope(GameObject prefab)
|
||||
{
|
||||
_prefab = prefab;
|
||||
|
||||
#if UNITY_EDITOR && UNITY_2020_1_OR_NEWER
|
||||
_madeDirty = prefab.activeSelf && !UnityEditor.EditorUtility.IsDirty(_prefab);
|
||||
#else
|
||||
_madeDirty = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
#if UNITY_EDITOR && UNITY_2020_1_OR_NEWER
|
||||
if (_madeDirty)
|
||||
{
|
||||
UnityEditor.EditorUtility.ClearDirty(_prefab);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public static void InjectGameObject(this IObjectResolver resolver, GameObject gameObject)
|
||||
{
|
||||
void InjectGameObjectRecursive(GameObject current)
|
||||
{
|
||||
if (current == null) return;
|
||||
|
||||
using (ListPool<MonoBehaviour>.Get(out var buffer))
|
||||
{
|
||||
buffer.Clear();
|
||||
current.GetComponents(buffer);
|
||||
foreach (var monoBehaviour in buffer)
|
||||
{
|
||||
if (monoBehaviour != null)
|
||||
{ // Can be null if the MonoBehaviour's type wasn't found (e.g. if it was stripped)
|
||||
resolver.Inject(monoBehaviour);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var transform = current.transform;
|
||||
for (var i = 0; i < transform.childCount; i++)
|
||||
{
|
||||
var child = transform.GetChild(i);
|
||||
InjectGameObjectRecursive(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
InjectGameObjectRecursive(gameObject);
|
||||
}
|
||||
|
||||
public static T Instantiate<T>(this IObjectResolver resolver, T prefab)
|
||||
where T : Component
|
||||
{
|
||||
return resolver.Instantiate(prefab, prefab.transform.position, prefab.transform.rotation);
|
||||
}
|
||||
|
||||
public static T Instantiate<T>(this IObjectResolver resolver, T prefab, Transform parent, bool worldPositionStays = false)
|
||||
where T : Component
|
||||
{
|
||||
var wasActive = prefab.gameObject.activeSelf;
|
||||
using (new PrefabDirtyScope(prefab.gameObject))
|
||||
{
|
||||
prefab.gameObject.SetActive(false);
|
||||
|
||||
var instance = UnityEngine.Object.Instantiate(prefab, parent, worldPositionStays);
|
||||
|
||||
SetName(instance, prefab);
|
||||
|
||||
try
|
||||
{
|
||||
resolver.InjectGameObject(instance.gameObject);
|
||||
}
|
||||
finally
|
||||
{
|
||||
prefab.gameObject.SetActive(wasActive);
|
||||
instance.gameObject.SetActive(wasActive);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static T Instantiate<T>(
|
||||
this IObjectResolver resolver,
|
||||
T prefab,
|
||||
Vector3 position,
|
||||
Quaternion rotation)
|
||||
where T : Component
|
||||
{
|
||||
if (resolver.ApplicationOrigin is LifetimeScope scope)
|
||||
{
|
||||
return scope.Instantiate(prefab, position, rotation);
|
||||
}
|
||||
|
||||
return resolver.Instantiate(prefab, position, rotation, null);
|
||||
}
|
||||
|
||||
public static T Instantiate<T>(
|
||||
this IObjectResolver resolver,
|
||||
T prefab,
|
||||
Vector3 position,
|
||||
Quaternion rotation,
|
||||
Transform parent)
|
||||
where T : Component
|
||||
{
|
||||
var wasActive = prefab.gameObject.activeSelf;
|
||||
using (new PrefabDirtyScope(prefab.gameObject))
|
||||
{
|
||||
prefab.gameObject.SetActive(false);
|
||||
|
||||
var instance = UnityEngine.Object.Instantiate(prefab, position, rotation, parent);
|
||||
|
||||
SetName(instance, prefab);
|
||||
|
||||
try
|
||||
{
|
||||
resolver.InjectGameObject(instance.gameObject);
|
||||
}
|
||||
finally
|
||||
{
|
||||
prefab.gameObject.SetActive(wasActive);
|
||||
instance.gameObject.SetActive(wasActive);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
static T Instantiate<T>(this LifetimeScope scope, T prefab, Vector3 position, Quaternion rotation)
|
||||
where T : Component
|
||||
{
|
||||
var wasActive = prefab.gameObject.activeSelf;
|
||||
using (new PrefabDirtyScope(prefab.gameObject))
|
||||
{
|
||||
prefab.gameObject.SetActive(false);
|
||||
|
||||
T instance;
|
||||
if (scope.IsRoot)
|
||||
{
|
||||
instance = UnityEngine.Object.Instantiate(prefab, position, rotation);
|
||||
UnityEngine.Object.DontDestroyOnLoad(instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Into the same scene as LifetimeScope
|
||||
instance = UnityEngine.Object.Instantiate(prefab, position, rotation, scope.transform);
|
||||
instance.transform.SetParent(null);
|
||||
}
|
||||
|
||||
SetName(instance, prefab);
|
||||
|
||||
try
|
||||
{
|
||||
scope.Container.InjectGameObject(instance.gameObject);
|
||||
}
|
||||
finally
|
||||
{
|
||||
prefab.gameObject.SetActive(wasActive);
|
||||
instance.gameObject.SetActive(wasActive);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
static GameObject Instantiate(this LifetimeScope scope, GameObject prefab, Vector3 position, Quaternion rotation)
|
||||
{
|
||||
var wasActive = prefab.activeSelf;
|
||||
using (new PrefabDirtyScope(prefab))
|
||||
{
|
||||
prefab.SetActive(false);
|
||||
|
||||
GameObject instance;
|
||||
if (scope.IsRoot)
|
||||
{
|
||||
instance = UnityEngine.Object.Instantiate(prefab, position, rotation);
|
||||
UnityEngine.Object.DontDestroyOnLoad(instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Into the same scene as LifetimeScope
|
||||
instance = UnityEngine.Object.Instantiate(prefab, position, rotation, scope.transform);
|
||||
instance.transform.SetParent(null);
|
||||
}
|
||||
|
||||
SetName(instance, prefab);
|
||||
|
||||
try
|
||||
{
|
||||
scope.Container.InjectGameObject(instance);
|
||||
}
|
||||
finally
|
||||
{
|
||||
prefab.SetActive(wasActive);
|
||||
instance.SetActive(wasActive);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static GameObject Instantiate(this IObjectResolver resolver, GameObject prefab)
|
||||
{
|
||||
return resolver.Instantiate(prefab, prefab.transform.position, prefab.transform.rotation);
|
||||
}
|
||||
|
||||
public static GameObject Instantiate(this IObjectResolver resolver, GameObject prefab, Transform parent, bool worldPositionStays = false)
|
||||
{
|
||||
var wasActive = prefab.activeSelf;
|
||||
using (new PrefabDirtyScope(prefab))
|
||||
{
|
||||
prefab.SetActive(false);
|
||||
|
||||
GameObject instance = null;
|
||||
try
|
||||
{
|
||||
instance = UnityEngine.Object.Instantiate(prefab, parent, worldPositionStays);
|
||||
SetName(instance, prefab);
|
||||
resolver.InjectGameObject(instance);
|
||||
}
|
||||
finally
|
||||
{
|
||||
prefab.SetActive(wasActive);
|
||||
instance?.SetActive(wasActive);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static GameObject Instantiate(
|
||||
this IObjectResolver resolver,
|
||||
GameObject prefab,
|
||||
Vector3 position,
|
||||
Quaternion rotation)
|
||||
{
|
||||
if (resolver.ApplicationOrigin is LifetimeScope scope)
|
||||
{
|
||||
return scope.Instantiate(prefab, position, rotation);
|
||||
}
|
||||
|
||||
return resolver.Instantiate(prefab, position, rotation, null);
|
||||
}
|
||||
|
||||
public static GameObject Instantiate(
|
||||
this IObjectResolver resolver,
|
||||
GameObject prefab,
|
||||
Vector3 position,
|
||||
Quaternion rotation,
|
||||
Transform parent)
|
||||
{
|
||||
var wasActive = prefab.activeSelf;
|
||||
using (new PrefabDirtyScope(prefab))
|
||||
{
|
||||
prefab.SetActive(false);
|
||||
|
||||
var instance = UnityEngine.Object.Instantiate(prefab, position, rotation, parent);
|
||||
|
||||
SetName(instance, prefab);
|
||||
|
||||
try
|
||||
{
|
||||
resolver.InjectGameObject(instance);
|
||||
}
|
||||
finally
|
||||
{
|
||||
prefab.SetActive(wasActive);
|
||||
instance.SetActive(wasActive);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetName(UnityEngine.Object instance, UnityEngine.Object prefab)
|
||||
{
|
||||
if (VContainerSettings.Instance != null && VContainerSettings.Instance.RemoveClonePostfix)
|
||||
instance.name = prefab.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8a82741a10a46aa94d4ce08e372dc34
|
||||
timeCreated: 1606404902
|
||||
@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
[Serializable]
|
||||
public struct ParentReference : ISerializationCallbackReceiver
|
||||
{
|
||||
[SerializeField]
|
||||
public string TypeName;
|
||||
|
||||
[NonSerialized]
|
||||
public LifetimeScope Object;
|
||||
|
||||
public Type Type { get; private set; }
|
||||
|
||||
ParentReference(Type type)
|
||||
{
|
||||
Type = type;
|
||||
TypeName = type.FullName;
|
||||
Object = null;
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||
{
|
||||
TypeName = Type?.FullName;
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(TypeName))
|
||||
{
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
Type = assembly.GetType(TypeName);
|
||||
if (Type != null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ParentReference Create<T>() where T : LifetimeScope
|
||||
{
|
||||
return new ParentReference(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99eaede4c7734beba2b3abd51cd79b1b
|
||||
timeCreated: 1594621389
|
||||
@ -0,0 +1,212 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
using UnityEngine.LowLevel;
|
||||
using UnityEngine.PlayerLoop;
|
||||
#else
|
||||
using UnityEngine.Experimental.LowLevel;
|
||||
using UnityEngine.Experimental.PlayerLoop;
|
||||
#endif
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public struct VContainerInitialization {}
|
||||
public struct VContainerPostInitialization {}
|
||||
public struct VContainerStartup {}
|
||||
public struct VContainerPostStartup {}
|
||||
public struct VContainerFixedUpdate {}
|
||||
public struct VContainerPostFixedUpdate {}
|
||||
public struct VContainerUpdate {}
|
||||
public struct VContainerPostUpdate {}
|
||||
public struct VContainerLateUpdate {}
|
||||
public struct VContainerPostLateUpdate {}
|
||||
|
||||
enum PlayerLoopTiming
|
||||
{
|
||||
Initialization = 0,
|
||||
PostInitialization = 1,
|
||||
|
||||
Startup = 2,
|
||||
PostStartup = 3,
|
||||
|
||||
FixedUpdate = 4,
|
||||
PostFixedUpdate = 5,
|
||||
|
||||
Update = 6,
|
||||
PostUpdate = 7,
|
||||
|
||||
LateUpdate = 8,
|
||||
PostLateUpdate = 9,
|
||||
}
|
||||
|
||||
static class PlayerLoopHelper
|
||||
{
|
||||
static readonly PlayerLoopRunner[] Runners = new PlayerLoopRunner[10];
|
||||
static long initialized;
|
||||
|
||||
// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
public static void EnsureInitialized()
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref initialized, 1, 0) != 0)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < Runners.Length; i++)
|
||||
{
|
||||
Runners[i] = new PlayerLoopRunner();
|
||||
}
|
||||
|
||||
var playerLoop =
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
PlayerLoop.GetCurrentPlayerLoop();
|
||||
#else
|
||||
PlayerLoop.GetDefaultPlayerLoop();
|
||||
#endif
|
||||
|
||||
var copyList = playerLoop.subSystemList;
|
||||
|
||||
ref var initializeSystem = ref FindSubSystem(typeof(Initialization), copyList);
|
||||
InsertSubsystem(
|
||||
ref initializeSystem,
|
||||
null,
|
||||
new PlayerLoopSystem
|
||||
{
|
||||
type = typeof(VContainerInitialization),
|
||||
updateDelegate = Runners[(int)PlayerLoopTiming.Initialization].Run
|
||||
},
|
||||
new PlayerLoopSystem
|
||||
{
|
||||
type = typeof(VContainerPostInitialization),
|
||||
updateDelegate = Runners[(int)PlayerLoopTiming.PostInitialization].Run
|
||||
});
|
||||
|
||||
|
||||
ref var earlyUpdateSystem = ref FindSubSystem(typeof(EarlyUpdate), copyList);
|
||||
InsertSubsystem(
|
||||
ref earlyUpdateSystem,
|
||||
typeof(EarlyUpdate.ScriptRunDelayedStartupFrame),
|
||||
new PlayerLoopSystem
|
||||
{
|
||||
type = typeof(VContainerStartup),
|
||||
updateDelegate = Runners[(int)PlayerLoopTiming.Startup].Run
|
||||
},
|
||||
new PlayerLoopSystem
|
||||
{
|
||||
type = typeof(VContainerPostStartup),
|
||||
updateDelegate = Runners[(int)PlayerLoopTiming.PostStartup].Run
|
||||
});
|
||||
|
||||
ref var fixedUpdateSystem = ref FindSubSystem(typeof(FixedUpdate), copyList);
|
||||
InsertSubsystem(
|
||||
ref fixedUpdateSystem,
|
||||
typeof(FixedUpdate.ScriptRunBehaviourFixedUpdate),
|
||||
new PlayerLoopSystem
|
||||
{
|
||||
type = typeof(VContainerFixedUpdate),
|
||||
updateDelegate = Runners[(int)PlayerLoopTiming.FixedUpdate].Run
|
||||
},
|
||||
new PlayerLoopSystem
|
||||
{
|
||||
type = typeof(VContainerPostFixedUpdate),
|
||||
updateDelegate = Runners[(int)PlayerLoopTiming.PostFixedUpdate].Run
|
||||
});
|
||||
|
||||
ref var updateSystem = ref FindSubSystem(typeof(Update), copyList);
|
||||
InsertSubsystem(
|
||||
ref updateSystem,
|
||||
typeof(Update.ScriptRunBehaviourUpdate),
|
||||
new PlayerLoopSystem
|
||||
{
|
||||
type = typeof(VContainerUpdate),
|
||||
updateDelegate = Runners[(int)PlayerLoopTiming.Update].Run
|
||||
},
|
||||
new PlayerLoopSystem
|
||||
{
|
||||
type = typeof(VContainerPostUpdate),
|
||||
updateDelegate = Runners[(int)PlayerLoopTiming.PostUpdate].Run
|
||||
});
|
||||
|
||||
ref var lateUpdateSystem = ref FindSubSystem(typeof(PreLateUpdate), copyList);
|
||||
InsertSubsystem(
|
||||
ref lateUpdateSystem,
|
||||
typeof(PreLateUpdate.ScriptRunBehaviourLateUpdate),
|
||||
new PlayerLoopSystem
|
||||
{
|
||||
type = typeof(VContainerLateUpdate),
|
||||
updateDelegate = Runners[(int)PlayerLoopTiming.LateUpdate].Run
|
||||
},
|
||||
new PlayerLoopSystem
|
||||
{
|
||||
type = typeof(VContainerPostLateUpdate),
|
||||
updateDelegate = Runners[(int)PlayerLoopTiming.PostLateUpdate].Run
|
||||
});
|
||||
|
||||
playerLoop.subSystemList = copyList;
|
||||
PlayerLoop.SetPlayerLoop(playerLoop);
|
||||
}
|
||||
|
||||
public static void Dispatch(PlayerLoopTiming timing, IPlayerLoopItem item)
|
||||
{
|
||||
EnsureInitialized();
|
||||
Runners[(int)timing].Dispatch(item);
|
||||
}
|
||||
|
||||
static ref PlayerLoopSystem FindSubSystem(Type targetType, PlayerLoopSystem[] systems)
|
||||
{
|
||||
for (var i = 0; i < systems.Length; i++)
|
||||
{
|
||||
if (systems[i].type == targetType)
|
||||
return ref systems[i];
|
||||
}
|
||||
throw new InvalidOperationException($"{targetType.FullName} not in systems");
|
||||
}
|
||||
|
||||
static void InsertSubsystem(
|
||||
ref PlayerLoopSystem parentSystem,
|
||||
Type beforeType,
|
||||
PlayerLoopSystem newSystem,
|
||||
PlayerLoopSystem newPostSystem)
|
||||
{
|
||||
var source = parentSystem.subSystemList;
|
||||
var insertIndex = -1;
|
||||
if (beforeType == null)
|
||||
{
|
||||
insertIndex = 0;
|
||||
}
|
||||
for (var i = 0; i < source.Length; i++)
|
||||
{
|
||||
if (source[i].type == beforeType)
|
||||
{
|
||||
insertIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (insertIndex < 0)
|
||||
{
|
||||
throw new ArgumentException($"{beforeType.FullName} not in system {parentSystem} {parentSystem.type.FullName}");
|
||||
}
|
||||
|
||||
var dest = new PlayerLoopSystem[source.Length + 2];
|
||||
for (var i = 0; i < dest.Length; i++)
|
||||
{
|
||||
if (i == insertIndex)
|
||||
{
|
||||
dest[i] = newSystem;
|
||||
}
|
||||
else if (i == dest.Length - 1)
|
||||
{
|
||||
dest[i] = newPostSystem;
|
||||
}
|
||||
else if (i < insertIndex)
|
||||
{
|
||||
dest[i] = source[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[i] = source[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
parentSystem.subSystemList = dest;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efc97ba6489541959a28b1356de70b97
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,349 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
#if VCONTAINER_UNITASK_INTEGRATION
|
||||
using Cysharp.Threading.Tasks;
|
||||
#endif
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
sealed class StartableLoopItem : IPlayerLoopItem, IDisposable
|
||||
{
|
||||
readonly IEnumerable<IStartable> entries;
|
||||
readonly EntryPointExceptionHandler exceptionHandler;
|
||||
bool disposed;
|
||||
|
||||
public StartableLoopItem(
|
||||
IEnumerable<IStartable> entries,
|
||||
EntryPointExceptionHandler exceptionHandler)
|
||||
{
|
||||
this.entries = entries;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed) return false;
|
||||
foreach (var x in entries)
|
||||
{
|
||||
try
|
||||
{
|
||||
x.Start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptionHandler == null) throw;
|
||||
exceptionHandler.Publish(ex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose() => disposed = true;
|
||||
}
|
||||
|
||||
sealed class PostStartableLoopItem : IPlayerLoopItem, IDisposable
|
||||
{
|
||||
readonly IEnumerable<IPostStartable> entries;
|
||||
readonly EntryPointExceptionHandler exceptionHandler;
|
||||
bool disposed;
|
||||
|
||||
public PostStartableLoopItem(
|
||||
IEnumerable<IPostStartable> entries,
|
||||
EntryPointExceptionHandler exceptionHandler)
|
||||
{
|
||||
this.entries = entries;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed) return false;
|
||||
foreach (var x in entries)
|
||||
{
|
||||
try
|
||||
{
|
||||
x.PostStart();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptionHandler == null) throw;
|
||||
exceptionHandler.Publish(ex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose() => disposed = true;
|
||||
}
|
||||
|
||||
sealed class FixedTickableLoopItem : IPlayerLoopItem, IDisposable
|
||||
{
|
||||
readonly IReadOnlyList<IFixedTickable> entries;
|
||||
readonly EntryPointExceptionHandler exceptionHandler;
|
||||
bool disposed;
|
||||
|
||||
public FixedTickableLoopItem(
|
||||
IReadOnlyList<IFixedTickable> entries,
|
||||
EntryPointExceptionHandler exceptionHandler)
|
||||
{
|
||||
this.entries = entries;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed) return false;
|
||||
for (var i = 0; i < entries.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
entries[i].FixedTick();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptionHandler == null) throw;
|
||||
exceptionHandler.Publish(ex);
|
||||
}
|
||||
}
|
||||
return !disposed;
|
||||
}
|
||||
|
||||
public void Dispose() => disposed = true;
|
||||
}
|
||||
|
||||
sealed class PostFixedTickableLoopItem : IPlayerLoopItem, IDisposable
|
||||
{
|
||||
readonly IReadOnlyList<IPostFixedTickable> entries;
|
||||
readonly EntryPointExceptionHandler exceptionHandler;
|
||||
bool disposed;
|
||||
|
||||
public PostFixedTickableLoopItem(
|
||||
IReadOnlyList<IPostFixedTickable> entries,
|
||||
EntryPointExceptionHandler exceptionHandler)
|
||||
{
|
||||
this.entries = entries;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed) return false;
|
||||
for (var i = 0; i < entries.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
entries[i].PostFixedTick();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptionHandler == null) throw;
|
||||
exceptionHandler.Publish(ex);
|
||||
}
|
||||
}
|
||||
return !disposed;
|
||||
}
|
||||
|
||||
public void Dispose() => disposed = true;
|
||||
}
|
||||
|
||||
sealed class TickableLoopItem : IPlayerLoopItem, IDisposable
|
||||
{
|
||||
readonly IReadOnlyList<ITickable> entries;
|
||||
readonly EntryPointExceptionHandler exceptionHandler;
|
||||
bool disposed;
|
||||
|
||||
public TickableLoopItem(
|
||||
IReadOnlyList<ITickable> entries,
|
||||
EntryPointExceptionHandler exceptionHandler)
|
||||
{
|
||||
this.entries = entries;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed) return false;
|
||||
for (var i = 0; i < entries.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
entries[i].Tick();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptionHandler == null) throw;
|
||||
exceptionHandler.Publish(ex);
|
||||
}
|
||||
}
|
||||
return !disposed;
|
||||
}
|
||||
|
||||
public void Dispose() => disposed = true;
|
||||
}
|
||||
|
||||
sealed class PostTickableLoopItem : IPlayerLoopItem, IDisposable
|
||||
{
|
||||
readonly IReadOnlyList<IPostTickable> entries;
|
||||
readonly EntryPointExceptionHandler exceptionHandler;
|
||||
bool disposed;
|
||||
|
||||
public PostTickableLoopItem(
|
||||
IReadOnlyList<IPostTickable> entries,
|
||||
EntryPointExceptionHandler exceptionHandler)
|
||||
{
|
||||
this.entries = entries;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed) return false;
|
||||
for (var i = 0; i < entries.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
entries[i].PostTick();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptionHandler == null) throw;
|
||||
exceptionHandler.Publish(ex);
|
||||
}
|
||||
}
|
||||
return !disposed;
|
||||
}
|
||||
|
||||
public void Dispose() => disposed = true;
|
||||
}
|
||||
|
||||
sealed class LateTickableLoopItem : IPlayerLoopItem, IDisposable
|
||||
{
|
||||
readonly IReadOnlyList<ILateTickable> entries;
|
||||
readonly EntryPointExceptionHandler exceptionHandler;
|
||||
bool disposed;
|
||||
|
||||
public LateTickableLoopItem(
|
||||
IReadOnlyList<ILateTickable> entries,
|
||||
EntryPointExceptionHandler exceptionHandler)
|
||||
{
|
||||
this.entries = entries;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed) return false;
|
||||
for (var i = 0; i < entries.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
entries[i].LateTick();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptionHandler == null) throw;
|
||||
exceptionHandler.Publish(ex);
|
||||
}
|
||||
}
|
||||
return !disposed;
|
||||
}
|
||||
|
||||
public void Dispose() => disposed = true;
|
||||
}
|
||||
|
||||
sealed class PostLateTickableLoopItem : IPlayerLoopItem, IDisposable
|
||||
{
|
||||
readonly IReadOnlyList<IPostLateTickable> entries;
|
||||
readonly EntryPointExceptionHandler exceptionHandler;
|
||||
bool disposed;
|
||||
|
||||
public PostLateTickableLoopItem(
|
||||
IReadOnlyList<IPostLateTickable> entries,
|
||||
EntryPointExceptionHandler exceptionHandler)
|
||||
{
|
||||
this.entries = entries;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed) return false;
|
||||
for (var i = 0; i < entries.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
entries[i].PostLateTick();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptionHandler == null) throw;
|
||||
exceptionHandler.Publish(ex);
|
||||
}
|
||||
}
|
||||
return !disposed;
|
||||
}
|
||||
|
||||
public void Dispose() => disposed = true;
|
||||
}
|
||||
|
||||
#if VCONTAINER_UNITASK_INTEGRATION || UNITY_2021_3_OR_NEWER
|
||||
sealed class AsyncStartableLoopItem : IPlayerLoopItem, IDisposable
|
||||
{
|
||||
readonly IEnumerable<IAsyncStartable> entries;
|
||||
readonly EntryPointExceptionHandler exceptionHandler;
|
||||
readonly CancellationTokenSource cts = new CancellationTokenSource();
|
||||
bool disposed;
|
||||
|
||||
public AsyncStartableLoopItem(
|
||||
IEnumerable<IAsyncStartable> entries,
|
||||
EntryPointExceptionHandler exceptionHandler)
|
||||
{
|
||||
this.entries = entries;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (disposed) return false;
|
||||
foreach (var x in entries)
|
||||
{
|
||||
#if VCONTAINER_UNITASK_INTEGRATION
|
||||
var task = x.StartAsync(cts.Token);
|
||||
if (exceptionHandler != null)
|
||||
{
|
||||
task.Forget(ex => exceptionHandler.Publish(ex));
|
||||
}
|
||||
else
|
||||
{
|
||||
task.Forget();
|
||||
}
|
||||
#else
|
||||
try
|
||||
{
|
||||
var task = x.StartAsync(cts.Token);
|
||||
_ = task.Forget(exceptionHandler);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptionHandler == null) throw;
|
||||
exceptionHandler.Publish(ex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (entries)
|
||||
{
|
||||
if (disposed) return;
|
||||
disposed = true;
|
||||
}
|
||||
cts.Cancel();
|
||||
cts.Dispose();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8278b0aa962c47c59217aa3127037554
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,43 @@
|
||||
using VContainer.Internal;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
interface IPlayerLoopItem
|
||||
{
|
||||
bool MoveNext();
|
||||
}
|
||||
|
||||
sealed class PlayerLoopRunner
|
||||
{
|
||||
readonly FreeList<IPlayerLoopItem> runners = new FreeList<IPlayerLoopItem>(16);
|
||||
|
||||
int running;
|
||||
|
||||
public void Dispatch(IPlayerLoopItem item)
|
||||
{
|
||||
runners.Add(item);
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
var span =
|
||||
#if NETSTANDARD2_1
|
||||
runners.AsSpan();
|
||||
#else
|
||||
runners;
|
||||
#endif
|
||||
for (var i = 0; i < span.Length; i++)
|
||||
{
|
||||
var item = span[i];
|
||||
if (item != null)
|
||||
{
|
||||
var continued = item.MoveNext();
|
||||
if (!continued)
|
||||
{
|
||||
runners.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15c8b175a3194a3cb81a63541b402fe5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,43 @@
|
||||
#if VCONTAINER_ECS_INTEGRATION
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Entities;
|
||||
using VContainer.Internal;
|
||||
|
||||
namespace VContainer.Unity {
|
||||
public sealed class SystemRegistrationBuilder : RegistrationBuilder {
|
||||
readonly string worldName;
|
||||
Type systemGroupType;
|
||||
|
||||
internal SystemRegistrationBuilder(Type implementationType, string worldName)
|
||||
: base(implementationType, default) {
|
||||
this.worldName = worldName;
|
||||
InterfaceTypes = new List<Type> {
|
||||
typeof(ComponentSystemBase),
|
||||
implementationType
|
||||
};
|
||||
}
|
||||
|
||||
public override Registration Build() {
|
||||
var injector = InjectorCache.GetOrBuild(ImplementationType);
|
||||
|
||||
var parameters = new object[] {
|
||||
ImplementationType,
|
||||
worldName,
|
||||
systemGroupType,
|
||||
injector,
|
||||
Parameters
|
||||
};
|
||||
|
||||
Type type = typeof(SystemInstanceProvider<>).MakeGenericType(ImplementationType);
|
||||
var provider = (IInstanceProvider)Activator.CreateInstance(type, parameters);
|
||||
return new Registration(ImplementationType, Lifetime, InterfaceTypes, provider);
|
||||
}
|
||||
|
||||
public SystemRegistrationBuilder IntoGroup<T>() where T : ComponentSystemGroup {
|
||||
systemGroupType = typeof(T);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4040dd1c878f4e029f835a9f41a8df2d
|
||||
timeCreated: 1595004027
|
||||
@ -0,0 +1,70 @@
|
||||
#if VCONTAINER_ECS_INTEGRATION && UNITY_2022_2_OR_NEWER
|
||||
using System;
|
||||
using Unity.Entities;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public class UnmanagedSystemReference : IDisposable
|
||||
{
|
||||
private World world;
|
||||
|
||||
public SystemHandle Id { get; private set; }
|
||||
|
||||
public Type SystemType { get; private set; }
|
||||
|
||||
public UnmanagedSystemReference(Type systemType, SystemHandle id, World world)
|
||||
{
|
||||
this.world = world;
|
||||
SystemType = systemType;
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public ref T GetSystem<T>() where T : unmanaged, ISystem
|
||||
{
|
||||
if (typeof(T) != SystemType)
|
||||
{
|
||||
throw new ArgumentException($"System type mismatch. Expected: {SystemType}, Actual: {typeof(T)}");
|
||||
}
|
||||
|
||||
if (!world.Unmanaged.IsSystemValid(Id))
|
||||
{
|
||||
throw new InvalidOperationException($"System is not valid. SystemType: {SystemType}");
|
||||
}
|
||||
|
||||
return ref world.Unmanaged.GetUnsafeSystemRef<T>(Id);
|
||||
}
|
||||
|
||||
public ref T GetSystemFromDefaultWorld<T>() where T : unmanaged, ISystem
|
||||
{
|
||||
return ref World.DefaultGameObjectInjectionWorld.Unmanaged.GetUnsafeSystemRef<T>(Id);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (world.Unmanaged.IsSystemValid(Id))
|
||||
{
|
||||
world.DestroySystem(Id);
|
||||
}
|
||||
else if(world is null && World.DefaultGameObjectInjectionWorld.Unmanaged.IsSystemValid(Id))
|
||||
{
|
||||
World.DefaultGameObjectInjectionWorld.DestroySystem(Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class UnmanagedSystemReference<T> : UnmanagedSystemReference where T : unmanaged, ISystem
|
||||
{
|
||||
public UnmanagedSystemReference(SystemHandle id, World world) : base(typeof(T), id, world) { }
|
||||
|
||||
public ref T GetSystem(WorldUnmanaged world)
|
||||
{
|
||||
return ref world.GetUnsafeSystemRef<T>(Id);
|
||||
}
|
||||
|
||||
public ref T GetSystemFromDefaultWorld()
|
||||
{
|
||||
return ref World.DefaultGameObjectInjectionWorld.Unmanaged.GetUnsafeSystemRef<T>(Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44d895de5bf04a3586323e6d798df1df
|
||||
timeCreated: 1674376930
|
||||
@ -0,0 +1,47 @@
|
||||
#if VCONTAINER_ECS_INTEGRATION && UNITY_2022_2_OR_NEWER
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Entities;
|
||||
using VContainer.Internal;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public sealed class UnmanagedSystemRegistrationBuilder : RegistrationBuilder
|
||||
{
|
||||
readonly string worldName;
|
||||
Type systemGroupType;
|
||||
|
||||
internal UnmanagedSystemRegistrationBuilder(Type implementationType, string worldName)
|
||||
: base(implementationType, default)
|
||||
{
|
||||
this.worldName = worldName;
|
||||
Type refType = typeof(UnmanagedSystemReference<>);
|
||||
Type[] typeArgs = { implementationType };
|
||||
Type refImplType = refType.MakeGenericType(typeArgs);
|
||||
InterfaceTypes = new List<Type>
|
||||
{
|
||||
typeof(UnmanagedSystemReference),
|
||||
refImplType
|
||||
};
|
||||
}
|
||||
|
||||
public override Registration Build()
|
||||
{
|
||||
IInjector injector = InjectorCache.GetOrBuild(ImplementationType);
|
||||
var provider = new UnmanagedSystemInstanceProvider(
|
||||
ImplementationType,
|
||||
worldName,
|
||||
systemGroupType,
|
||||
injector,
|
||||
Parameters);
|
||||
return new Registration(ImplementationType, Lifetime, InterfaceTypes, provider);
|
||||
}
|
||||
|
||||
public UnmanagedSystemRegistrationBuilder IntoGroup<T>() where T : ComponentSystemGroup
|
||||
{
|
||||
systemGroupType = typeof(T);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a773d39e6f5c40ffa1c54b017f69de04
|
||||
timeCreated: 1671719145
|
||||
@ -0,0 +1,124 @@
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public sealed class VContainerSettings : ScriptableObject
|
||||
{
|
||||
public static VContainerSettings Instance { get; private set; }
|
||||
public static bool DiagnosticsEnabled => Instance != null && Instance.EnableDiagnostics;
|
||||
|
||||
static LifetimeScope rootLifetimeScopeInstance;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Set the Prefab to be the parent of the entire Project.")]
|
||||
public LifetimeScope RootLifetimeScope;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Enables the collection of information that can be viewed in the VContainerDiagnosticsWindow. Note: Performance degradation")]
|
||||
public bool EnableDiagnostics;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Disables script modification for LifetimeScope scripts.")]
|
||||
public bool DisableScriptModifier;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Removes (Clone) postfix in IObjectResolver.Instantiate() and IContainerBuilder.RegisterComponentInNewPrefab().")]
|
||||
public bool RemoveClonePostfix;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[UnityEditor.MenuItem("Assets/Create/VContainer/VContainer Settings")]
|
||||
public static void CreateAsset()
|
||||
{
|
||||
var path = UnityEditor.EditorUtility.SaveFilePanelInProject(
|
||||
"Save VContainerSettings",
|
||||
"VContainerSettings",
|
||||
"asset",
|
||||
string.Empty);
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return;
|
||||
|
||||
var newSettings = CreateInstance<VContainerSettings>();
|
||||
UnityEditor.AssetDatabase.CreateAsset(newSettings, path);
|
||||
|
||||
var preloadedAssets = UnityEditor.PlayerSettings.GetPreloadedAssets().ToList();
|
||||
preloadedAssets.RemoveAll(x => x is VContainerSettings);
|
||||
preloadedAssets.Add(newSettings);
|
||||
UnityEditor.PlayerSettings.SetPreloadedAssets(preloadedAssets.ToArray());
|
||||
}
|
||||
|
||||
public static void LoadInstanceFromPreloadAssets()
|
||||
{
|
||||
var preloadAsset = UnityEditor.PlayerSettings.GetPreloadedAssets().FirstOrDefault(x => x is VContainerSettings);
|
||||
if (preloadAsset is VContainerSettings instance)
|
||||
{
|
||||
instance.OnDisable();
|
||||
instance.OnEnable();
|
||||
}
|
||||
}
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
static void RuntimeInitialize()
|
||||
{
|
||||
// For editor, we need to load the Preload asset manually.
|
||||
LoadInstanceFromPreloadAssets();
|
||||
}
|
||||
#endif
|
||||
|
||||
public LifetimeScope GetOrCreateRootLifetimeScopeInstance()
|
||||
{
|
||||
if (RootLifetimeScope != null && rootLifetimeScopeInstance == null)
|
||||
{
|
||||
var activeBefore = RootLifetimeScope.gameObject.activeSelf;
|
||||
RootLifetimeScope.gameObject.SetActive(false);
|
||||
|
||||
rootLifetimeScopeInstance = Instantiate(RootLifetimeScope);
|
||||
DontDestroyOnLoad(rootLifetimeScopeInstance);
|
||||
rootLifetimeScopeInstance.gameObject.SetActive(true);
|
||||
|
||||
RootLifetimeScope.gameObject.SetActive(activeBefore);
|
||||
}
|
||||
return rootLifetimeScopeInstance;
|
||||
}
|
||||
|
||||
public bool IsRootLifetimeScopeInstance(LifetimeScope lifetimeScope) =>
|
||||
RootLifetimeScope == lifetimeScope || rootLifetimeScopeInstance == lifetimeScope;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
var activeScene = SceneManager.GetActiveScene();
|
||||
if (activeScene.isLoaded)
|
||||
{
|
||||
OnFirstSceneLoaded(activeScene, default);
|
||||
}
|
||||
else
|
||||
{
|
||||
SceneManager.sceneLoaded -= OnFirstSceneLoaded;
|
||||
SceneManager.sceneLoaded += OnFirstSceneLoaded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
void OnFirstSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
{
|
||||
if (RootLifetimeScope != null &&
|
||||
RootLifetimeScope.autoRun &&
|
||||
(rootLifetimeScopeInstance == null || rootLifetimeScopeInstance.Container == null))
|
||||
{
|
||||
GetOrCreateRootLifetimeScopeInstance();
|
||||
}
|
||||
SceneManager.sceneLoaded -= OnFirstSceneLoaded;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cf4d8df1d704d5689f3c69bd70d1cb9
|
||||
timeCreated: 1595759041
|
||||
@ -0,0 +1,48 @@
|
||||
#if VCONTAINER_ECS_INTEGRATION
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Entities;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public sealed class WorldConfigurationHelper : IDisposable
|
||||
{
|
||||
public readonly World World;
|
||||
|
||||
public WorldConfigurationHelper(IEnumerable<World> worlds, string targetWorldName)
|
||||
{
|
||||
foreach (var world in worlds)
|
||||
{
|
||||
if (world.Name == targetWorldName)
|
||||
{
|
||||
World = world;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (World is null)
|
||||
throw new VContainerException(typeof(WorldConfigurationHelper), $"World {targetWorldName} is not registered");
|
||||
}
|
||||
|
||||
public void SortSystems()
|
||||
{
|
||||
foreach (var system in World.Systems)
|
||||
{
|
||||
if (system is ComponentSystemGroup group)
|
||||
group.SortSystems();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var system in World.Systems)
|
||||
{
|
||||
if (system is IDisposable disposableSystem)
|
||||
{
|
||||
disposableSystem.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e747717446364b59ae6fc331aa779b27
|
||||
timeCreated: 1595137806
|
||||
@ -0,0 +1,26 @@
|
||||
#if VCONTAINER_ECS_INTEGRATION
|
||||
using System;
|
||||
using Unity.Entities;
|
||||
|
||||
namespace VContainer.Unity
|
||||
{
|
||||
public sealed class WorldRegistrationBuilder : RegistrationBuilder
|
||||
{
|
||||
readonly string name;
|
||||
readonly Action<World> initialization;
|
||||
|
||||
public WorldRegistrationBuilder(string name, Lifetime lifetime, Action<World> initialization)
|
||||
: base(typeof(World), lifetime)
|
||||
{
|
||||
this.name = name;
|
||||
this.initialization = initialization;
|
||||
}
|
||||
|
||||
public override Registration Build()
|
||||
{
|
||||
var provider = new WorldInstanceProvider(name, initialization);
|
||||
return new Registration(typeof(World), Lifetime, null, provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b731692c99e34ff984d1e308b27415ff
|
||||
timeCreated: 1595060757
|
||||
Reference in New Issue
Block a user