diff --git a/OtterGui b/OtterGui
index d59cf504..73f6b14d 160000
--- a/OtterGui
+++ b/OtterGui
@@ -1 +1 @@
-Subproject commit d59cf50483fc81af5deb871bac76f70d42d7b8c1
+Subproject commit 73f6b14d16920a94b7b98fe85973b9b2b959ada5
diff --git a/Penumbra/Collections/Cache/CollectionCache.cs b/Penumbra/Collections/Cache/CollectionCache.cs
index 298e683c..1196a110 100644
--- a/Penumbra/Collections/Cache/CollectionCache.cs
+++ b/Penumbra/Collections/Cache/CollectionCache.cs
@@ -122,26 +122,40 @@ public class CollectionCache : IDisposable
return ret;
}
+ public void ForceFile(Utf8GamePath path, FullPath fullPath)
+ => _manager.AddChange(ChangeData.ForcedFile(this, path, fullPath));
+
+ public void RemovePath(Utf8GamePath path)
+ => _manager.AddChange(ChangeData.ForcedFile(this, path, FullPath.Empty));
+
+ public void ReloadMod(IMod mod, bool addMetaChanges)
+ => _manager.AddChange(ChangeData.ModReload(this, mod, addMetaChanges));
+
+ public void AddMod(IMod mod, bool addMetaChanges)
+ => _manager.AddChange(ChangeData.ModAddition(this, mod, addMetaChanges));
+
+ public void RemoveMod(IMod mod, bool addMetaChanges)
+ => _manager.AddChange(ChangeData.ModRemoval(this, mod, addMetaChanges));
+
/// Force a file to be resolved to a specific path regardless of conflicts.
- internal void ForceFile(Utf8GamePath path, FullPath fullPath)
+ private void ForceFileSync(Utf8GamePath path, FullPath fullPath)
{
if (!CheckFullPath(path, fullPath))
return;
-
- _manager.ForceFile(this, path, fullPath);
+
+ if (ResolvedFiles.Remove(path, out var modPath))
+ ModData.RemovePath(modPath.Mod, path);
+ if (fullPath.FullName.Length > 0)
+ ResolvedFiles.Add(path, new ModPath(Mod.ForcedFiles, fullPath));
}
- /// Force a file resolve to be removed.
- internal void RemovePath(Utf8GamePath path)
- => _manager.ForceFile(this, path, FullPath.Empty);
-
- public void ReloadMod(IMod mod, bool addMetaChanges)
+ internal void ReloadModSync(IMod mod, bool addMetaChanges)
{
- RemoveMod(mod, addMetaChanges);
- AddMod(mod, addMetaChanges);
+ RemoveModSync(mod, addMetaChanges);
+ AddModSync(mod, addMetaChanges);
}
- public void RemoveMod(IMod mod, bool addMetaChanges)
+ internal void RemoveModSync(IMod mod, bool addMetaChanges)
{
var conflicts = Conflicts(mod);
var (paths, manipulations) = ModData.RemoveMod(mod);
@@ -168,7 +182,7 @@ public class CollectionCache : IDisposable
{
if (conflict.HasPriority)
{
- ReloadMod(conflict.Mod2, false);
+ ReloadModSync(conflict.Mod2, false);
}
else
{
@@ -185,8 +199,8 @@ public class CollectionCache : IDisposable
}
- // Add all files and possibly manipulations of a given mod according to its settings in this collection.
- public void AddMod(IMod mod, bool addMetaChanges)
+ /// Add all files and possibly manipulations of a given mod according to its settings in this collection.
+ internal void AddModSync(IMod mod, bool addMetaChanges)
{
if (mod.Index >= 0)
{
@@ -421,4 +435,55 @@ public class CollectionCache : IDisposable
Penumbra.Log.Error($"The redirected path is too long to add the redirection\n\t{path}\n\t--> {fullPath}");
return false;
}
+
+ public readonly record struct ChangeData
+ {
+ public readonly CollectionCache Cache;
+ public readonly Utf8GamePath Path;
+ public readonly FullPath FullPath;
+ public readonly IMod Mod;
+ public readonly byte Type;
+ public readonly bool AddMetaChanges;
+
+ private ChangeData(CollectionCache cache, Utf8GamePath p, FullPath fp, IMod m, byte t, bool a)
+ {
+ Cache = cache;
+ Path = p;
+ FullPath = fp;
+ Mod = m;
+ Type = t;
+ AddMetaChanges = a;
+ }
+
+ public static ChangeData ModRemoval(CollectionCache cache, IMod mod, bool addMetaChanges)
+ => new(cache, Utf8GamePath.Empty, FullPath.Empty, mod, 0, addMetaChanges);
+
+ public static ChangeData ModAddition(CollectionCache cache, IMod mod, bool addMetaChanges)
+ => new(cache, Utf8GamePath.Empty, FullPath.Empty, mod, 1, addMetaChanges);
+
+ public static ChangeData ModReload(CollectionCache cache, IMod mod, bool addMetaChanges)
+ => new(cache, Utf8GamePath.Empty, FullPath.Empty, mod, 2, addMetaChanges);
+
+ public static ChangeData ForcedFile(CollectionCache cache, Utf8GamePath p, FullPath fp)
+ => new(cache, p, fp, Mods.Mod.ForcedFiles, 3, false);
+
+ public void Apply()
+ {
+ switch (Type)
+ {
+ case 0:
+ Cache.RemoveModSync(Mod, AddMetaChanges);
+ break;
+ case 1:
+ Cache.AddModSync(Mod, AddMetaChanges);
+ break;
+ case 2:
+ Cache.ReloadModSync(Mod, AddMetaChanges);
+ break;
+ case 3:
+ Cache.ForceFileSync(Path, FullPath);
+ break;
+ }
+ }
+ }
}
diff --git a/Penumbra/Collections/Cache/CollectionCacheManager.cs b/Penumbra/Collections/Cache/CollectionCacheManager.cs
index a14c6ac2..0c084c5c 100644
--- a/Penumbra/Collections/Cache/CollectionCacheManager.cs
+++ b/Penumbra/Collections/Cache/CollectionCacheManager.cs
@@ -15,7 +15,6 @@ using Penumbra.Meta;
using Penumbra.Mods;
using Penumbra.Mods.Manager;
using Penumbra.Services;
-using Penumbra.String.Classes;
namespace Penumbra.Collections.Cache;
@@ -30,7 +29,7 @@ public class CollectionCacheManager : IDisposable
internal readonly MetaFileManager MetaFileManager;
- private readonly ConcurrentQueue<(CollectionCache, Utf8GamePath, FullPath)> _forcedFileQueue = new();
+ private readonly ConcurrentQueue _changeQueue = new();
private int _count;
@@ -81,6 +80,14 @@ public class CollectionCacheManager : IDisposable
MetaFileManager.CharacterUtility.LoadingFinished -= IncrementCounters;
}
+ public void AddChange(CollectionCache.ChangeData data)
+ {
+ if (_framework.Framework.IsInFrameworkUpdateThread)
+ data.Apply();
+ else
+ _changeQueue.Enqueue(data);
+ }
+
/// Only creates a new cache, does not update an existing one.
public bool CreateCache(ModCollection collection)
{
@@ -102,9 +109,6 @@ public class CollectionCacheManager : IDisposable
=> _framework.RegisterImportant(nameof(CalculateEffectiveFileList) + collection.Name,
() => CalculateEffectiveFileListInternal(collection));
- public void ForceFile(CollectionCache cache, Utf8GamePath path, FullPath fullPath)
- => _forcedFileQueue.Enqueue((cache, path, fullPath));
-
private void CalculateEffectiveFileListInternal(ModCollection collection)
{
// Skip the empty collection.
@@ -143,10 +147,10 @@ public class CollectionCacheManager : IDisposable
.Concat(_tempMods.Mods.TryGetValue(collection, out var list)
? list
: Array.Empty()))
- cache.AddMod(tempMod, false);
+ cache.AddModSync(tempMod, false);
foreach (var mod in _modStorage)
- cache.AddMod(mod, false);
+ cache.AddModSync(mod, false);
cache.AddMetaFiles();
@@ -351,12 +355,7 @@ public class CollectionCacheManager : IDisposable
///
private void OnFramework(Framework _)
{
- while (_forcedFileQueue.TryDequeue(out var tuple))
- {
- if (tuple.Item1.ResolvedFiles.Remove(tuple.Item2, out var modPath))
- tuple.Item1.ModData.RemovePath(modPath.Mod, tuple.Item2);
- if (tuple.Item3.FullName.Length > 0)
- tuple.Item1.ResolvedFiles.Add(tuple.Item2, new ModPath(Mod.ForcedFiles, tuple.Item3));
- }
+ while (_changeQueue.TryDequeue(out var changeData))
+ changeData.Apply();
}
}
diff --git a/Penumbra/Mods/Editor/ModBackup.cs b/Penumbra/Mods/Editor/ModBackup.cs
index 72680091..cbb98a38 100644
--- a/Penumbra/Mods/Editor/ModBackup.cs
+++ b/Penumbra/Mods/Editor/ModBackup.cs
@@ -3,9 +3,10 @@ using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Threading.Tasks;
+using OtterGui;
using Penumbra.Mods.Manager;
-namespace Penumbra.Mods;
+namespace Penumbra.Mods.Editor;
/// Utility to create and apply a zipped backup of a mod.
public class ModBackup
@@ -80,7 +81,7 @@ public class ModBackup
return;
CreatingBackup = true;
- await Task.Run(Create);
+ await AsyncTask.Run(Create);
CreatingBackup = false;
}
diff --git a/Penumbra/Mods/Editor/ModNormalizer.cs b/Penumbra/Mods/Editor/ModNormalizer.cs
index 8a918ec6..0019b5f6 100644
--- a/Penumbra/Mods/Editor/ModNormalizer.cs
+++ b/Penumbra/Mods/Editor/ModNormalizer.cs
@@ -41,7 +41,7 @@ public class ModNormalizer
Step = 0;
TotalSteps = mod.TotalFileCount + 5;
- Worker = Task.Run(NormalizeSync);
+ Worker = TrackedTask.Run(NormalizeSync);
}
private void NormalizeSync()
diff --git a/Penumbra/Mods/Manager/ModExportManager.cs b/Penumbra/Mods/Manager/ModExportManager.cs
index 6bb919fc..f2bfb9bc 100644
--- a/Penumbra/Mods/Manager/ModExportManager.cs
+++ b/Penumbra/Mods/Manager/ModExportManager.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using Penumbra.Communication;
+using Penumbra.Mods.Editor;
using Penumbra.Services;
namespace Penumbra.Mods.Manager;
diff --git a/Penumbra/Mods/Manager/ModManager.cs b/Penumbra/Mods/Manager/ModManager.cs
index 7e7599f0..6c1ff9ab 100644
--- a/Penumbra/Mods/Manager/ModManager.cs
+++ b/Penumbra/Mods/Manager/ModManager.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Penumbra.Communication;
+using Penumbra.Mods.Editor;
using Penumbra.Services;
namespace Penumbra.Mods.Manager;
diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs
index 4876d530..bd530ccd 100644
--- a/Penumbra/Penumbra.cs
+++ b/Penumbra/Penumbra.cs
@@ -52,10 +52,14 @@ public class Penumbra : IDalamudPlugin
try
{
var startTimer = new StartTracker();
- using var timer = startTimer.Measure(StartTimeType.Total);
+ using var timer = startTimer.Measure(StartTimeType.Total);
_services = ServiceManager.CreateProvider(this, pluginInterface, Log, startTimer);
ChatService = _services.GetRequiredService();
_validityChecker = _services.GetRequiredService();
+ var startup = _services.GetRequiredService().GetDalamudConfig(DalamudServices.WaitingForPluginsOption, out bool s)
+ ? s.ToString()
+ : "Unknown";
+ Log.Information($"Loading Penumbra Version {_validityChecker.Version}, Commit #{_validityChecker.CommitHash} with Waiting For Plugins: {startup}...");
_services.GetRequiredService(); // Initialize because not required anywhere else.
_config = _services.GetRequiredService();
_characterUtility = _services.GetRequiredService();
@@ -114,7 +118,7 @@ public class Penumbra : IDalamudPlugin
private void SetupInterface()
{
- Task.Run(() =>
+ AsyncTask.Run(() =>
{
using var tInterface = _services.GetRequiredService().Measure(StartTimeType.Interface);
var system = _services.GetRequiredService();
diff --git a/Penumbra/Services/ConfigMigrationService.cs b/Penumbra/Services/ConfigMigrationService.cs
index 8c0a60f1..5d19dbe5 100644
--- a/Penumbra/Services/ConfigMigrationService.cs
+++ b/Penumbra/Services/ConfigMigrationService.cs
@@ -9,6 +9,7 @@ using Penumbra.Collections;
using Penumbra.Collections.Manager;
using Penumbra.Interop.Services;
using Penumbra.Mods;
+using Penumbra.Mods.Editor;
using Penumbra.Mods.Manager;
using Penumbra.UI.Classes;
using Penumbra.Util;
diff --git a/Penumbra/Services/ServiceWrapper.cs b/Penumbra/Services/ServiceWrapper.cs
index cb4c86e8..5a43cf9a 100644
--- a/Penumbra/Services/ServiceWrapper.cs
+++ b/Penumbra/Services/ServiceWrapper.cs
@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
+using OtterGui;
using Penumbra.Util;
namespace Penumbra.Services;
@@ -58,7 +59,7 @@ public abstract class AsyncServiceWrapper
protected AsyncServiceWrapper(string name, StartTracker tracker, StartTimeType type, Func factory)
{
Name = name;
- _task = Task.Run(() =>
+ _task = TrackedTask.Run(() =>
{
using var timer = tracker.Measure(type);
var service = factory();
@@ -84,7 +85,7 @@ public abstract class AsyncServiceWrapper
protected AsyncServiceWrapper(string name, Func factory)
{
Name = name;
- _task = Task.Run(() =>
+ _task = TrackedTask.Run(() =>
{
var service = factory();
if (_isDisposed)
diff --git a/Penumbra/UI/ModsTab/ModPanelEditTab.cs b/Penumbra/UI/ModsTab/ModPanelEditTab.cs
index 294f8041..f5b03659 100644
--- a/Penumbra/UI/ModsTab/ModPanelEditTab.cs
+++ b/Penumbra/UI/ModsTab/ModPanelEditTab.cs
@@ -12,6 +12,7 @@ using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.Api.Enums;
using Penumbra.Mods;
+using Penumbra.Mods.Editor;
using Penumbra.Mods.Manager;
using Penumbra.Services;
using Penumbra.UI.AdvancedWindow;