diff --git a/OtterGui b/OtterGui
index becacbca..5de708b2 160000
--- a/OtterGui
+++ b/OtterGui
@@ -1 +1 @@
-Subproject commit becacbca4f35595d16ff40dc9639cfa24be3461f
+Subproject commit 5de708b27ed45c9cdead71742c7061ad9ce64323
diff --git a/Penumbra.CrashHandler/CrashData.cs b/Penumbra.CrashHandler/CrashData.cs
index cdac103f..dd75f46e 100644
--- a/Penumbra.CrashHandler/CrashData.cs
+++ b/Penumbra.CrashHandler/CrashData.cs
@@ -55,7 +55,7 @@ public class CrashData
/// The last vfx function invoked before this crash data was generated.
public VfxFuncInvokedEntry? LastVfxFuncInvoked
- => LastVfxFuncsInvoked.Count == 0 ? default : LastVfxFuncsInvoked[0];
+ => LastVFXFuncsInvoked.Count == 0 ? default : LastVFXFuncsInvoked[0];
/// A collection of the last few characters loaded before this crash data was generated.
public List LastCharactersLoaded { get; set; } = [];
@@ -64,5 +64,5 @@ public class CrashData
public List LastModdedFilesLoaded { get; set; } = [];
/// A collection of the last few vfx functions invoked before this crash data was generated.
- public List LastVfxFuncsInvoked { get; set; } = [];
+ public List LastVFXFuncsInvoked { get; set; } = [];
}
diff --git a/Penumbra/Collections/Manager/CollectionStorage.cs b/Penumbra/Collections/Manager/CollectionStorage.cs
index f6287320..67de3a03 100644
--- a/Penumbra/Collections/Manager/CollectionStorage.cs
+++ b/Penumbra/Collections/Manager/CollectionStorage.cs
@@ -181,6 +181,7 @@ public class CollectionStorage : IReadOnlyList, IDisposable
return false;
}
+ Delete(collection);
_saveService.ImmediateDelete(new ModCollectionSave(_modStorage, collection));
_collections.RemoveAt(collection.Index);
// Update indices.
diff --git a/Penumbra/Communication/ModSettingChanged.cs b/Penumbra/Communication/ModSettingChanged.cs
index a7da345b..7fda2f35 100644
--- a/Penumbra/Communication/ModSettingChanged.cs
+++ b/Penumbra/Communication/ModSettingChanged.cs
@@ -24,7 +24,7 @@ public sealed class ModSettingChanged()
{
public enum Priority
{
- ///
+ ///
Api = int.MinValue,
///
diff --git a/Penumbra/Services/CrashHandlerService.cs b/Penumbra/Services/CrashHandlerService.cs
index 1239578b..25c6cf57 100644
--- a/Penumbra/Services/CrashHandlerService.cs
+++ b/Penumbra/Services/CrashHandlerService.cs
@@ -287,7 +287,7 @@ public sealed class CrashHandlerService : IDisposable, IService
try
{
- if (PathDataHandler.Split(manipulatedPath.Value.FullName, out var actualPath, out _) && Path.IsPathRooted(actualPath))
+ if (PathDataHandler.Split(manipulatedPath.Value.FullName, out var actualPath, out _) && !Path.IsPathRooted(actualPath))
return;
var name = GetActorName(resolveData.AssociatedGameObject);
diff --git a/Penumbra/UI/CollectionTab/CollectionPanel.cs b/Penumbra/UI/CollectionTab/CollectionPanel.cs
index cb4dbe20..082b78b8 100644
--- a/Penumbra/UI/CollectionTab/CollectionPanel.cs
+++ b/Penumbra/UI/CollectionTab/CollectionPanel.cs
@@ -20,19 +20,23 @@ using Penumbra.UI.Classes;
namespace Penumbra.UI.CollectionTab;
-public sealed class CollectionPanel : IDisposable
+public sealed class CollectionPanel(
+ DalamudPluginInterface pi,
+ CommunicatorService communicator,
+ CollectionManager manager,
+ CollectionSelector selector,
+ ActorManager actors,
+ ITargetManager targets,
+ ModStorage mods,
+ SaveService saveService,
+ IncognitoService incognito)
+ : IDisposable
{
- private readonly CollectionStorage _collections;
- private readonly ActiveCollections _active;
- private readonly CollectionSelector _selector;
- private readonly ActorManager _actors;
- private readonly ITargetManager _targets;
- private readonly IndividualAssignmentUi _individualAssignmentUi;
- private readonly InheritanceUi _inheritanceUi;
- private readonly ModStorage _mods;
- private readonly FilenameService _fileNames;
- private readonly IncognitoService _incognito;
- private readonly IFontHandle _nameFont;
+ private readonly CollectionStorage _collections = manager.Storage;
+ private readonly ActiveCollections _active = manager.Active;
+ private readonly IndividualAssignmentUi _individualAssignmentUi = new(communicator, actors, manager);
+ private readonly InheritanceUi _inheritanceUi = new(manager, incognito);
+ private readonly IFontHandle _nameFont = pi.UiBuilder.FontAtlas.NewGameFontHandle(new GameFontStyle(GameFontFamilyAndSize.Jupiter23));
private static readonly IReadOnlyDictionary Buttons = CreateButtons();
private static readonly IReadOnlyList<(CollectionType, bool, bool, string, uint)> AdvancedTree = CreateTree();
@@ -41,23 +45,6 @@ public sealed class CollectionPanel : IDisposable
private int _draggedIndividualAssignment = -1;
- public CollectionPanel(DalamudPluginInterface pi, CommunicatorService communicator, CollectionManager manager,
- CollectionSelector selector, ActorManager actors, ITargetManager targets, ModStorage mods, FilenameService fileNames,
- IncognitoService incognito)
- {
- _collections = manager.Storage;
- _active = manager.Active;
- _selector = selector;
- _actors = actors;
- _targets = targets;
- _mods = mods;
- _fileNames = fileNames;
- _incognito = incognito;
- _individualAssignmentUi = new IndividualAssignmentUi(communicator, actors, manager);
- _inheritanceUi = new InheritanceUi(manager, incognito);
- _nameFont = pi.UiBuilder.FontAtlas.NewGameFontHandle(new GameFontStyle(GameFontFamilyAndSize.Jupiter23));
- }
-
public void Dispose()
{
_individualAssignmentUi.Dispose();
@@ -237,17 +224,22 @@ public sealed class CollectionPanel : IDisposable
var name = _newName ?? collection.Name;
var identifier = collection.Identifier;
var width = ImGui.GetContentRegionAvail().X;
- var fileName = _fileNames.CollectionFile(collection);
+ var fileName = saveService.FileNames.CollectionFile(collection);
ImGui.SetNextItemWidth(width);
if (ImGui.InputText("##name", ref name, 128))
_newName = name;
- if (ImGui.IsItemDeactivatedAfterEdit() && _newName != null)
+ if (ImGui.IsItemDeactivatedAfterEdit() && _newName != null && _newName != collection.Name)
{
collection.Name = _newName;
- _newName = null;
+ saveService.QueueSave(new ModCollectionSave(mods, collection));
+ selector.RestoreCollections();
+ _newName = null;
}
else if (ImGui.IsItemDeactivated())
+ {
_newName = null;
+ }
+
using (ImRaii.PushFont(UiBuilder.MonoFont))
{
if (ImGui.Button(collection.Identifier, new Vector2(width, 0)))
@@ -329,7 +321,7 @@ public sealed class CollectionPanel : IDisposable
DrawIndividualDragTarget(text, id);
if (!invalid)
{
- _selector.DragTargetAssignment(type, id);
+ selector.DragTargetAssignment(type, id);
var name = Name(collection);
var size = ImGui.CalcTextSize(name);
var textPos = ImGui.GetItemRectMax() - size - ImGui.GetStyle().FramePadding;
@@ -418,7 +410,7 @@ public sealed class CollectionPanel : IDisposable
/// Respect incognito mode for names of identifiers.
private string Name(ActorIdentifier id, string? name)
- => _incognito.IncognitoMode && id.Type is IdentifierType.Player or IdentifierType.Owned
+ => incognito.IncognitoMode && id.Type is IdentifierType.Player or IdentifierType.Owned
? id.Incognito(name)
: name ?? id.ToString();
@@ -426,7 +418,7 @@ public sealed class CollectionPanel : IDisposable
private string Name(ModCollection? collection)
=> collection == null ? "Unassigned" :
collection == ModCollection.Empty ? "Use No Mods" :
- _incognito.IncognitoMode ? collection.AnonymizedName : collection.Name;
+ incognito.IncognitoMode ? collection.AnonymizedName : collection.Name;
private void DrawIndividualButton(string intro, Vector2 width, string tooltip, char suffix, params ActorIdentifier[] identifiers)
{
@@ -445,11 +437,11 @@ public sealed class CollectionPanel : IDisposable
}
private void DrawCurrentCharacter(Vector2 width)
- => DrawIndividualButton("Current Character", width, string.Empty, 'c', _actors.GetCurrentPlayer());
+ => DrawIndividualButton("Current Character", width, string.Empty, 'c', actors.GetCurrentPlayer());
private void DrawCurrentTarget(Vector2 width)
=> DrawIndividualButton("Current Target", width, string.Empty, 't',
- _actors.FromObject(_targets.Target, false, true, true));
+ actors.FromObject(targets.Target, false, true, true));
private void DrawNewPlayer(Vector2 width)
=> DrawIndividualButton("New Player", width, _individualAssignmentUi.PlayerTooltip, 'p',
@@ -610,7 +602,7 @@ public sealed class CollectionPanel : IDisposable
ImGui.TableSetupColumn("State", ImGuiTableColumnFlags.WidthFixed, 1.75f * ImGui.GetFrameHeight());
ImGui.TableSetupColumn("Priority", ImGuiTableColumnFlags.WidthFixed, 2.5f * ImGui.GetFrameHeight());
ImGui.TableHeadersRow();
- foreach (var (mod, (settings, parent)) in _mods.Select(m => (m, collection[m.Index]))
+ foreach (var (mod, (settings, parent)) in mods.Select(m => (m, collection[m.Index]))
.Where(t => t.Item2.Settings != null)
.OrderBy(t => t.m.Name))
{
diff --git a/Penumbra/UI/CollectionTab/CollectionSelector.cs b/Penumbra/UI/CollectionTab/CollectionSelector.cs
index c14baf5b..024873bf 100644
--- a/Penumbra/UI/CollectionTab/CollectionSelector.cs
+++ b/Penumbra/UI/CollectionTab/CollectionSelector.cs
@@ -44,7 +44,9 @@ public sealed class CollectionSelector : ItemSelector, IDisposabl
if (idx < 0 || idx >= Items.Count)
return false;
- return _storage.RemoveCollection(Items[idx]);
+ // Always return false since we handle the selection update ourselves.
+ _storage.RemoveCollection(Items[idx]);
+ return false;
}
protected override bool DeleteButtonEnabled()
@@ -111,6 +113,15 @@ public sealed class CollectionSelector : ItemSelector, IDisposabl
private string Name(ModCollection collection)
=> _incognito.IncognitoMode || collection.Name.Length == 0 ? collection.AnonymizedName : collection.Name;
+ public void RestoreCollections()
+ {
+ Items.Clear();
+ foreach (var c in _storage.OrderBy(c => c.Name))
+ Items.Add(c);
+ SetFilterDirty();
+ SetCurrent(_active.Current);
+ }
+
private void OnCollectionChange(CollectionType type, ModCollection? old, ModCollection? @new, string _3)
{
switch (type)
@@ -122,14 +133,7 @@ public sealed class CollectionSelector : ItemSelector, IDisposabl
SetFilterDirty();
return;
case CollectionType.Inactive:
- Items.Clear();
- foreach (var c in _storage.OrderBy(c => c.Name))
- Items.Add(c);
-
- if (old == Current)
- ClearCurrentSelection();
- else
- TryRestoreCurrent();
+ RestoreCollections();
SetFilterDirty();
return;
default:
diff --git a/Penumbra/UI/Tabs/CollectionsTab.cs b/Penumbra/UI/Tabs/CollectionsTab.cs
index 1eaece50..fabf7561 100644
--- a/Penumbra/UI/Tabs/CollectionsTab.cs
+++ b/Penumbra/UI/Tabs/CollectionsTab.cs
@@ -1,16 +1,12 @@
using Dalamud.Game.ClientState.Objects;
-using Dalamud.Interface;
-using Dalamud.Interface.Utility;
using Dalamud.Plugin;
using ImGuiNET;
-using OtterGui;
using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.Collections.Manager;
using Penumbra.GameData.Actors;
using Penumbra.Mods.Manager;
using Penumbra.Services;
-using Penumbra.UI.Classes;
using Penumbra.UI.CollectionTab;
namespace Penumbra.UI.Tabs;
@@ -42,13 +38,13 @@ public sealed class CollectionsTab : IDisposable, ITab
}
public CollectionsTab(DalamudPluginInterface pi, Configuration configuration, CommunicatorService communicator, IncognitoService incognito,
- CollectionManager collectionManager, ModStorage modStorage, ActorManager actors, ITargetManager targets, TutorialService tutorial, FilenameService fileNames)
+ CollectionManager collectionManager, ModStorage modStorage, ActorManager actors, ITargetManager targets, TutorialService tutorial, SaveService saveService)
{
_config = configuration.Ephemeral;
_tutorial = tutorial;
_incognito = incognito;
_selector = new CollectionSelector(configuration, communicator, collectionManager.Storage, collectionManager.Active, _tutorial, incognito);
- _panel = new CollectionPanel(pi, communicator, collectionManager, _selector, actors, targets, modStorage, fileNames, incognito);
+ _panel = new CollectionPanel(pi, communicator, collectionManager, _selector, actors, targets, modStorage, saveService, incognito);
}
public void Dispose()
diff --git a/Penumbra/UI/Tabs/Debug/CrashDataExtensions.cs b/Penumbra/UI/Tabs/Debug/CrashDataExtensions.cs
index 4649e548..94c6cbd6 100644
--- a/Penumbra/UI/Tabs/Debug/CrashDataExtensions.cs
+++ b/Penumbra/UI/Tabs/Debug/CrashDataExtensions.cs
@@ -96,7 +96,7 @@ public static class CrashDataExtensions
if (!table)
return;
- ImGuiClip.ClippedDraw(data.LastVfxFuncsInvoked, vfx =>
+ ImGuiClip.ClippedDraw(data.LastVFXFuncsInvoked, vfx =>
{
ImGuiUtil.DrawTableColumn(vfx.Age.ToString(CultureInfo.InvariantCulture));
ImGuiUtil.DrawTableColumn(vfx.ThreadId.ToString());