diff --git a/Dalamud/Game/SigScanner.cs b/Dalamud/Game/SigScanner.cs
index ffc7188f4..9f5a8e33c 100644
--- a/Dalamud/Game/SigScanner.cs
+++ b/Dalamud/Game/SigScanner.cs
@@ -376,6 +376,7 @@ namespace Dalamud.Game
try
{
File.WriteAllText(this.cacheFile.FullName, JsonConvert.SerializeObject(this.textCache));
+ Log.Information("Saved cache to {CachePath}", this.cacheFile);
}
catch (Exception e)
{
diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs
index 52059da7e..3d66c89ff 100644
--- a/Dalamud/Plugin/Internal/PluginManager.cs
+++ b/Dalamud/Plugin/Internal/PluginManager.cs
@@ -334,7 +334,8 @@ internal partial class PluginManager : IDisposable, IServiceType
///
/// This should only be called during Dalamud startup.
///
- public void LoadAllPlugins()
+ /// The task.
+ public async Task LoadAllPlugins()
{
var pluginDefs = new List();
var devPluginDefs = new List();
@@ -405,8 +406,9 @@ internal partial class PluginManager : IDisposable, IServiceType
// Dev plugins should load first.
pluginDefs.InsertRange(0, devPluginDefs);
- async Task LoadPluginOnBoot(string logPrefix, PluginDef pluginDef)
+ async Task LoadPluginOnBoot(string logPrefix, PluginDef pluginDef, CancellationToken token)
{
+ token.ThrowIfCancellationRequested();
using (Timings.Start($"{pluginDef.DllFile.Name}: {logPrefix}Boot"))
{
try
@@ -429,24 +431,30 @@ internal partial class PluginManager : IDisposable, IServiceType
}
}
- async Task LoadPluginsSync(string logPrefix, IEnumerable pluginDefsList)
+ async Task LoadPluginsSync(string logPrefix, IEnumerable pluginDefsList, CancellationToken token)
{
- Log.Information("============= LoadPluginsSync START =============");
+ Log.Information($"============= LoadPluginsSync({logPrefix}) START =============");
foreach (var pluginDef in pluginDefsList)
- await LoadPluginOnBoot(logPrefix, pluginDef);
+ await LoadPluginOnBoot(logPrefix, pluginDef, token).ConfigureAwait(false);
- Log.Information("============= LoadPluginsSync END =============");
+ Log.Information($"============= LoadPluginsSync({logPrefix}) END =============");
}
- Task LoadPluginsAsync(string logPrefix, IEnumerable pluginDefsList)
+ async Task LoadPluginsAsync(string logPrefix, IEnumerable pluginDefsList, CancellationToken token)
{
- Log.Information("============= LoadPluginsAsync START =============");
- return Task.WhenAll(
+ Log.Information($"============= LoadPluginsAsync({logPrefix}) START =============");
+
+ await Task.WhenAll(
pluginDefsList
- .Select(pluginDef => Task.Run(Timings.AttachTimingHandle(
- () => LoadPluginOnBoot(logPrefix, pluginDef))))
- .ToArray()).ContinueWith(t => Log.Information($"============= LoadPluginsAsync END {t.IsCompletedSuccessfully} ============="));
+ .Select(pluginDef =>
+ Task.Run(
+ Timings.AttachTimingHandle(
+ () => LoadPluginOnBoot(logPrefix, pluginDef, token)),
+ token))
+ .ToArray()).ConfigureAwait(false);
+
+ Log.Information($"============= LoadPluginsAsync({logPrefix}) END =============");
}
var syncPlugins = pluginDefs.Where(def => def.Manifest?.LoadSync == true).ToList();
@@ -456,107 +464,62 @@ internal partial class PluginManager : IDisposable, IServiceType
var tokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(5));
// Load plugins that can be loaded anytime
- LoadPluginsSync(
+ await LoadPluginsSync(
"AnytimeSync",
- syncPlugins.Where(def => def.Manifest?.LoadRequiredState == 2)).GetAwaiter().GetResult();
- loadTasks.Add(
- Task.Run(
- () => LoadPluginsAsync(
- "AnytimeAsync",
- asyncPlugins.Where(def => def.Manifest?.LoadRequiredState == 2)),
- tokenSource.Token));
+ syncPlugins.Where(def => def.Manifest?.LoadRequiredState == 2),
+ tokenSource.Token);
+ loadTasks.Add(LoadPluginsAsync(
+ "AnytimeAsync",
+ asyncPlugins.Where(def => def.Manifest?.LoadRequiredState == 2),
+ tokenSource.Token));
- // Load plugins that want to be loaded during Framework.Tick
- loadTasks.Add(
- Task.Run(
- () => Service
- .GetAsync()
- .ContinueWith(
- x => x.Result.RunOnTick(
- () => LoadPluginsSync(
- "FrameworkTickSync",
- syncPlugins.Where(def => def.Manifest?.LoadRequiredState == 1)),
- cancellationToken: tokenSource.Token),
- tokenSource.Token,
- TaskContinuationOptions.RunContinuationsAsynchronously,
- TaskScheduler.Default)
- .Unwrap()
- .ContinueWith(
- _ => LoadPluginsAsync(
- "FrameworkTickAsync",
- asyncPlugins.Where(def => def.Manifest?.LoadRequiredState == 1)),
- tokenSource.Token,
- TaskContinuationOptions.RunContinuationsAsynchronously,
- TaskScheduler.Default)
- .Unwrap(),
- tokenSource.Token));
+ // Pass the rest of plugin loading to another thread(task)
+ _ = Task.Run(
+ async () =>
+ {
+ // Load plugins that want to be loaded during Framework.Tick
+ var framework = await Service.GetAsync().ConfigureAwait(false);
+ await framework.RunOnTick(
+ () => LoadPluginsSync(
+ "FrameworkTickSync",
+ syncPlugins.Where(def => def.Manifest?.LoadRequiredState == 1),
+ tokenSource.Token),
+ cancellationToken: tokenSource.Token).ConfigureAwait(false);
+ loadTasks.Add(LoadPluginsAsync(
+ "FrameworkTickAsync",
+ asyncPlugins.Where(def => def.Manifest?.LoadRequiredState == 1),
+ tokenSource.Token));
- // Load plugins that want to be loaded during Framework.Tick, when drawing facilities are available
- loadTasks.Add(
- Task.Run(
- () => Service
- .GetAsync()
- .ContinueWith(
- _ => Service.Get().RunOnTick(
- () => LoadPluginsSync(
- "DrawAvailableSync",
- syncPlugins.Where(def => def.Manifest?.LoadRequiredState is 0 or null)),
- cancellationToken: tokenSource.Token),
- tokenSource.Token)
- .Unwrap()
- .ContinueWith(
- _ => LoadPluginsAsync(
+ // Load plugins that want to be loaded during Framework.Tick, when drawing facilities are available
+ _ = await Service.GetAsync().ConfigureAwait(false);
+ await framework.RunOnTick(
+ () => LoadPluginsSync(
+ "DrawAvailableSync",
+ syncPlugins.Where(def => def.Manifest?.LoadRequiredState is 0 or null),
+ tokenSource.Token),
+ cancellationToken: tokenSource.Token);
+ loadTasks.Add(LoadPluginsAsync(
"DrawAvailableAsync",
- asyncPlugins.Where(def => def.Manifest?.LoadRequiredState is 0 or null)),
- tokenSource.Token)
- .Unwrap(),
- tokenSource.Token));
+ asyncPlugins.Where(def => def.Manifest?.LoadRequiredState is 0 or null),
+ tokenSource.Token));
- // Save signatures when all plugins are done loading, successful or not.
- _ = Task
- .WhenAll(loadTasks)
- .ContinueWith(
- t =>
+ // Save signatures when all plugins are done loading, successful or not.
+ try
{
- Log.Information("Task.WhenAll continuing");
- if (!t.IsCompletedSuccessfully)
- {
- foreach (var loadTask in loadTasks)
- {
- if (!loadTask.IsCompletedSuccessfully)
- {
- if (loadTask.Exception != null)
- {
- Log.Error(loadTask.Exception, " => Exception during load");
- }
- else
- {
- Log.Error($" => Task failed, canceled: {t.IsCanceled} faulted: {t.IsFaulted}");
- }
- }
- }
- }
-
- return Service.GetAsync();
- },
- tokenSource.Token,
- TaskContinuationOptions.RunContinuationsAsynchronously,
- TaskScheduler.Default)
- .Unwrap()
- .ContinueWith(
- sigScannerTask =>
+ await Task.WhenAll(loadTasks).ConfigureAwait(false);
+ Log.Information("Loaded plugins on boot");
+ }
+ catch (Exception e)
{
- Log.Information("sigScannerTask continuing");
+ Log.Error(e, "Failed to load at least one plugin");
+ }
- this.PluginsReady = true;
- this.NotifyInstalledPluginsChanged();
-
- sigScannerTask.Result.Save();
- },
- tokenSource.Token,
- TaskContinuationOptions.RunContinuationsAsynchronously,
- TaskScheduler.Default)
- .ConfigureAwait(false);
+ var sigScanner = await Service.GetAsync().ConfigureAwait(false);
+ this.PluginsReady = true;
+ this.NotifyInstalledPluginsChanged();
+ sigScanner.Save();
+ },
+ tokenSource.Token);
}
///
diff --git a/Dalamud/Plugin/Internal/StartupPluginLoader.cs b/Dalamud/Plugin/Internal/StartupPluginLoader.cs
index a95e25ace..3c1b80363 100644
--- a/Dalamud/Plugin/Internal/StartupPluginLoader.cs
+++ b/Dalamud/Plugin/Internal/StartupPluginLoader.cs
@@ -35,7 +35,7 @@ public class StartupPluginLoader : IServiceType
using (Timings.Start("PM Load Sync Plugins"))
{
- pluginManager.LoadAllPlugins();
+ pluginManager.LoadAllPlugins().Wait();
Log.Information("[T3] PML OK!");
}