mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-01-01 05:13:40 +01:00
feat: enable early loaded services to wait for provided services, some rewrites to make service kind declaration more explicit
This commit is contained in:
parent
0690f5dd2a
commit
2bdb837577
4 changed files with 37 additions and 26 deletions
|
|
@ -74,14 +74,17 @@ internal sealed class Dalamud : IServiceType
|
||||||
if (!configuration.IsResumeGameAfterPluginLoad)
|
if (!configuration.IsResumeGameAfterPluginLoad)
|
||||||
{
|
{
|
||||||
NativeFunctions.SetEvent(mainThreadContinueEvent);
|
NativeFunctions.SetEvent(mainThreadContinueEvent);
|
||||||
try
|
ServiceManager.InitializeEarlyLoadableServices()
|
||||||
{
|
.ContinueWith(t =>
|
||||||
_ = ServiceManager.InitializeEarlyLoadableServices();
|
{
|
||||||
}
|
if (t.IsCompletedSuccessfully)
|
||||||
catch (Exception e)
|
return;
|
||||||
{
|
|
||||||
Log.Error(e, "Service initialization failure");
|
Log.Error(t.Exception!, "Service initialization failure");
|
||||||
}
|
Util.Fatal(
|
||||||
|
"Dalamud failed to load all necessary services.\n\nThe game will continue, but you may not be able to use plugins.",
|
||||||
|
"Dalamud", false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1276,6 +1276,7 @@ internal class InterfaceManager : IDisposable, IServiceType
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an instance of InstanceManager with scene ready for use.
|
/// Represents an instance of InstanceManager with scene ready for use.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[ServiceManager.Service]
|
||||||
public class InterfaceManagerWithScene : IServiceType
|
public class InterfaceManagerWithScene : IServiceType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,9 @@ internal static class ServiceManager
|
||||||
None = 0,
|
None = 0,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Regular service.
|
/// Service that is loaded manually.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ManualService = 1 << 0,
|
ProvidedService = 1 << 0,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Service that is loaded asynchronously while the game starts.
|
/// Service that is loaded asynchronously while the game starts.
|
||||||
|
|
@ -90,7 +90,7 @@ internal static class ServiceManager
|
||||||
{
|
{
|
||||||
void ProvideService<T>(T service) where T : IServiceType
|
void ProvideService<T>(T service) where T : IServiceType
|
||||||
{
|
{
|
||||||
Debug.Assert(typeof(T).GetServiceKind().HasFlag(ServiceKind.ManualService), "Provided service must have Service attribute");
|
Debug.Assert(typeof(T).GetServiceKind().HasFlag(ServiceKind.ProvidedService), "Provided service must have Service attribute");
|
||||||
Service<T>.Provide(service);
|
Service<T>.Provide(service);
|
||||||
LoadedServices.Add(typeof(T));
|
LoadedServices.Add(typeof(T));
|
||||||
}
|
}
|
||||||
|
|
@ -119,23 +119,18 @@ internal static class ServiceManager
|
||||||
|
|
||||||
var serviceContainer = Service<ServiceContainer>.Get();
|
var serviceContainer = Service<ServiceContainer>.Get();
|
||||||
|
|
||||||
foreach (var serviceType in Assembly.GetExecutingAssembly().GetTypes())
|
foreach (var serviceType in Assembly.GetExecutingAssembly().GetTypes().Where(x => x.IsAssignableTo(typeof(IServiceType)) && !x.IsInterface && !x.IsAbstract))
|
||||||
{
|
{
|
||||||
var serviceKind = serviceType.GetServiceKind();
|
var serviceKind = serviceType.GetServiceKind();
|
||||||
if (serviceKind is ServiceKind.None)
|
if (serviceKind is ServiceKind.None)
|
||||||
continue;
|
throw new Exception($"Service<{serviceType.FullName}> did not specify a kind");
|
||||||
|
|
||||||
// Let IoC know about the interfaces this service implements
|
// Let IoC know about the interfaces this service implements
|
||||||
serviceContainer.RegisterInterfaces(serviceType);
|
serviceContainer.RegisterInterfaces(serviceType);
|
||||||
|
|
||||||
// Scoped service do not go through Service<T> and are never early loaded
|
// Scoped service do not go through Service<T> and are never early loaded
|
||||||
// Manual services are provided
|
if (serviceKind.HasFlag(ServiceKind.ScopedService))
|
||||||
if (serviceKind.HasFlag(ServiceKind.ScopedService) || serviceKind.HasFlag(ServiceKind.ManualService))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Debug.Assert(
|
|
||||||
!serviceKind.HasFlag(ServiceKind.ManualService) && !serviceKind.HasFlag(ServiceKind.ScopedService),
|
|
||||||
"Regular and scoped services should never be loaded early");
|
|
||||||
|
|
||||||
var genericWrappedServiceType = typeof(Service<>).MakeGenericType(serviceType);
|
var genericWrappedServiceType = typeof(Service<>).MakeGenericType(serviceType);
|
||||||
|
|
||||||
|
|
@ -147,9 +142,14 @@ internal static class ServiceManager
|
||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
|
|
||||||
|
getAsyncTaskMap[serviceType] = getTask;
|
||||||
|
|
||||||
|
// We don't actually need to load provided services, something else does
|
||||||
|
if (serviceKind.HasFlag(ServiceKind.ProvidedService))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (serviceKind.HasFlag(ServiceKind.BlockingEarlyLoadedService))
|
if (serviceKind.HasFlag(ServiceKind.BlockingEarlyLoadedService))
|
||||||
{
|
{
|
||||||
getAsyncTaskMap[serviceType] = getTask;
|
|
||||||
blockingEarlyLoadingServices.Add(serviceType);
|
blockingEarlyLoadingServices.Add(serviceType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -191,13 +191,13 @@ internal static class ServiceManager
|
||||||
var hasDeps = true;
|
var hasDeps = true;
|
||||||
foreach (var dependency in dependencyServicesMap[serviceType])
|
foreach (var dependency in dependencyServicesMap[serviceType])
|
||||||
{
|
{
|
||||||
var depServiceKind = dependency.GetServiceKind();
|
var depUnderlyingServiceType = dependency.GetGenericArguments().First();
|
||||||
var depResolveTask = getAsyncTaskMap.GetValueOrDefault(dependency);
|
var depResolveTask = getAsyncTaskMap.GetValueOrDefault(depUnderlyingServiceType);
|
||||||
|
|
||||||
if (depResolveTask == null && (depServiceKind.HasFlag(ServiceKind.EarlyLoadedService) || depServiceKind.HasFlag(ServiceKind.BlockingEarlyLoadedService)))
|
if (depResolveTask == null)
|
||||||
{
|
{
|
||||||
Log.Error("{Type}: {Dependency} has no resolver task, is it early loaded or blocking early loaded?", serviceType.FullName!, dependency.FullName!);
|
Log.Error("{Type}: {Dependency} has no resolver task", serviceType.FullName!, dependency.FullName!);
|
||||||
Debug.Assert(false, $"No resolver for dependent service {dependency.FullName}");
|
Debug.Assert(false, $"No resolver for dependent service {depUnderlyingServiceType.FullName}");
|
||||||
}
|
}
|
||||||
else if (depResolveTask is { IsCompleted: false })
|
else if (depResolveTask is { IsCompleted: false })
|
||||||
{
|
{
|
||||||
|
|
@ -386,7 +386,7 @@ internal static class ServiceManager
|
||||||
if (attr.IsAssignableTo(typeof(ScopedService)))
|
if (attr.IsAssignableTo(typeof(ScopedService)))
|
||||||
return ServiceKind.ScopedService;
|
return ServiceKind.ScopedService;
|
||||||
|
|
||||||
return ServiceKind.ManualService;
|
return ServiceKind.ProvidedService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,8 @@ internal static class Service<T> where T : IServiceType
|
||||||
public static List<Type> GetDependencyServices()
|
public static List<Type> GetDependencyServices()
|
||||||
{
|
{
|
||||||
var res = new List<Type>();
|
var res = new List<Type>();
|
||||||
|
|
||||||
|
ServiceManager.Log.Verbose("Service<{0}>: Getting dependencies", typeof(T).Name);
|
||||||
|
|
||||||
var ctor = GetServiceConstructor();
|
var ctor = GetServiceConstructor();
|
||||||
if (ctor != null)
|
if (ctor != null)
|
||||||
|
|
@ -181,6 +183,11 @@ internal static class Service<T> where T : IServiceType
|
||||||
res.Add(serviceType);
|
res.Add(serviceType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var type in res)
|
||||||
|
{
|
||||||
|
ServiceManager.Log.Verbose("Service<{0}>: => Dependency: {1}", typeof(T).Name, type.Name);
|
||||||
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
.Distinct()
|
.Distinct()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue