diff --git a/Penumbra/Communication/PreSettingsTabBarDraw.cs b/Penumbra/Communication/PreSettingsTabBarDraw.cs
index 8614bbbe..e1d67297 100644
--- a/Penumbra/Communication/PreSettingsTabBarDraw.cs
+++ b/Penumbra/Communication/PreSettingsTabBarDraw.cs
@@ -1,5 +1,6 @@
using OtterGui.Classes;
using Penumbra.Api.Api;
+using Penumbra.Api.IpcSubscribers;
namespace Penumbra.Communication;
@@ -15,7 +16,7 @@ public sealed class PreSettingsTabBarDraw() : EventWrapper
+ ///
Default = 0,
}
}
diff --git a/Penumbra/Mods/Groups/IModGroup.cs b/Penumbra/Mods/Groups/IModGroup.cs
index 0cabc9f3..b13799cd 100644
--- a/Penumbra/Mods/Groups/IModGroup.cs
+++ b/Penumbra/Mods/Groups/IModGroup.cs
@@ -16,22 +16,22 @@ public interface IModGroup
{
public const int MaxMultiOptions = 63;
- public Mod Mod { get; }
- public string Name { get; }
- public string Description { get; }
- public GroupType Type { get; }
- public ModPriority Priority { get; set; }
- public Setting DefaultSettings { get; set; }
+ public Mod Mod { get; }
+ public string Name { get; }
+ public string Description { get; set; }
+ public GroupType Type { get; }
+ public ModPriority Priority { get; set; }
+ public Setting DefaultSettings { get; set; }
public FullPath? FindBestMatch(Utf8GamePath gamePath);
- public int AddOption(Mod mod, string name, string description = "");
+ public int AddOption(Mod mod, string name, string description = "");
- public IReadOnlyList Options { get; }
+ public IReadOnlyList Options { get; }
public IReadOnlyList DataContainers { get; }
- public bool IsOption { get; }
+ public bool IsOption { get; }
public IModGroup Convert(GroupType type);
- public bool MoveOption(int optionIdxFrom, int optionIdxTo);
+ public bool MoveOption(int optionIdxFrom, int optionIdxTo);
public int GetIndex();
@@ -42,46 +42,5 @@ public interface IModGroup
public void WriteJson(JsonTextWriter jWriter, JsonSerializer serializer, DirectoryInfo? basePath = null);
- public bool ChangeOptionDescription(int optionIndex, string newDescription)
- {
- if (optionIndex < 0 || optionIndex >= Options.Count)
- return false;
-
- var option = Options[optionIndex];
- if (option.Description == newDescription)
- return false;
-
- option.Description = newDescription;
- return true;
- }
-
- public bool ChangeOptionName(int optionIndex, string newName)
- {
- if (optionIndex < 0 || optionIndex >= Options.Count)
- return false;
-
- var option = Options[optionIndex];
- if (option.Name == newName)
- return false;
-
- option.Name = newName;
- return true;
- }
-
public (int Redirections, int Swaps, int Manips) GetCounts();
-
- public static (int Redirections, int Swaps, int Manips) GetCountsBase(IModGroup group)
- {
- var redirectionCount = 0;
- var swapCount = 0;
- var manipCount = 0;
- foreach (var option in group.DataContainers)
- {
- redirectionCount += option.Files.Count;
- swapCount += option.FileSwaps.Count;
- manipCount += option.Manipulations.Count;
- }
-
- return (redirectionCount, swapCount, manipCount);
- }
}
diff --git a/Penumbra/Mods/Groups/ModGroup.cs b/Penumbra/Mods/Groups/ModGroup.cs
new file mode 100644
index 00000000..da302714
--- /dev/null
+++ b/Penumbra/Mods/Groups/ModGroup.cs
@@ -0,0 +1,42 @@
+using Penumbra.Api.Enums;
+using Penumbra.Mods.Settings;
+
+namespace Penumbra.Mods.Groups;
+
+public static class ModGroup
+{
+ public static IModGroup Create(Mod mod, GroupType type, string name)
+ {
+ var maxPriority = mod.Groups.Count == 0 ? ModPriority.Default : mod.Groups.Max(o => o.Priority) + 1;
+ return type switch
+ {
+ GroupType.Single => new SingleModGroup(mod)
+ {
+ Name = name,
+ Priority = maxPriority,
+ },
+ GroupType.Multi => new MultiModGroup(mod)
+ {
+ Name = name,
+ Priority = maxPriority,
+ },
+ _ => throw new ArgumentOutOfRangeException(nameof(type), type, null),
+ };
+ }
+
+
+ public static (int Redirections, int Swaps, int Manips) GetCountsBase(IModGroup group)
+ {
+ var redirectionCount = 0;
+ var swapCount = 0;
+ var manipCount = 0;
+ foreach (var option in group.DataContainers)
+ {
+ redirectionCount += option.Files.Count;
+ swapCount += option.FileSwaps.Count;
+ manipCount += option.Manipulations.Count;
+ }
+
+ return (redirectionCount, swapCount, manipCount);
+ }
+}
diff --git a/Penumbra/Mods/Groups/ModSaveGroup.cs b/Penumbra/Mods/Groups/ModSaveGroup.cs
index 92ccb36e..332879cb 100644
--- a/Penumbra/Mods/Groups/ModSaveGroup.cs
+++ b/Penumbra/Mods/Groups/ModSaveGroup.cs
@@ -51,7 +51,7 @@ public readonly struct ModSaveGroup : ISavable
if (_groupIdx >= 0)
_group!.WriteJson(j, serializer);
else
- SubModHelpers.WriteModContainer(j, serializer, _defaultMod!, _basePath);
+ SubMod.WriteModContainer(j, serializer, _defaultMod!, _basePath);
j.WriteEndObject();
}
diff --git a/Penumbra/Mods/Groups/MultiModGroup.cs b/Penumbra/Mods/Groups/MultiModGroup.cs
index 7e900ef5..6b352f66 100644
--- a/Penumbra/Mods/Groups/MultiModGroup.cs
+++ b/Penumbra/Mods/Groups/MultiModGroup.cs
@@ -141,10 +141,10 @@ public sealed class MultiModGroup(Mod mod) : IModGroup, ITexToolsGroup
foreach (var option in OptionData)
{
jWriter.WriteStartObject();
- SubModHelpers.WriteModOption(jWriter, option);
+ SubMod.WriteModOption(jWriter, option);
jWriter.WritePropertyName(nameof(option.Priority));
jWriter.WriteValue(option.Priority.Value);
- SubModHelpers.WriteModContainer(jWriter, serializer, option, basePath ?? Mod.ModPath);
+ SubMod.WriteModContainer(jWriter, serializer, option, basePath ?? Mod.ModPath);
jWriter.WriteEndObject();
}
@@ -153,7 +153,7 @@ public sealed class MultiModGroup(Mod mod) : IModGroup, ITexToolsGroup
}
public (int Redirections, int Swaps, int Manips) GetCounts()
- => IModGroup.GetCountsBase(this);
+ => ModGroup.GetCountsBase(this);
public Setting FixSetting(Setting setting)
=> new(setting.Value & (1ul << OptionData.Count) - 1);
diff --git a/Penumbra/Mods/Groups/SingleModGroup.cs b/Penumbra/Mods/Groups/SingleModGroup.cs
index 6aa9160e..ac85e2bc 100644
--- a/Penumbra/Mods/Groups/SingleModGroup.cs
+++ b/Penumbra/Mods/Groups/SingleModGroup.cs
@@ -135,7 +135,7 @@ public sealed class SingleModGroup(Mod mod) : IModGroup, ITexToolsGroup
=> OptionData.Count == 0 ? Setting.Zero : new Setting(Math.Min(setting.Value, (ulong)(OptionData.Count - 1)));
public (int Redirections, int Swaps, int Manips) GetCounts()
- => IModGroup.GetCountsBase(this);
+ => ModGroup.GetCountsBase(this);
public void WriteJson(JsonTextWriter jWriter, JsonSerializer serializer, DirectoryInfo? basePath = null)
{
@@ -145,8 +145,8 @@ public sealed class SingleModGroup(Mod mod) : IModGroup, ITexToolsGroup
foreach (var option in OptionData)
{
jWriter.WriteStartObject();
- SubModHelpers.WriteModOption(jWriter, option);
- SubModHelpers.WriteModContainer(jWriter, serializer, option, basePath ?? Mod.ModPath);
+ SubMod.WriteModOption(jWriter, option);
+ SubMod.WriteModContainer(jWriter, serializer, option, basePath ?? Mod.ModPath);
jWriter.WriteEndObject();
}
diff --git a/Penumbra/Mods/Manager/ModOptionEditor.cs b/Penumbra/Mods/Manager/ModOptionEditor.cs
index a02c8d68..c6122ea8 100644
--- a/Penumbra/Mods/Manager/ModOptionEditor.cs
+++ b/Penumbra/Mods/Manager/ModOptionEditor.cs
@@ -68,7 +68,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
return;
saveService.ImmediateDelete(new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
- var _ = group switch
+ _ = group switch
{
SingleModGroup s => s.Name = newName,
MultiModGroup m => m.Name = newName,
@@ -85,21 +85,11 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
if (!VerifyFileName(mod, null, newName, true))
return;
- var maxPriority = mod.Groups.Count == 0 ? ModPriority.Default : mod.Groups.Max(o => o.Priority) + 1;
-
- mod.Groups.Add(type == GroupType.Multi
- ? new MultiModGroup(mod)
- {
- Name = newName,
- Priority = maxPriority,
- }
- : new SingleModGroup(mod)
- {
- Name = newName,
- Priority = maxPriority,
- });
- saveService.Save(saveType, new ModSaveGroup(mod, mod.Groups.Count - 1, config.ReplaceNonAsciiOnImport));
- communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupAdded, mod, mod.Groups.Count - 1, -1, -1);
+ var idx = mod.Groups.Count;
+ var group = ModGroup.Create(mod, type, newName);
+ mod.Groups.Add(group);
+ saveService.Save(saveType, new ModSaveGroup(mod, idx, config.ReplaceNonAsciiOnImport));
+ communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupAdded, mod, idx, -1, -1);
}
/// Add a new mod, empty option group of the given type and name if it does not exist already.
@@ -142,12 +132,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
if (group.Description == newDescription)
return;
- var _ = group switch
- {
- SingleModGroup s => s.Description = newDescription,
- MultiModGroup m => m.Description = newDescription,
- _ => newDescription,
- };
+ group.Description = newDescription;
saveService.QueueSave(new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
communicator.ModOptionChanged.Invoke(ModOptionChangeType.DisplayChange, mod, groupIdx, -1, -1);
}
@@ -155,9 +140,11 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
/// Change the description of the given option.
public void ChangeOptionDescription(Mod mod, int groupIdx, int optionIdx, string newDescription)
{
- if (!mod.Groups[groupIdx].ChangeOptionDescription(optionIdx, newDescription))
+ var option = mod.Groups[groupIdx].Options[optionIdx];
+ if (option.Description == newDescription)
return;
+ option.Description = newDescription;
saveService.QueueSave(new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
communicator.ModOptionChanged.Invoke(ModOptionChangeType.DisplayChange, mod, groupIdx, optionIdx, -1);
}
@@ -193,9 +180,12 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
/// Rename the given option.
public void RenameOption(Mod mod, int groupIdx, int optionIdx, string newName)
{
- if (!mod.Groups[groupIdx].ChangeOptionName(optionIdx, newName))
+ var option = mod.Groups[groupIdx].Options[optionIdx];
+ if (option.Name == newName)
return;
+ option.Name = newName;
+
saveService.QueueSave(new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
communicator.ModOptionChanged.Invoke(ModOptionChangeType.DisplayChange, mod, groupIdx, optionIdx, -1);
}
@@ -251,7 +241,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
Description = option.Description,
};
if (option is IModDataContainer data)
- SubModHelpers.Clone(data, newOption);
+ SubMod.Clone(data, newOption);
s.OptionData.Add(newOption);
break;
}
@@ -265,7 +255,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
Priority = option is MultiSubMod s ? s.Priority : ModPriority.Default,
};
if (option is IModDataContainer data)
- SubModHelpers.Clone(data, newOption);
+ SubMod.Clone(data, newOption);
m.OptionData.Add(newOption);
break;
}
diff --git a/Penumbra/Mods/Manager/ModStorage.cs b/Penumbra/Mods/Manager/ModStorage.cs
index 65b8ddd9..acb2c1ab 100644
--- a/Penumbra/Mods/Manager/ModStorage.cs
+++ b/Penumbra/Mods/Manager/ModStorage.cs
@@ -3,17 +3,13 @@ using OtterGui.Widgets;
namespace Penumbra.Mods.Manager;
-public class ModCombo : FilterComboCache
+public class ModCombo(Func> generator) : FilterComboCache(generator, MouseWheelType.None, Penumbra.Log)
{
protected override bool IsVisible(int globalIndex, LowerString filter)
=> Items[globalIndex].Name.Contains(filter);
protected override string ToString(Mod obj)
=> obj.Name.Text;
-
- public ModCombo(Func> generator)
- : base(generator, MouseWheelType.None, Penumbra.Log)
- { }
}
public class ModStorage : IReadOnlyList
diff --git a/Penumbra/Mods/ModCreator.cs b/Penumbra/Mods/ModCreator.cs
index 0626bc9d..40f943c8 100644
--- a/Penumbra/Mods/ModCreator.cs
+++ b/Penumbra/Mods/ModCreator.cs
@@ -115,7 +115,7 @@ public partial class ModCreator(
try
{
var jObject = File.Exists(defaultFile) ? JObject.Parse(File.ReadAllText(defaultFile)) : new JObject();
- SubModHelpers.LoadDataContainer(jObject, mod.Default, mod.ModPath);
+ SubMod.LoadDataContainer(jObject, mod.Default, mod.ModPath);
}
catch (Exception e)
{
diff --git a/Penumbra/Mods/SubMods/DefaultSubMod.cs b/Penumbra/Mods/SubMods/DefaultSubMod.cs
index 980b805d..1a234879 100644
--- a/Penumbra/Mods/SubMods/DefaultSubMod.cs
+++ b/Penumbra/Mods/SubMods/DefaultSubMod.cs
@@ -22,7 +22,7 @@ public class DefaultSubMod(IMod mod) : IModDataContainer
=> null;
public void AddTo(Dictionary redirections, HashSet manipulations)
- => SubModHelpers.AddContainerTo(this, redirections, manipulations);
+ => SubMod.AddContainerTo(this, redirections, manipulations);
public string GetName()
=> FullName;
diff --git a/Penumbra/Mods/SubMods/MultiSubMod.cs b/Penumbra/Mods/SubMods/MultiSubMod.cs
index c43d4b9e..3bcaffab 100644
--- a/Penumbra/Mods/SubMods/MultiSubMod.cs
+++ b/Penumbra/Mods/SubMods/MultiSubMod.cs
@@ -11,8 +11,8 @@ public class MultiSubMod(Mod mod, MultiModGroup group) : OptionSubMod() ?? ModPriority.Default;
}
@@ -24,7 +24,7 @@ public class MultiSubMod(Mod mod, MultiModGroup group) : OptionSubMod(Mod mod, T group) : IModDataOption
public HashSet Manipulations { get; set; } = [];
public void AddDataTo(Dictionary redirections, HashSet manipulations)
- => SubModHelpers.AddContainerTo(this, redirections, manipulations);
+ => SubMod.AddContainerTo(this, redirections, manipulations);
public string GetName()
=> Name;
diff --git a/Penumbra/Mods/SubMods/SingleSubMod.cs b/Penumbra/Mods/SubMods/SingleSubMod.cs
index 5d68e401..98c56151 100644
--- a/Penumbra/Mods/SubMods/SingleSubMod.cs
+++ b/Penumbra/Mods/SubMods/SingleSubMod.cs
@@ -9,8 +9,8 @@ public class SingleSubMod(Mod mod, SingleModGroup singleGroup) : OptionSubMod group switch
+ {
+ SingleModGroup single => new SingleSubMod(group.Mod, single)
+ {
+ Name = name,
+ Description = description,
+ },
+ MultiModGroup multi => new MultiSubMod(group.Mod, multi)
+ {
+ Name = name,
+ Description = description,
+ },
+ _ => throw new ArgumentOutOfRangeException(nameof(group)),
+ };
+
/// Add all unique meta manipulations, file redirections and then file swaps from a ModDataContainer to the given sets. Skip any keys that are already contained.
public static void AddContainerTo(IModDataContainer container, Dictionary redirections,
HashSet manipulations)