186e02c3ee
Dalamud's plugin validator flagged two issues on v0.1.0: - "The plugin does not register a config UI callback." - "The plugin does not register a main UI callback." v0.1.0 ships the RecipeData layer only - the actual SettingsWindow and MainWindow arrive with module 08 (UI). To pass validation and to give users a useful response when they click "Open Settings" or "Open Main" in the plugin installer, both callbacks now fire toast notifications via INotificationManager that point at the roadmap. The handlers wire up in the constructor right after the host build and unwire in DisposeAsync. INotificationManager joins the Block A Dalamud services in PluginHostDependencies + PluginHostFactory so the DI container also exposes it for later modules.
103 lines
4.2 KiB
C#
103 lines
4.2 KiB
C#
// Builds the generic-host DI container for Anvil. v0.1.0 is intentionally
|
|
// thin - module 01 (RecipeData) plus the bootstrap glue. Module 02+ will
|
|
// extend the Block B / Block C sections, not replace them.
|
|
//
|
|
// Every service registration goes through a factory lambda. The default
|
|
// AddSingleton<T>() overload reflects public constructors, and Anvil
|
|
// follows the Goatcorp / Dalamud convention of internal-sealed types -
|
|
// the activator would throw on the first resolve otherwise (HellionChat
|
|
// v1.5.0 C0 smoke documented this). The lambda compiles inside Anvil's
|
|
// namespace where internal access works.
|
|
|
|
using System.Collections.Generic;
|
|
using Anvil.Hosting;
|
|
using Anvil.Infrastructure.Logging;
|
|
using Anvil.RecipeData;
|
|
using Anvil.RecipeData.Internal;
|
|
using Anvil.SelfTest;
|
|
using Dalamud.Plugin;
|
|
using Dalamud.Plugin.SelfTest;
|
|
using Dalamud.Plugin.Services;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Anvil;
|
|
|
|
internal static class PluginHostFactory
|
|
{
|
|
public static IHost Build(Plugin plugin, PluginHostDependencies dependencies)
|
|
{
|
|
return new HostBuilder()
|
|
.UseContentRoot(dependencies.PluginInterface.ConfigDirectory.FullName)
|
|
.ConfigureLogging(logging =>
|
|
{
|
|
logging.ClearProviders();
|
|
logging.AddDalamudLogging(dependencies.PluginLog);
|
|
logging.SetMinimumLevel(LogLevel.Trace);
|
|
})
|
|
.ConfigureServices(services => ConfigureServices(services, plugin, dependencies))
|
|
.Build();
|
|
}
|
|
|
|
private static void ConfigureServices(
|
|
IServiceCollection services,
|
|
Plugin plugin,
|
|
PluginHostDependencies dependencies
|
|
)
|
|
{
|
|
// ---- Block A: Dalamud services ----
|
|
services.AddSingleton(dependencies);
|
|
services.AddSingleton(dependencies.PluginInterface);
|
|
services.AddSingleton(dependencies.PluginLog);
|
|
services.AddSingleton(dependencies.DataManager);
|
|
services.AddSingleton(dependencies.Framework);
|
|
services.AddSingleton(dependencies.SelfTestRegistry);
|
|
services.AddSingleton(dependencies.Notification);
|
|
|
|
// Self-reference. Lets services that genuinely need the plugin
|
|
// back-ref (later modules; v0.1.0 has none) reach it without a
|
|
// Plugin.Instance static.
|
|
services.AddSingleton(plugin);
|
|
|
|
services.AddSingleton<PluginLifecycle>(sp => new PluginLifecycle(
|
|
sp.GetRequiredService<IFramework>(),
|
|
sp.GetRequiredService<Plugin>()
|
|
));
|
|
|
|
// ---- Block B: Anvil singletons ----
|
|
services.AddSingleton<RecipeDataCatalog>(_ => new RecipeDataCatalog());
|
|
services.AddSingleton<LuminaRecipeAdapter>(sp => new LuminaRecipeAdapter(
|
|
sp.GetRequiredService<IDataManager>(),
|
|
sp.GetRequiredService<ILogger<LuminaRecipeAdapter>>(),
|
|
sp.GetRequiredService<RecipeDataCatalog>()
|
|
));
|
|
|
|
// ---- Block C: SelfTest steps (collected as IEnumerable<ISelfTestStep>) ----
|
|
services.AddSingleton<ISelfTestStep, RecipeDataAdapterLoadStep>(
|
|
sp => new RecipeDataAdapterLoadStep(
|
|
sp.GetRequiredService<RecipeDataCatalog>(),
|
|
sp.GetRequiredService<ILogger<RecipeDataAdapterLoadStep>>()
|
|
)
|
|
);
|
|
|
|
// ---- Block D: Hosted services (init order is registration order) ----
|
|
// RecipeData adapter runs first so the catalog is populated before
|
|
// the self-test registry sees its steps.
|
|
services.AddHostedService<RecipeDataLoadHostedService>(
|
|
sp => new RecipeDataLoadHostedService(
|
|
sp.GetRequiredService<IFramework>(),
|
|
sp.GetRequiredService<LuminaRecipeAdapter>(),
|
|
sp.GetRequiredService<ILogger<RecipeDataLoadHostedService>>()
|
|
)
|
|
);
|
|
services.AddHostedService<SelfTestRegistrationHostedService>(
|
|
sp => new SelfTestRegistrationHostedService(
|
|
sp.GetRequiredService<ISelfTestRegistry>(),
|
|
sp.GetRequiredService<IEnumerable<ISelfTestStep>>(),
|
|
sp.GetRequiredService<ILogger<SelfTestRegistrationHostedService>>()
|
|
)
|
|
);
|
|
}
|
|
}
|