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)