DI: Build root scope async while still registering events/commands during plugin init
This commit is contained in:
parent
adddbc452c
commit
f63e70b0c4
@ -1,141 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.Command;
|
||||
using Dalamud.Game.Gui;
|
||||
using ECommons.Schedulers;
|
||||
using Pal.Client.Configuration;
|
||||
using Pal.Client.DependencyInjection;
|
||||
using Pal.Client.Extensions;
|
||||
using Pal.Client.Properties;
|
||||
using Pal.Client.Rendering;
|
||||
using Pal.Client.Windows;
|
||||
|
||||
namespace Pal.Client.Commands
|
||||
{
|
||||
// should restructure this when more commands exist, if that ever happens
|
||||
// this command is more-or-less a debug/troubleshooting command, if anything
|
||||
internal sealed class PalCommand : IDisposable
|
||||
{
|
||||
private readonly IPalacePalConfiguration _configuration;
|
||||
private readonly CommandManager _commandManager;
|
||||
private readonly Chat _chat;
|
||||
private readonly StatisticsService _statisticsService;
|
||||
private readonly ConfigWindow _configWindow;
|
||||
private readonly TerritoryState _territoryState;
|
||||
private readonly FloorService _floorService;
|
||||
private readonly ClientState _clientState;
|
||||
|
||||
public PalCommand(
|
||||
IPalacePalConfiguration configuration,
|
||||
CommandManager commandManager,
|
||||
Chat chat,
|
||||
StatisticsService statisticsService,
|
||||
ConfigWindow configWindow,
|
||||
TerritoryState territoryState,
|
||||
FloorService floorService,
|
||||
ClientState clientState)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_commandManager = commandManager;
|
||||
_chat = chat;
|
||||
_statisticsService = statisticsService;
|
||||
_configWindow = configWindow;
|
||||
_territoryState = territoryState;
|
||||
_floorService = floorService;
|
||||
_clientState = clientState;
|
||||
|
||||
_commandManager.AddHandler("/pal", new CommandInfo(OnCommand)
|
||||
{
|
||||
HelpMessage = Localization.Command_pal_HelpText
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_commandManager.RemoveHandler("/pal");
|
||||
}
|
||||
|
||||
private void OnCommand(string command, string arguments)
|
||||
{
|
||||
if (_configuration.FirstUse)
|
||||
{
|
||||
_chat.Error(Localization.Error_FirstTimeSetupRequired);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
arguments = arguments.Trim();
|
||||
switch (arguments)
|
||||
{
|
||||
case "stats":
|
||||
_statisticsService.ShowGlobalStatistics();
|
||||
break;
|
||||
|
||||
case "test-connection":
|
||||
case "tc":
|
||||
_configWindow.IsOpen = true;
|
||||
var _ = new TickScheduler(() => _configWindow.TestConnection());
|
||||
break;
|
||||
|
||||
#if DEBUG
|
||||
case "update-saves":
|
||||
LocalState.UpdateAll();
|
||||
_chat.Message(Localization.Command_pal_updatesaves);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case "":
|
||||
case "config":
|
||||
_configWindow.Toggle();
|
||||
break;
|
||||
|
||||
case "near":
|
||||
DebugNearest(_ => true);
|
||||
break;
|
||||
|
||||
case "tnear":
|
||||
DebugNearest(m => m.Type == Marker.EType.Trap);
|
||||
break;
|
||||
|
||||
case "hnear":
|
||||
DebugNearest(m => m.Type == Marker.EType.Hoard);
|
||||
break;
|
||||
|
||||
default:
|
||||
_chat.Error(string.Format(Localization.Command_pal_UnknownSubcommand, arguments,
|
||||
command));
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_chat.Error(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void DebugNearest(Predicate<Marker> predicate)
|
||||
{
|
||||
if (!_territoryState.IsInDeepDungeon())
|
||||
return;
|
||||
|
||||
var state = _floorService.GetFloorMarkers(_clientState.TerritoryType);
|
||||
var playerPosition = _clientState.LocalPlayer?.Position;
|
||||
if (playerPosition == null)
|
||||
return;
|
||||
_chat.Message($"{playerPosition}");
|
||||
|
||||
var nearbyMarkers = state.Markers
|
||||
.Where(m => predicate(m))
|
||||
.Where(m => m.RenderElement != null && m.RenderElement.Color != RenderData.ColorInvisible)
|
||||
.Select(m => new { m, distance = (playerPosition - m.Position)?.Length() ?? float.MaxValue })
|
||||
.OrderBy(m => m.distance)
|
||||
.Take(5)
|
||||
.ToList();
|
||||
foreach (var nearbyMarker in nearbyMarkers)
|
||||
_chat.UnformattedMessage(
|
||||
$"{nearbyMarker.distance:F2} - {nearbyMarker.m.Type} {nearbyMarker.m.NetworkId?.ToPartialId(length: 8)} - {nearbyMarker.m.Position}");
|
||||
}
|
||||
}
|
||||
}
|
31
Pal.Client/Commands/PalConfigCommand.cs
Normal file
31
Pal.Client/Commands/PalConfigCommand.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using Dalamud.Interface.Windowing;
|
||||
using Pal.Client.Configuration;
|
||||
using Pal.Client.Windows;
|
||||
|
||||
namespace Pal.Client.Commands
|
||||
{
|
||||
internal class PalConfigCommand
|
||||
{
|
||||
private readonly IPalacePalConfiguration _configuration;
|
||||
private readonly AgreementWindow _agreementWindow;
|
||||
private readonly ConfigWindow _configWindow;
|
||||
|
||||
public PalConfigCommand(
|
||||
IPalacePalConfiguration configuration,
|
||||
AgreementWindow agreementWindow,
|
||||
ConfigWindow configWindow)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_agreementWindow = agreementWindow;
|
||||
_configWindow = configWindow;
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
if (_configuration.FirstUse)
|
||||
_agreementWindow.IsOpen = true;
|
||||
else
|
||||
_configWindow.Toggle();
|
||||
}
|
||||
}
|
||||
}
|
67
Pal.Client/Commands/PalNearCommand.cs
Normal file
67
Pal.Client/Commands/PalNearCommand.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Pal.Client.DependencyInjection;
|
||||
using Pal.Client.Extensions;
|
||||
using Pal.Client.Rendering;
|
||||
|
||||
namespace Pal.Client.Commands
|
||||
{
|
||||
internal sealed class PalNearCommand
|
||||
{
|
||||
private readonly Chat _chat;
|
||||
private readonly ClientState _clientState;
|
||||
private readonly TerritoryState _territoryState;
|
||||
private readonly FloorService _floorService;
|
||||
|
||||
public PalNearCommand(Chat chat, ClientState clientState, TerritoryState territoryState,
|
||||
FloorService floorService)
|
||||
{
|
||||
_chat = chat;
|
||||
_clientState = clientState;
|
||||
_territoryState = territoryState;
|
||||
_floorService = floorService;
|
||||
}
|
||||
|
||||
public void Execute(string arguments)
|
||||
{
|
||||
switch (arguments)
|
||||
{
|
||||
default:
|
||||
DebugNearest(_ => true);
|
||||
break;
|
||||
|
||||
case "tnear":
|
||||
DebugNearest(m => m.Type == Marker.EType.Trap);
|
||||
break;
|
||||
|
||||
case "hnear":
|
||||
DebugNearest(m => m.Type == Marker.EType.Hoard);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void DebugNearest(Predicate<Marker> predicate)
|
||||
{
|
||||
if (!_territoryState.IsInDeepDungeon())
|
||||
return;
|
||||
|
||||
var state = _floorService.GetFloorMarkers(_clientState.TerritoryType);
|
||||
var playerPosition = _clientState.LocalPlayer?.Position;
|
||||
if (playerPosition == null)
|
||||
return;
|
||||
_chat.Message($"{playerPosition}");
|
||||
|
||||
var nearbyMarkers = state.Markers
|
||||
.Where(m => predicate(m))
|
||||
.Where(m => m.RenderElement != null && m.RenderElement.Color != RenderData.ColorInvisible)
|
||||
.Select(m => new { m, distance = (playerPosition - m.Position)?.Length() ?? float.MaxValue })
|
||||
.OrderBy(m => m.distance)
|
||||
.Take(5)
|
||||
.ToList();
|
||||
foreach (var nearbyMarker in nearbyMarkers)
|
||||
_chat.UnformattedMessage(
|
||||
$"{nearbyMarker.distance:F2} - {nearbyMarker.m.Type} {nearbyMarker.m.NetworkId?.ToPartialId(length: 8)} - {nearbyMarker.m.Position}");
|
||||
}
|
||||
}
|
||||
}
|
18
Pal.Client/Commands/PalStatsCommand.cs
Normal file
18
Pal.Client/Commands/PalStatsCommand.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using Pal.Client.DependencyInjection;
|
||||
|
||||
namespace Pal.Client.Commands
|
||||
{
|
||||
internal sealed class PalStatsCommand
|
||||
{
|
||||
private readonly StatisticsService _statisticsService;
|
||||
|
||||
public PalStatsCommand(StatisticsService statisticsService)
|
||||
{
|
||||
_statisticsService = statisticsService;
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
=> _statisticsService.ShowGlobalStatistics();
|
||||
}
|
||||
}
|
20
Pal.Client/Commands/PalTestConnectionCommand.cs
Normal file
20
Pal.Client/Commands/PalTestConnectionCommand.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using ECommons.Schedulers;
|
||||
using Pal.Client.Windows;
|
||||
|
||||
namespace Pal.Client.Commands
|
||||
{
|
||||
internal sealed class PalTestConnectionCommand
|
||||
{
|
||||
private readonly ConfigWindow _configWindow;
|
||||
|
||||
public PalTestConnectionCommand(ConfigWindow configWindow)
|
||||
{
|
||||
_configWindow = configWindow;
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
var _ = new TickScheduler(() => _configWindow.TestConnection());
|
||||
}
|
||||
}
|
||||
}
|
@ -52,7 +52,8 @@ namespace Pal.Client
|
||||
|
||||
public string Name => Localization.Palace_Pal;
|
||||
|
||||
public DependencyInjectionContext(DalamudPluginInterface pluginInterface,
|
||||
public DependencyInjectionContext(
|
||||
DalamudPluginInterface pluginInterface,
|
||||
ClientState clientState,
|
||||
GameGui gameGui,
|
||||
ChatGui chatGui,
|
||||
@ -70,7 +71,6 @@ namespace Pal.Client
|
||||
#pragma warning restore CS0612
|
||||
|
||||
// set up logging
|
||||
CancellationToken token = _initCts.Token;
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
services.AddLogging(builder =>
|
||||
builder.AddFilter("Pal", LogLevel.Trace)
|
||||
@ -100,32 +100,37 @@ namespace Pal.Client
|
||||
services.AddTransient<JsonMigration>();
|
||||
|
||||
// plugin-specific
|
||||
services.AddSingleton<Plugin>();
|
||||
services.AddSingleton<DebugState>();
|
||||
services.AddSingleton<Hooks>();
|
||||
services.AddSingleton<RemoteApi>();
|
||||
services.AddSingleton<ConfigurationManager>();
|
||||
services.AddSingleton<IPalacePalConfiguration>(sp => sp.GetRequiredService<ConfigurationManager>().Load());
|
||||
services.AddScoped<DependencyInjectionLoader>();
|
||||
services.AddScoped<DebugState>();
|
||||
services.AddScoped<Hooks>();
|
||||
services.AddScoped<RemoteApi>();
|
||||
services.AddScoped<ConfigurationManager>();
|
||||
services.AddScoped<IPalacePalConfiguration>(sp => sp.GetRequiredService<ConfigurationManager>().Load());
|
||||
services.AddTransient<RepoVerification>();
|
||||
services.AddSingleton<PalCommand>();
|
||||
|
||||
// commands
|
||||
services.AddScoped<PalConfigCommand>();
|
||||
services.AddScoped<PalNearCommand>();
|
||||
services.AddScoped<PalStatsCommand>();
|
||||
services.AddScoped<PalTestConnectionCommand>();
|
||||
|
||||
// territory & marker related services
|
||||
services.AddSingleton<TerritoryState>();
|
||||
services.AddSingleton<FrameworkService>();
|
||||
services.AddSingleton<ChatService>();
|
||||
services.AddSingleton<FloorService>();
|
||||
services.AddSingleton<ImportService>();
|
||||
services.AddScoped<TerritoryState>();
|
||||
services.AddScoped<FrameworkService>();
|
||||
services.AddScoped<ChatService>();
|
||||
services.AddScoped<FloorService>();
|
||||
services.AddScoped<ImportService>();
|
||||
|
||||
// windows & related services
|
||||
services.AddSingleton<AgreementWindow>();
|
||||
services.AddSingleton<ConfigWindow>();
|
||||
services.AddTransient<StatisticsService>();
|
||||
services.AddSingleton<StatisticsWindow>();
|
||||
services.AddScoped<AgreementWindow>();
|
||||
services.AddScoped<ConfigWindow>();
|
||||
services.AddScoped<StatisticsService>();
|
||||
services.AddScoped<StatisticsWindow>();
|
||||
|
||||
// these should maybe be scoped
|
||||
services.AddScoped<SimpleRenderer>();
|
||||
services.AddScoped<SplatoonRenderer>();
|
||||
services.AddSingleton<RenderAdapter>();
|
||||
services.AddScoped<RenderAdapter>();
|
||||
|
||||
// queue handling
|
||||
services.AddTransient<IQueueOnFrameworkThread.Handler<QueuedImport>, QueuedImport.Handler>();
|
||||
@ -161,63 +166,8 @@ namespace Pal.Client
|
||||
// There's 2-3 seconds of slowdown primarily caused by the sqlite init, but that needs to happen for
|
||||
// config stuff.
|
||||
_logger = _serviceProvider.GetRequiredService<ILogger<DependencyInjectionContext>>();
|
||||
_logger.LogInformation("Service container built, triggering async init");
|
||||
Task.Run(async () =>
|
||||
{
|
||||
using IDisposable? logScope = _logger.BeginScope("AsyncInit");
|
||||
|
||||
Chat? chat = null;
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Starting async init");
|
||||
chat = _serviceProvider.GetService<Chat>();
|
||||
|
||||
// initialize database
|
||||
await using (var scope = _serviceProvider.CreateAsyncScope())
|
||||
{
|
||||
_logger.LogInformation("Loading database & running migrations");
|
||||
await using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
|
||||
await dbContext.Database.MigrateAsync(token);
|
||||
|
||||
_logger.LogInformation("Completed database migrations");
|
||||
}
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
// v1 migration: config migration for import history, json migration for markers
|
||||
_serviceProvider.GetRequiredService<ConfigurationManager>().Migrate();
|
||||
await _serviceProvider.GetRequiredService<JsonMigration>().MigrateAsync(token);
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
// windows that have logic to open on startup
|
||||
_serviceProvider.GetRequiredService<AgreementWindow>();
|
||||
|
||||
// initialize components that are mostly self-contained/self-registered
|
||||
_serviceProvider.GetRequiredService<Hooks>();
|
||||
_serviceProvider.GetRequiredService<PalCommand>();
|
||||
_serviceProvider.GetRequiredService<FrameworkService>();
|
||||
_serviceProvider.GetRequiredService<ChatService>();
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
_plugin = new Plugin(pluginInterface, _serviceProvider);
|
||||
|
||||
_logger.LogInformation("Async init complete");
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (TaskCanceledException e)
|
||||
{
|
||||
_logger.LogError(e, "Task cancelled");
|
||||
chat?.Error("Plugin was unloaded before it finished loading.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Async load failed");
|
||||
chat?.Error($"Async loading failed: {e.GetType()}: {e.Message}");
|
||||
}
|
||||
});
|
||||
_logger.LogInformation("Service container built, creating plugin");
|
||||
_plugin = new Plugin(pluginInterface, _serviceProvider, _initCts.Token);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
107
Pal.Client/DependencyInjectionLoader.cs
Normal file
107
Pal.Client/DependencyInjectionLoader.cs
Normal file
@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Pal.Client.Commands;
|
||||
using Pal.Client.Configuration;
|
||||
using Pal.Client.Configuration.Legacy;
|
||||
using Pal.Client.Database;
|
||||
using Pal.Client.DependencyInjection;
|
||||
using Pal.Client.Properties;
|
||||
using Pal.Client.Windows;
|
||||
|
||||
namespace Pal.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Takes care of async plugin init - this is mostly everything that requires either the config or the database to
|
||||
/// be available.
|
||||
/// </summary>
|
||||
internal sealed class DependencyInjectionLoader
|
||||
{
|
||||
private readonly ILogger<DependencyInjectionLoader> _logger;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public DependencyInjectionLoader(ILogger<DependencyInjectionLoader> logger, IServiceProvider serviceProvider)
|
||||
{
|
||||
_logger = logger;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public ELoadState LoadState { get; private set; } = ELoadState.Initializing;
|
||||
|
||||
public event Action<Action?>? InitCompleted;
|
||||
|
||||
public async Task InitializeAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
using IDisposable? logScope = _logger.BeginScope("AsyncInit");
|
||||
|
||||
Chat? chat = null;
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Starting async init");
|
||||
chat = _serviceProvider.GetService<Chat>();
|
||||
|
||||
// initialize database
|
||||
await using (var scope = _serviceProvider.CreateAsyncScope())
|
||||
{
|
||||
_logger.LogInformation("Loading database & running migrations");
|
||||
await using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
|
||||
|
||||
// takes 2-3 seconds with initializing connections, loading driver etc.
|
||||
await dbContext.Database.MigrateAsync(cancellationToken);
|
||||
_logger.LogInformation("Completed database migrations");
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// v1 migration: config migration for import history, json migration for markers
|
||||
_serviceProvider.GetRequiredService<ConfigurationManager>().Migrate();
|
||||
await _serviceProvider.GetRequiredService<JsonMigration>().MigrateAsync(cancellationToken);
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// windows that have logic to open on startup
|
||||
_serviceProvider.GetRequiredService<AgreementWindow>();
|
||||
|
||||
// initialize components that are mostly self-contained/self-registered
|
||||
_serviceProvider.GetRequiredService<Hooks>();
|
||||
_serviceProvider.GetRequiredService<FrameworkService>();
|
||||
_serviceProvider.GetRequiredService<ChatService>();
|
||||
|
||||
// eager load any commands to find errors now, not when running them
|
||||
_serviceProvider.GetRequiredService<PalConfigCommand>();
|
||||
_serviceProvider.GetRequiredService<PalNearCommand>();
|
||||
_serviceProvider.GetRequiredService<PalStatsCommand>();
|
||||
_serviceProvider.GetRequiredService<PalTestConnectionCommand>();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
LoadState = ELoadState.Loaded;
|
||||
InitCompleted?.Invoke(null);
|
||||
_logger.LogInformation("Async init complete");
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
InitCompleted?.Invoke(null);
|
||||
LoadState = ELoadState.Error;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Async load failed");
|
||||
InitCompleted?.Invoke(() => chat?.Error(string.Format(Localization.Error_LoadFailed, $"{e.GetType()} - {e.Message}")));
|
||||
|
||||
LoadState = ELoadState.Error;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ELoadState
|
||||
{
|
||||
Initializing,
|
||||
Loaded,
|
||||
Error
|
||||
}
|
||||
}
|
||||
}
|
@ -5,11 +5,17 @@ using Pal.Client.Windows;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.Command;
|
||||
using Pal.Client.Properties;
|
||||
using ECommons;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Pal.Client.Commands;
|
||||
using Pal.Client.Configuration;
|
||||
using Pal.Client.DependencyInjection;
|
||||
|
||||
namespace Pal.Client
|
||||
{
|
||||
@ -17,51 +23,120 @@ namespace Pal.Client
|
||||
/// With all DI logic elsewhere, this plugin shell really only takes care of a few things around events that
|
||||
/// need to be sent to different receivers depending on priority or configuration .
|
||||
/// </summary>
|
||||
/// <see cref="DependencyInjection.DependencyInjectionContext"/>
|
||||
/// <see cref="DependencyInjectionContext"/>
|
||||
internal sealed class Plugin : IDisposable
|
||||
{
|
||||
private readonly DalamudPluginInterface _pluginInterface;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<Plugin> _logger;
|
||||
private readonly IPalacePalConfiguration _configuration;
|
||||
private readonly RenderAdapter _renderAdapter;
|
||||
private readonly CommandManager _commandManager;
|
||||
private readonly Chat _chat;
|
||||
private readonly WindowSystem _windowSystem;
|
||||
private readonly ClientState _clientState;
|
||||
|
||||
private readonly IServiceScope _rootScope;
|
||||
private readonly DependencyInjectionLoader _loader;
|
||||
|
||||
private Action? _loginAction = null;
|
||||
|
||||
public Plugin(
|
||||
DalamudPluginInterface pluginInterface,
|
||||
IServiceProvider serviceProvider)
|
||||
IServiceProvider serviceProvider,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
_pluginInterface = pluginInterface;
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = _serviceProvider.GetRequiredService<ILogger<Plugin>>();
|
||||
_configuration = serviceProvider.GetRequiredService<IPalacePalConfiguration>();
|
||||
_renderAdapter = serviceProvider.GetRequiredService<RenderAdapter>();
|
||||
_logger = serviceProvider.GetRequiredService<ILogger<Plugin>>();
|
||||
_commandManager = serviceProvider.GetRequiredService<CommandManager>();
|
||||
_chat = serviceProvider.GetRequiredService<Chat>();
|
||||
_windowSystem = serviceProvider.GetRequiredService<WindowSystem>();
|
||||
_clientState = serviceProvider.GetRequiredService<ClientState>();
|
||||
|
||||
LanguageChanged(pluginInterface.UiLanguage);
|
||||
_rootScope = serviceProvider.CreateScope();
|
||||
_loader = _rootScope.ServiceProvider.GetRequiredService<DependencyInjectionLoader>();
|
||||
_loader.InitCompleted += InitCompleted;
|
||||
var _ = Task.Run(async () => await _loader.InitializeAsync(cancellationToken));
|
||||
|
||||
pluginInterface.UiBuilder.Draw += Draw;
|
||||
pluginInterface.UiBuilder.OpenConfigUi += OpenConfigUi;
|
||||
pluginInterface.LanguageChanged += LanguageChanged;
|
||||
_clientState.Login += Login;
|
||||
|
||||
_commandManager.AddHandler("/pal", new CommandInfo(OnCommand)
|
||||
{
|
||||
HelpMessage = Localization.Command_pal_HelpText
|
||||
});
|
||||
}
|
||||
|
||||
private void InitCompleted(Action? loginAction)
|
||||
{
|
||||
LanguageChanged(_pluginInterface.UiLanguage);
|
||||
|
||||
if (_clientState.IsLoggedIn)
|
||||
{
|
||||
loginAction?.Invoke();
|
||||
_loginAction = null;
|
||||
}
|
||||
else
|
||||
_loginAction = loginAction;
|
||||
}
|
||||
|
||||
private void Login(object? sender, EventArgs eventArgs)
|
||||
{
|
||||
_loginAction?.Invoke();
|
||||
_loginAction = null;
|
||||
}
|
||||
|
||||
private void OnCommand(string command, string arguments)
|
||||
{
|
||||
arguments = arguments.Trim();
|
||||
|
||||
IPalacePalConfiguration configuration =
|
||||
_rootScope.ServiceProvider.GetRequiredService<IPalacePalConfiguration>();
|
||||
if (configuration.FirstUse && arguments != "" && arguments != "config")
|
||||
{
|
||||
_chat.Error(Localization.Error_FirstTimeSetupRequired);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var sp = _rootScope.ServiceProvider;
|
||||
|
||||
switch (arguments)
|
||||
{
|
||||
case "":
|
||||
case "config":
|
||||
sp.GetRequiredService<PalConfigCommand>().Execute();
|
||||
break;
|
||||
|
||||
case "stats":
|
||||
sp.GetRequiredService<PalStatsCommand>().Execute();
|
||||
break;
|
||||
|
||||
case "tc":
|
||||
case "test-connection":
|
||||
sp.GetRequiredService<PalTestConnectionCommand>().Execute();
|
||||
break;
|
||||
|
||||
case "near":
|
||||
case "tnear":
|
||||
case "hnear":
|
||||
sp.GetRequiredService<PalNearCommand>().Execute(arguments);
|
||||
break;
|
||||
|
||||
default:
|
||||
_chat.Error(string.Format(Localization.Command_pal_UnknownSubcommand, arguments,
|
||||
command));
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_chat.Error(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenConfigUi()
|
||||
{
|
||||
Window configWindow;
|
||||
if (_configuration.FirstUse)
|
||||
configWindow = _serviceProvider.GetRequiredService<AgreementWindow>();
|
||||
else
|
||||
configWindow = _serviceProvider.GetRequiredService<ConfigWindow>();
|
||||
|
||||
configWindow.IsOpen = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_pluginInterface.UiBuilder.Draw -= Draw;
|
||||
_pluginInterface.UiBuilder.OpenConfigUi -= OpenConfigUi;
|
||||
_pluginInterface.LanguageChanged -= LanguageChanged;
|
||||
}
|
||||
=> _rootScope.ServiceProvider.GetRequiredService<PalConfigCommand>().Execute();
|
||||
|
||||
private void LanguageChanged(string languageCode)
|
||||
{
|
||||
@ -74,8 +149,24 @@ namespace Pal.Client
|
||||
|
||||
private void Draw()
|
||||
{
|
||||
_renderAdapter.DrawLayers();
|
||||
_windowSystem.Draw();
|
||||
if (_loader.LoadState == DependencyInjectionLoader.ELoadState.Loaded)
|
||||
{
|
||||
_rootScope.ServiceProvider.GetRequiredService<RenderAdapter>().DrawLayers();
|
||||
_windowSystem.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_commandManager.RemoveHandler("/pal");
|
||||
|
||||
_pluginInterface.UiBuilder.Draw -= Draw;
|
||||
_pluginInterface.UiBuilder.OpenConfigUi -= OpenConfigUi;
|
||||
_pluginInterface.LanguageChanged -= LanguageChanged;
|
||||
_clientState.Login -= Login;
|
||||
|
||||
_loader.InitCompleted -= InitCompleted;
|
||||
_rootScope.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
18
Pal.Client/Properties/Localization.Designer.cs
generated
18
Pal.Client/Properties/Localization.Designer.cs
generated
@ -149,15 +149,6 @@ namespace Pal.Client.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Updated all locally cached marker files to latest version..
|
||||
/// </summary>
|
||||
internal static string Command_pal_updatesaves {
|
||||
get {
|
||||
return ResourceManager.GetString("Command_pal_updatesaves", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You are NOT in a deep dungeon..
|
||||
/// </summary>
|
||||
@ -664,6 +655,15 @@ namespace Pal.Client.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Plugin could not be loaded: {0}.
|
||||
/// </summary>
|
||||
internal static string Error_LoadFailed {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_LoadFailed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please install this plugin from the official repository at {0} to continue using it..
|
||||
/// </summary>
|
||||
|
@ -61,10 +61,6 @@
|
||||
<value>Impossible de récupérer les statistiques.</value>
|
||||
<comment>Shown when /pal stats produces a server-side error, and the statistics window can't be loaded.</comment>
|
||||
</data>
|
||||
<data name="Command_pal_updatesaves" xml:space="preserve">
|
||||
<value>Mise à jour de tous les marqueurs du cache local vers la dernière version.</value>
|
||||
<comment>Shown after /pal update-saves was successful.</comment>
|
||||
</data>
|
||||
<!-- Messages while connecting to the server. These are typically only visible when clicking 'Test connection'. -->
|
||||
<data name="ConnectionSuccessful" xml:space="preserve">
|
||||
<value>Connexion réussie.</value>
|
||||
|
@ -61,10 +61,6 @@
|
||||
<value>統計情報を取得できません。</value>
|
||||
<comment>Shown when /pal stats produces a server-side error, and the statistics window can't be loaded.</comment>
|
||||
</data>
|
||||
<data name="Command_pal_updatesaves" xml:space="preserve">
|
||||
<value>保存されたマーカーファイルを更新しました。</value>
|
||||
<comment>Shown after /pal update-saves was successful.</comment>
|
||||
</data>
|
||||
<!-- Messages while connecting to the server. These are typically only visible when clicking 'Test connection'. -->
|
||||
<data name="ConnectionSuccessful" xml:space="preserve">
|
||||
<value>接続に成功しました。</value>
|
||||
|
@ -46,6 +46,9 @@
|
||||
<value>Please finish the initial setup first.</value>
|
||||
<comment>Before using any /pal command, the initial setup/agreeement needs to be completed.</comment>
|
||||
</data>
|
||||
<data name="Error_LoadFailed" xml:space="preserve">
|
||||
<value>Plugin could not be loaded: {0}</value>
|
||||
</data>
|
||||
<data name="Error_WrongRepository" xml:space="preserve">
|
||||
<value>Please install this plugin from the official repository at {0} to continue using it.</value>
|
||||
</data>
|
||||
@ -66,11 +69,7 @@
|
||||
<value>Unable to fetch statistics.</value>
|
||||
<comment>Shown when /pal stats produces a server-side error, and the statistics window can't be loaded.</comment>
|
||||
</data>
|
||||
<data name="Command_pal_updatesaves" xml:space="preserve">
|
||||
<value>Updated all locally cached marker files to latest version.</value>
|
||||
<comment>Shown after /pal update-saves was successful.</comment>
|
||||
</data>
|
||||
|
||||
|
||||
<!-- Messages while connecting to the server. These are typically only visible when clicking 'Test connection'. -->
|
||||
<data name="ConnectionSuccessful" xml:space="preserve">
|
||||
<value>Connection successful.</value>
|
||||
@ -322,6 +321,5 @@ This is not synchronized with other players and not saved between floors/runs.</
|
||||
<data name="Error_ImportFailed_InvalidFile" xml:space="preserve">
|
||||
<value>Import failed: Invalid file.</value>
|
||||
</data>
|
||||
|
||||
<!-- Other -->
|
||||
</root>
|
||||
|
Loading…
Reference in New Issue
Block a user