Penumbra/Penumbra/Mods/Groups/SingleModGroup.cs
2024-08-03 22:45:44 +02:00

151 lines
5.1 KiB
C#

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OtterGui;
using Penumbra.Api.Enums;
using Penumbra.GameData.Data;
using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Settings;
using Penumbra.Mods.SubMods;
using Penumbra.String.Classes;
using Penumbra.UI.ModsTab.Groups;
using Penumbra.Util;
namespace Penumbra.Mods.Groups;
/// <summary> Groups that allow only one of their available options to be selected. </summary>
public sealed class SingleModGroup(Mod mod) : IModGroup, ITexToolsGroup
{
public GroupType Type
=> GroupType.Single;
public GroupDrawBehaviour Behaviour
=> GroupDrawBehaviour.SingleSelection;
public Mod Mod { get; } = mod;
public string Name { get; set; } = "Option";
public string Description { get; set; } = string.Empty;
public string Image { get; set; } = string.Empty;
public ModPriority Priority { get; set; }
public Setting DefaultSettings { get; set; }
public readonly List<SingleSubMod> OptionData = [];
public FullPath? FindBestMatch(Utf8GamePath gamePath)
{
foreach (var path in OptionData
.SelectWhere(m => (m.Files.TryGetValue(gamePath, out var file) || m.FileSwaps.TryGetValue(gamePath, out file), file)))
return path;
return null;
}
public IModOption AddOption(string name, string description = "")
{
var subMod = new SingleSubMod(this)
{
Name = name,
Description = description,
};
OptionData.Add(subMod);
return subMod;
}
public IReadOnlyList<IModOption> Options
=> OptionData;
public IReadOnlyList<IModDataContainer> DataContainers
=> OptionData;
public bool IsOption
=> OptionData.Count > 1;
public static SingleModGroup? Load(Mod mod, JObject json)
{
var options = json["Options"];
var ret = new SingleModGroup(mod)
{
Name = json[nameof(Name)]?.ToObject<string>() ?? string.Empty,
Description = json[nameof(Description)]?.ToObject<string>() ?? string.Empty,
Image = json[nameof(Image)]?.ToObject<string>() ?? string.Empty,
Priority = json[nameof(Priority)]?.ToObject<ModPriority>() ?? ModPriority.Default,
DefaultSettings = json[nameof(DefaultSettings)]?.ToObject<Setting>() ?? Setting.Zero,
};
if (ret.Name.Length == 0)
return null;
if (options != null)
foreach (var child in options.Children())
{
var subMod = new SingleSubMod(ret, child);
ret.OptionData.Add(subMod);
}
ret.DefaultSettings = ret.FixSetting(ret.DefaultSettings);
return ret;
}
public MultiModGroup ConvertToMulti()
{
var multi = new MultiModGroup(Mod)
{
Name = Name,
Description = Description,
Priority = Priority,
DefaultSettings = Setting.Multi((int)DefaultSettings.Value),
};
multi.OptionData.AddRange(OptionData.Select((o, i) => o.ConvertToMulti(multi, new ModPriority(i))));
return multi;
}
public int GetIndex()
=> ModGroup.GetIndex(this);
public IModGroupEditDrawer EditDrawer(ModGroupEditDrawer editDrawer)
=> new SingleModGroupEditDrawer(editDrawer, this);
public void AddData(Setting setting, Dictionary<Utf8GamePath, FullPath> redirections, MetaDictionary manipulations)
{
if (OptionData.Count == 0)
return;
OptionData[setting.AsIndex].AddDataTo(redirections, manipulations);
}
public void AddChangedItems(ObjectIdentification identifier, IDictionary<string, IIdentifiedObjectData?> changedItems)
{
foreach (var container in DataContainers)
identifier.AddChangedItems(container, changedItems);
}
public Setting FixSetting(Setting setting)
=> OptionData.Count == 0 ? Setting.Zero : new Setting(Math.Min(setting.Value, (ulong)(OptionData.Count - 1)));
public (int Redirections, int Swaps, int Manips) GetCounts()
=> ModGroup.GetCountsBase(this);
public void WriteJson(JsonTextWriter jWriter, JsonSerializer serializer, DirectoryInfo? basePath = null)
{
ModSaveGroup.WriteJsonBase(jWriter, this);
jWriter.WritePropertyName("Options");
jWriter.WriteStartArray();
foreach (var option in OptionData)
{
jWriter.WriteStartObject();
SubMod.WriteModOption(jWriter, option);
SubMod.WriteModContainer(jWriter, serializer, option, basePath ?? Mod.ModPath);
jWriter.WriteEndObject();
}
jWriter.WriteEndArray();
}
/// <summary> Create a group without a mod only for saving it in the creator. </summary>
internal static SingleModGroup CreateForSaving(string name)
=> new(null!)
{
Name = name,
};
IReadOnlyList<OptionSubMod> ITexToolsGroup.OptionData
=> OptionData;
}