Initial commit: Unity WordConnect project

This commit is contained in:
2025-08-01 19:12:05 +08:00
commit f14db75802
3503 changed files with 448337 additions and 0 deletions

View File

@ -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);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 48336697de89414886abfd92d2ac9218
timeCreated: 1593187294

View File

@ -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;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c8d9071a8a0a4915bc374a6691d9aebd
timeCreated: 1592589484

View File

@ -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
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5e9b811ca5454c89a0905e0127ea62b8
timeCreated: 1593020228

View File

@ -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;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 792f76fbc1dd409887297cdfe8aa3aa9
timeCreated: 1653803074

View File

@ -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();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e8b5d8a26f2d409fb1de359daa251bde
timeCreated: 1614397266

View File

@ -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);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3b60c8fd4709435d82c04a947e096fa3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
namespace VContainer.Unity
{
public interface IInstaller
{
void Install(IContainerBuilder builder);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 22d89c28d4364858a331cd5f669e58b7
timeCreated: 1593187294

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d7d46367acb94de1966baea5febbf70c
timeCreated: 1637900702

View File

@ -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;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3eaf1bb53ea4494484290e95207cc8f3
timeCreated: 1620020530

View File

@ -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;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8feb76212733400e80e88bc385685993
timeCreated: 1619932417

View File

@ -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;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f18c3e4b45d349ca8f1d388dca5bc8b8
timeCreated: 1619933144

View File

@ -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;
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 51a9e9ed532b41898ab9e5f82ea2781f
timeCreated: 1619932830

View File

@ -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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: baa43b4b3a9a4d1895436d98f4c539e4
timeCreated: 1595083942

View File

@ -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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c3e078788acd49f292b76c0a778b1a45
timeCreated: 1671719884

View File

@ -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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c152c2c135444258b6b6bc730bdb1f64
timeCreated: 1595059160

View File

@ -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
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 69462a1b64a3d4de2bcbd8707dd57ca1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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);
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1b2c62ac3bcd44fb9e09835581422057
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a8a82741a10a46aa94d4ce08e372dc34
timeCreated: 1606404902

View File

@ -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));
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 99eaede4c7734beba2b3abd51cd79b1b
timeCreated: 1594621389

View File

@ -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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: efc97ba6489541959a28b1356de70b97
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8278b0aa962c47c59217aa3127037554
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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);
}
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 15c8b175a3194a3cb81a63541b402fe5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4040dd1c878f4e029f835a9f41a8df2d
timeCreated: 1595004027

View File

@ -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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 44d895de5bf04a3586323e6d798df1df
timeCreated: 1674376930

View File

@ -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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a773d39e6f5c40ffa1c54b017f69de04
timeCreated: 1671719145

View File

@ -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;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9cf4d8df1d704d5689f3c69bd70d1cb9
timeCreated: 1595759041

View File

@ -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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e747717446364b59ae6fc331aa779b27
timeCreated: 1595137806

View File

@ -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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b731692c99e34ff984d1e308b27415ff
timeCreated: 1595060757