More cleanup on groups.

This commit is contained in:
Ottermandias 2024-04-26 10:57:09 +02:00
parent e40c4999b6
commit 297be487b5
14 changed files with 107 additions and 102 deletions

View file

@ -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<string, float, float,
{
public enum Priority
{
/// <seealso cref="PenumbraApi.PreSettingsTabBarDraw"/>
/// <seealso cref="Api.IpcSubscribers.PreSettingsTabBarDraw"/>
Default = 0,
}
}

View file

@ -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<IModOption> Options { get; }
public IReadOnlyList<IModOption> Options { get; }
public IReadOnlyList<IModDataContainer> 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);
}
}

View file

@ -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);
}
}

View file

@ -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();
}

View file

@ -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);

View file

@ -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();
}

View file

@ -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);
}
/// <summary> Add a new mod, empty option group of the given type and name if it does not exist already. </summary>
@ -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
/// <summary> Change the description of the given option. </summary>
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
/// <summary> Rename the given option. </summary>
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;
}

View file

@ -3,17 +3,13 @@ using OtterGui.Widgets;
namespace Penumbra.Mods.Manager;
public class ModCombo : FilterComboCache<Mod>
public class ModCombo(Func<IReadOnlyList<Mod>> generator) : FilterComboCache<Mod>(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<IReadOnlyList<Mod>> generator)
: base(generator, MouseWheelType.None, Penumbra.Log)
{ }
}
public class ModStorage : IReadOnlyList<Mod>

View file

@ -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)
{

View file

@ -22,7 +22,7 @@ public class DefaultSubMod(IMod mod) : IModDataContainer
=> null;
public void AddTo(Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations)
=> SubModHelpers.AddContainerTo(this, redirections, manipulations);
=> SubMod.AddContainerTo(this, redirections, manipulations);
public string GetName()
=> FullName;

View file

@ -11,8 +11,8 @@ public class MultiSubMod(Mod mod, MultiModGroup group) : OptionSubMod<MultiModGr
public MultiSubMod(Mod mod, MultiModGroup group, JToken json)
: this(mod, group)
{
SubModHelpers.LoadOptionData(json, this);
SubModHelpers.LoadDataContainer(json, this, mod.ModPath);
SubMod.LoadOptionData(json, this);
SubMod.LoadDataContainer(json, this, mod.ModPath);
Priority = json[nameof(IModGroup.Priority)]?.ToObject<ModPriority>() ?? ModPriority.Default;
}
@ -24,7 +24,7 @@ public class MultiSubMod(Mod mod, MultiModGroup group) : OptionSubMod<MultiModGr
Description = Description,
Priority = Priority,
};
SubModHelpers.Clone(this, ret);
SubMod.Clone(this, ret);
return ret;
}
@ -36,7 +36,7 @@ public class MultiSubMod(Mod mod, MultiModGroup group) : OptionSubMod<MultiModGr
Name = Name,
Description = Description,
};
SubModHelpers.Clone(this, ret);
SubMod.Clone(this, ret);
return ret;
}

View file

@ -32,7 +32,7 @@ public abstract class OptionSubMod<T>(Mod mod, T group) : IModDataOption
public HashSet<MetaManipulation> Manipulations { get; set; } = [];
public void AddDataTo(Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations)
=> SubModHelpers.AddContainerTo(this, redirections, manipulations);
=> SubMod.AddContainerTo(this, redirections, manipulations);
public string GetName()
=> Name;

View file

@ -9,8 +9,8 @@ public class SingleSubMod(Mod mod, SingleModGroup singleGroup) : OptionSubMod<Si
public SingleSubMod(Mod mod, SingleModGroup singleGroup, JToken json)
: this(mod, singleGroup)
{
SubModHelpers.LoadOptionData(json, this);
SubModHelpers.LoadDataContainer(json, this, mod.ModPath);
SubMod.LoadOptionData(json, this);
SubMod.LoadDataContainer(json, this, mod.ModPath);
}
public SingleSubMod Clone(Mod mod, SingleModGroup group)
@ -20,7 +20,7 @@ public class SingleSubMod(Mod mod, SingleModGroup singleGroup) : OptionSubMod<Si
Name = Name,
Description = Description,
};
SubModHelpers.Clone(this, ret);
SubMod.Clone(this, ret);
return ret;
}
@ -33,7 +33,7 @@ public class SingleSubMod(Mod mod, SingleModGroup singleGroup) : OptionSubMod<Si
Description = Description,
Priority = priority,
};
SubModHelpers.Clone(this, ret);
SubMod.Clone(this, ret);
return ret;
}

View file

@ -1,12 +1,29 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Groups;
using Penumbra.String.Classes;
namespace Penumbra.Mods.SubMods;
public static class SubModHelpers
public static class SubMod
{
public static IModOption Create(IModGroup group, string name, string description = "")
=> 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)),
};
/// <summary> 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. </summary>
public static void AddContainerTo(IModDataContainer container, Dictionary<Utf8GamePath, FullPath> redirections,
HashSet<MetaManipulation> manipulations)