diff --git a/Penumbra/Import/TexToolsImporter.ModPack.cs b/Penumbra/Import/TexToolsImporter.ModPack.cs index 7a247a53..099b133c 100644 --- a/Penumbra/Import/TexToolsImporter.ModPack.cs +++ b/Penumbra/Import/TexToolsImporter.ModPack.cs @@ -153,7 +153,7 @@ public partial class TexToolsImporter // Iterate through all pages var options = new List(); - var groupPriority = 0; + var groupPriority = ModPriority.Default; var groupNames = new HashSet(); foreach (var page in modList.ModPackPages) { @@ -209,9 +209,9 @@ public partial class TexToolsImporter } } - _modManager.Creator.CreateOptionGroup(_currentModDirectory, group.SelectionType, name, groupPriority, groupPriority, + _modManager.Creator.CreateOptionGroup(_currentModDirectory, group.SelectionType, name, groupPriority, groupPriority.Value, defaultSettings ?? Setting.Zero, group.Description, options); - ++groupPriority; + groupPriority += 1; } } } diff --git a/Penumbra/Mods/Manager/ModMigration.cs b/Penumbra/Mods/Manager/ModMigration.cs index 8b73cae5..295afd7b 100644 --- a/Penumbra/Mods/Manager/ModMigration.cs +++ b/Penumbra/Mods/Manager/ModMigration.cs @@ -61,10 +61,9 @@ public static partial class ModMigration if (fileVersion > 0) return false; - var swaps = json["FileSwaps"]?.ToObject>() - ?? new Dictionary(); - var groups = json["Groups"]?.ToObject>() ?? new Dictionary(); - var priority = 1; + var swaps = json["FileSwaps"]?.ToObject>() ?? []; + var groups = json["Groups"]?.ToObject>() ?? []; + var priority = new ModPriority(1); var seenMetaFiles = new HashSet(); foreach (var group in groups.Values) ConvertGroup(creator, mod, group, ref priority, seenMetaFiles); @@ -116,7 +115,8 @@ public static partial class ModMigration return true; } - private static void ConvertGroup(ModCreator creator, Mod mod, OptionGroupV0 group, ref int priority, HashSet seenMetaFiles) + private static void ConvertGroup(ModCreator creator, Mod mod, OptionGroupV0 group, ref ModPriority priority, + HashSet seenMetaFiles) { if (group.Options.Count == 0) return; @@ -125,7 +125,7 @@ public static partial class ModMigration { case GroupType.Multi: - var optionPriority = 0; + var optionPriority = ModPriority.Default; var newMultiGroup = new MultiModGroup() { Name = group.GroupName, diff --git a/Penumbra/Mods/Manager/ModOptionEditor.cs b/Penumbra/Mods/Manager/ModOptionEditor.cs index ea6a62df..0ffdc4af 100644 --- a/Penumbra/Mods/Manager/ModOptionEditor.cs +++ b/Penumbra/Mods/Manager/ModOptionEditor.cs @@ -34,8 +34,6 @@ public enum ModOptionChangeType public class ModOptionEditor(CommunicatorService communicator, SaveService saveService, Configuration config) { - - /// Change the type of a group given by mod and index to type, if possible. public void ChangeModGroupType(Mod mod, int groupIdx, GroupType type) { @@ -86,7 +84,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS if (!VerifyFileName(mod, null, newName, true)) return; - var maxPriority = mod.Groups.Count == 0 ? 0 : mod.Groups.Max(o => o.Priority) + 1; + var maxPriority = mod.Groups.Count == 0 ? ModPriority.Default : mod.Groups.Max(o => o.Priority) + 1; mod.Groups.Add(type == GroupType.Multi ? new MultiModGroup @@ -169,7 +167,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS } /// Change the internal priority of the given option group. - public void ChangeGroupPriority(Mod mod, int groupIdx, int newPriority) + public void ChangeGroupPriority(Mod mod, int groupIdx, ModPriority newPriority) { var group = mod.Groups[groupIdx]; if (group.Priority == newPriority) @@ -186,7 +184,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS } /// Change the internal priority of the given option. - public void ChangeOptionPriority(Mod mod, int groupIdx, int optionIdx, int newPriority) + public void ChangeOptionPriority(Mod mod, int groupIdx, int optionIdx, ModPriority newPriority) { switch (mod.Groups[groupIdx]) { @@ -240,7 +238,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS s.OptionData.Add(subMod); break; case MultiModGroup m: - m.PrioritizedOptions.Add((subMod, 0)); + m.PrioritizedOptions.Add((subMod, ModPriority.Default)); break; } @@ -263,8 +261,12 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS return ((SubMod)group[^1], true); } - /// Add an existing option to a given group with a given priority. - public void AddOption(Mod mod, int groupIdx, ISubMod option, int priority = 0) + /// Add an existing option to a given group with default priority. + public void AddOption(Mod mod, int groupIdx, ISubMod option) + => AddOption(mod, groupIdx, option, ModPriority.Default); + + /// Add an existing option to a given group with a given priority. + public void AddOption(Mod mod, int groupIdx, ISubMod option, ModPriority priority) { if (option is not SubMod o) return; diff --git a/Penumbra/Mods/ModCreator.cs b/Penumbra/Mods/ModCreator.cs index c324af48..2bcdd3b1 100644 --- a/Penumbra/Mods/ModCreator.cs +++ b/Penumbra/Mods/ModCreator.cs @@ -235,7 +235,7 @@ public partial class ModCreator(SaveService _saveService, Configuration config, /// Create a file for an option group from given data. public void CreateOptionGroup(DirectoryInfo baseFolder, GroupType type, string name, - int priority, int index, Setting defaultSettings, string desc, IEnumerable subMods) + ModPriority priority, int index, Setting defaultSettings, string desc, IEnumerable subMods) { switch (type) { @@ -248,7 +248,7 @@ public partial class ModCreator(SaveService _saveService, Configuration config, Priority = priority, DefaultSettings = defaultSettings, }; - group.PrioritizedOptions.AddRange(subMods.OfType().Select((s, idx) => (s, idx))); + group.PrioritizedOptions.AddRange(subMods.OfType().Select((s, idx) => (s, new ModPriority(idx)))); _saveService.ImmediateSaveSync(new ModSaveGroup(baseFolder, group, index, Config.ReplaceNonAsciiOnImport)); break; } diff --git a/Penumbra/Mods/Subclasses/IModGroup.cs b/Penumbra/Mods/Subclasses/IModGroup.cs index 2f6b2403..e9e2a93b 100644 --- a/Penumbra/Mods/Subclasses/IModGroup.cs +++ b/Penumbra/Mods/Subclasses/IModGroup.cs @@ -8,13 +8,13 @@ public interface IModGroup : IEnumerable { public const int MaxMultiOptions = 32; - public string Name { get; } - public string Description { get; } - public GroupType Type { get; } - public int Priority { get; } - public Setting DefaultSettings { get; set; } + public string Name { get; } + public string Description { get; } + public GroupType Type { get; } + public ModPriority Priority { get; } + public Setting DefaultSettings { get; set; } - public int OptionPriority(Index optionIdx); + public ModPriority OptionPriority(Index optionIdx); public ISubMod this[Index idx] { get; } @@ -94,7 +94,11 @@ public readonly struct ModSaveGroup : ISavable j.WritePropertyName("Options"); j.WriteStartArray(); for (var idx = 0; idx < _group.Count; ++idx) - ISubMod.WriteSubMod(j, serializer, _group[idx], _basePath, _group.Type == GroupType.Multi ? _group.OptionPriority(idx) : null); + ISubMod.WriteSubMod(j, serializer, _group[idx], _basePath, _group.Type switch + { + GroupType.Multi => _group.OptionPriority(idx), + _ => null, + }); j.WriteEndArray(); j.WriteEndObject(); diff --git a/Penumbra/Mods/Subclasses/ISubMod.cs b/Penumbra/Mods/Subclasses/ISubMod.cs index 8c296f20..29323c1d 100644 --- a/Penumbra/Mods/Subclasses/ISubMod.cs +++ b/Penumbra/Mods/Subclasses/ISubMod.cs @@ -16,7 +16,7 @@ public interface ISubMod public bool IsDefault { get; } - public static void WriteSubMod(JsonWriter j, JsonSerializer serializer, ISubMod mod, DirectoryInfo basePath, int? priority) + public static void WriteSubMod(JsonWriter j, JsonSerializer serializer, ISubMod mod, DirectoryInfo basePath, ModPriority? priority) { j.WriteStartObject(); j.WritePropertyName(nameof(Name)); @@ -26,7 +26,7 @@ public interface ISubMod if (priority != null) { j.WritePropertyName(nameof(IModGroup.Priority)); - j.WriteValue(priority.Value); + j.WriteValue(priority.Value.Value); } j.WritePropertyName(nameof(mod.Files)); diff --git a/Penumbra/Mods/Subclasses/ModPriority.cs b/Penumbra/Mods/Subclasses/ModPriority.cs index 3302c627..a99c12ed 100644 --- a/Penumbra/Mods/Subclasses/ModPriority.cs +++ b/Penumbra/Mods/Subclasses/ModPriority.cs @@ -8,7 +8,9 @@ public readonly record struct ModPriority(int Value) : IAdditionOperators, IAdditionOperators, ISubtractionOperators, - ISubtractionOperators + ISubtractionOperators, + IIncrementOperators, + IComparable { public static readonly ModPriority Default = new(0); public static readonly ModPriority MaxValue = new(int.MaxValue); @@ -58,4 +60,10 @@ public readonly record struct ModPriority(int Value) : public static ModPriority operator -(ModPriority left, int right) => new(left.Value - right); + + public static ModPriority operator ++(ModPriority value) + => new(value.Value + 1); + + public int CompareTo(ModPriority other) + => Value.CompareTo(other.Value); } diff --git a/Penumbra/Mods/Subclasses/MultiModGroup.cs b/Penumbra/Mods/Subclasses/MultiModGroup.cs index 8a8e10bd..444e8e2c 100644 --- a/Penumbra/Mods/Subclasses/MultiModGroup.cs +++ b/Penumbra/Mods/Subclasses/MultiModGroup.cs @@ -14,12 +14,12 @@ public sealed class MultiModGroup : IModGroup public GroupType Type => GroupType.Multi; - public string Name { get; set; } = "Group"; - public string Description { get; set; } = "A non-exclusive group of settings."; - public int Priority { get; set; } - public Setting DefaultSettings { get; set; } + public string Name { get; set; } = "Group"; + public string Description { get; set; } = "A non-exclusive group of settings."; + public ModPriority Priority { get; set; } + public Setting DefaultSettings { get; set; } - public int OptionPriority(Index idx) + public ModPriority OptionPriority(Index idx) => PrioritizedOptions[idx].Priority; public ISubMod this[Index idx] @@ -29,7 +29,7 @@ public sealed class MultiModGroup : IModGroup public int Count => PrioritizedOptions.Count; - public readonly List<(SubMod Mod, int Priority)> PrioritizedOptions = new(); + public readonly List<(SubMod Mod, ModPriority Priority)> PrioritizedOptions = []; public IEnumerator GetEnumerator() => PrioritizedOptions.Select(o => o.Mod).GetEnumerator(); @@ -43,7 +43,7 @@ public sealed class MultiModGroup : IModGroup { Name = json[nameof(Name)]?.ToObject() ?? string.Empty, Description = json[nameof(Description)]?.ToObject() ?? string.Empty, - Priority = json[nameof(Priority)]?.ToObject() ?? 0, + Priority = json[nameof(Priority)]?.ToObject() ?? ModPriority.Default, DefaultSettings = json[nameof(DefaultSettings)]?.ToObject() ?? Setting.Zero, }; if (ret.Name.Length == 0) diff --git a/Penumbra/Mods/Subclasses/SingleModGroup.cs b/Penumbra/Mods/Subclasses/SingleModGroup.cs index be1dbde5..0bfa04f4 100644 --- a/Penumbra/Mods/Subclasses/SingleModGroup.cs +++ b/Penumbra/Mods/Subclasses/SingleModGroup.cs @@ -12,14 +12,14 @@ public sealed class SingleModGroup : IModGroup public GroupType Type => GroupType.Single; - public string Name { get; set; } = "Option"; - public string Description { get; set; } = "A mutually exclusive group of settings."; - public int Priority { get; set; } - public Setting DefaultSettings { get; set; } + public string Name { get; set; } = "Option"; + public string Description { get; set; } = "A mutually exclusive group of settings."; + public ModPriority Priority { get; set; } + public Setting DefaultSettings { get; set; } public readonly List OptionData = []; - public int OptionPriority(Index _) + public ModPriority OptionPriority(Index _) => Priority; public ISubMod this[Index idx] @@ -42,7 +42,7 @@ public sealed class SingleModGroup : IModGroup { Name = json[nameof(Name)]?.ToObject() ?? string.Empty, Description = json[nameof(Description)]?.ToObject() ?? string.Empty, - Priority = json[nameof(Priority)]?.ToObject() ?? 0, + Priority = json[nameof(Priority)]?.ToObject() ?? ModPriority.Default, DefaultSettings = json[nameof(DefaultSettings)]?.ToObject() ?? Setting.Zero, }; if (ret.Name.Length == 0) @@ -72,9 +72,9 @@ public sealed class SingleModGroup : IModGroup Name = Name, Description = Description, Priority = Priority, - DefaultSettings = Setting.Multi((int) DefaultSettings.Value), + DefaultSettings = Setting.Multi((int)DefaultSettings.Value), }; - multi.PrioritizedOptions.AddRange(OptionData.Select((o, i) => (o, i))); + multi.PrioritizedOptions.AddRange(OptionData.Select((o, i) => (o, new ModPriority(i)))); return multi; default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } diff --git a/Penumbra/Mods/Subclasses/SubMod.cs b/Penumbra/Mods/Subclasses/SubMod.cs index 88c4e4ce..4f35cd33 100644 --- a/Penumbra/Mods/Subclasses/SubMod.cs +++ b/Penumbra/Mods/Subclasses/SubMod.cs @@ -53,7 +53,7 @@ public sealed class SubMod : ISubMod OptionIdx = optionIdx; } - public void Load(DirectoryInfo basePath, JToken json, out int priority) + public void Load(DirectoryInfo basePath, JToken json, out ModPriority priority) { FileData.Clear(); FileSwapData.Clear(); @@ -62,7 +62,7 @@ public sealed class SubMod : ISubMod // Every option has a name, but priorities are only relevant for multi group options. Name = json[nameof(ISubMod.Name)]?.ToObject() ?? string.Empty; Description = json[nameof(ISubMod.Description)]?.ToObject() ?? string.Empty; - priority = json[nameof(IModGroup.Priority)]?.ToObject() ?? 0; + priority = json[nameof(IModGroup.Priority)]?.ToObject() ?? ModPriority.Default; var files = (JObject?)json[nameof(Files)]; if (files != null) diff --git a/Penumbra/UI/ModsTab/ModPanelEditTab.cs b/Penumbra/UI/ModsTab/ModPanelEditTab.cs index 1292367a..80af7b15 100644 --- a/Penumbra/UI/ModsTab/ModPanelEditTab.cs +++ b/Penumbra/UI/ModsTab/ModPanelEditTab.cs @@ -511,7 +511,8 @@ public class ModPanelEditTab( { var isDefaultOption = group.DefaultSettings.HasFlag(optionIdx); if (ImGui.Checkbox("##default", ref isDefaultOption)) - panel._modManager.OptionEditor.ChangeModGroupDefaultOption(panel._mod, groupIdx, group.DefaultSettings.SetBit(optionIdx, isDefaultOption)); + panel._modManager.OptionEditor.ChangeModGroupDefaultOption(panel._mod, groupIdx, + group.DefaultSettings.SetBit(optionIdx, isDefaultOption)); ImGuiUtil.HoverTooltip($"{(isDefaultOption ? "Disable" : "Enable")} {option.Name} per default in this group."); } @@ -669,10 +670,10 @@ public class ModPanelEditTab( public const int Description = -7; // Temporary strings - private static string? _currentEdit; - private static int? _currentGroupPriority; - private static int _currentField = None; - private static int _optionIndex = None; + private static string? _currentEdit; + private static ModPriority? _currentGroupPriority; + private static int _currentField = None; + private static int _optionIndex = None; public static void Reset() { @@ -705,13 +706,13 @@ public class ModPanelEditTab( return false; } - public static bool Priority(string label, int field, int option, int oldValue, out int value, float width) + public static bool Priority(string label, int field, int option, ModPriority oldValue, out ModPriority value, float width) { - var tmp = field == _currentField && option == _optionIndex ? _currentGroupPriority ?? oldValue : oldValue; + var tmp = (field == _currentField && option == _optionIndex ? _currentGroupPriority ?? oldValue : oldValue).Value; ImGui.SetNextItemWidth(width); if (ImGui.InputInt(label, ref tmp, 0, 0)) { - _currentGroupPriority = tmp; + _currentGroupPriority = new ModPriority(tmp); _optionIndex = option; _currentField = field; } @@ -724,7 +725,7 @@ public class ModPanelEditTab( return ret; } - value = 0; + value = ModPriority.Default; return false; } }