mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
198 lines
7.6 KiB
C#
198 lines
7.6 KiB
C#
using OtterGui;
|
|
using OtterGui.Filesystem;
|
|
using Penumbra.Api.Enums;
|
|
using Penumbra.Mods.Editor;
|
|
using Penumbra.Mods.Groups;
|
|
using Penumbra.Mods.Manager;
|
|
|
|
namespace Penumbra.Mods.Settings;
|
|
|
|
/// <summary> Contains the settings for a given mod. </summary>
|
|
public class ModSettings
|
|
{
|
|
public static readonly ModSettings Empty = new();
|
|
public SettingList Settings { get; private init; } = [];
|
|
public ModPriority Priority { get; set; }
|
|
public bool Enabled { get; set; }
|
|
|
|
// Create an independent copy of the current settings.
|
|
public ModSettings DeepCopy()
|
|
=> new()
|
|
{
|
|
Enabled = Enabled,
|
|
Priority = Priority,
|
|
Settings = Settings.Clone(),
|
|
};
|
|
|
|
// Create default settings for a given mod.
|
|
public static ModSettings DefaultSettings(Mod mod)
|
|
=> new()
|
|
{
|
|
Enabled = false,
|
|
Priority = ModPriority.Default,
|
|
Settings = SettingList.Default(mod),
|
|
};
|
|
|
|
// Return everything required to resolve things for a single mod with given settings (which can be null, in which case the default is used.
|
|
public static AppliedModData GetResolveData(Mod mod, ModSettings? settings)
|
|
{
|
|
if (settings == null)
|
|
settings = DefaultSettings(mod);
|
|
else
|
|
settings.Settings.FixSize(mod);
|
|
|
|
return mod.GetData(settings);
|
|
}
|
|
|
|
// Automatically react to changes in a mods available options.
|
|
public bool HandleChanges(ModOptionChangeType type, Mod mod, int groupIdx, int optionIdx, int movedToIdx)
|
|
{
|
|
switch (type)
|
|
{
|
|
case ModOptionChangeType.GroupRenamed: return true;
|
|
case ModOptionChangeType.GroupAdded:
|
|
// Add new empty setting for new mod.
|
|
Settings.Insert(groupIdx, mod.Groups[groupIdx].DefaultSettings);
|
|
return true;
|
|
case ModOptionChangeType.GroupDeleted:
|
|
// Remove setting for deleted mod.
|
|
Settings.RemoveAt(groupIdx);
|
|
return true;
|
|
case ModOptionChangeType.GroupTypeChanged:
|
|
{
|
|
// Fix settings for a changed group type.
|
|
// Single -> Multi: set single as enabled, rest as disabled
|
|
// Multi -> Single: set the first enabled option or 0.
|
|
var group = mod.Groups[groupIdx];
|
|
var config = Settings[groupIdx];
|
|
Settings[groupIdx] = group.Type switch
|
|
{
|
|
GroupType.Single => config.TurnMulti(group.Options.Count),
|
|
GroupType.Multi => Setting.Multi((int)config.Value),
|
|
_ => config,
|
|
};
|
|
return config != Settings[groupIdx];
|
|
}
|
|
case ModOptionChangeType.OptionDeleted:
|
|
{
|
|
// Single -> select the previous option if any.
|
|
// Multi -> excise the corresponding bit.
|
|
var group = mod.Groups[groupIdx];
|
|
var config = Settings[groupIdx];
|
|
Settings[groupIdx] = group.Type switch
|
|
{
|
|
GroupType.Single => config.AsIndex >= optionIdx
|
|
? config.AsIndex > 1 ? Setting.Single(config.AsIndex - 1) : Setting.Zero
|
|
: config,
|
|
GroupType.Multi => config.RemoveBit(optionIdx),
|
|
_ => config,
|
|
};
|
|
return config != Settings[groupIdx];
|
|
}
|
|
case ModOptionChangeType.GroupMoved:
|
|
// Move the group the same way.
|
|
return Settings.Move(groupIdx, movedToIdx);
|
|
case ModOptionChangeType.OptionMoved:
|
|
{
|
|
// Single -> select the moved option if it was currently selected
|
|
// Multi -> move the corresponding bit
|
|
var group = mod.Groups[groupIdx];
|
|
var config = Settings[groupIdx];
|
|
Settings[groupIdx] = group.Type switch
|
|
{
|
|
GroupType.Single => config.AsIndex == optionIdx ? Setting.Single(movedToIdx) : config,
|
|
GroupType.Multi => config.MoveBit(optionIdx, movedToIdx),
|
|
_ => config,
|
|
};
|
|
return config != Settings[groupIdx];
|
|
}
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
/// <summary> Set a setting. Ensures that there are enough settings and fixes the setting beforehand. </summary>
|
|
public void SetValue(Mod mod, int groupIdx, Setting newValue)
|
|
{
|
|
Settings.FixSize(mod);
|
|
var group = mod.Groups[groupIdx];
|
|
Settings[groupIdx] = group.FixSetting(newValue);
|
|
}
|
|
|
|
// A simple struct conversion to easily save settings by name instead of value.
|
|
public struct SavedSettings
|
|
{
|
|
public Dictionary<string, Setting> Settings;
|
|
public ModPriority Priority;
|
|
public bool Enabled;
|
|
|
|
public SavedSettings DeepCopy()
|
|
=> this with { Settings = Settings.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) };
|
|
|
|
public SavedSettings(ModSettings settings, Mod mod)
|
|
{
|
|
Priority = settings.Priority;
|
|
Enabled = settings.Enabled;
|
|
Settings = new Dictionary<string, Setting>(mod.Groups.Count);
|
|
settings.Settings.FixSize(mod);
|
|
|
|
foreach (var (group, setting) in mod.Groups.Zip(settings.Settings))
|
|
Settings.Add(group.Name, setting);
|
|
}
|
|
|
|
// Convert and fix.
|
|
public readonly bool ToSettings(Mod mod, out ModSettings settings)
|
|
{
|
|
var list = new SettingList(mod.Groups.Count);
|
|
var changes = Settings.Count != mod.Groups.Count;
|
|
foreach (var group in mod.Groups)
|
|
{
|
|
if (Settings.TryGetValue(group.Name, out var config))
|
|
{
|
|
var actualConfig = group.FixSetting(config);
|
|
list.Add(actualConfig);
|
|
if (actualConfig != config)
|
|
changes = true;
|
|
}
|
|
else
|
|
{
|
|
list.Add(group.DefaultSettings);
|
|
changes = true;
|
|
}
|
|
}
|
|
|
|
settings = new ModSettings
|
|
{
|
|
Enabled = Enabled,
|
|
Priority = Priority,
|
|
Settings = list,
|
|
};
|
|
|
|
return changes;
|
|
}
|
|
}
|
|
|
|
// Return the settings for a given mod in a shareable format, using the names of groups and options instead of indices.
|
|
// Does not repair settings but ignores settings not fitting to the given mod.
|
|
public (bool Enabled, ModPriority Priority, Dictionary<string, List<string>> Settings) ConvertToShareable(Mod mod)
|
|
{
|
|
var dict = new Dictionary<string, List<string>>(Settings.Count);
|
|
foreach (var (setting, idx) in Settings.WithIndex())
|
|
{
|
|
if (idx >= mod.Groups.Count)
|
|
break;
|
|
|
|
switch (mod.Groups[idx])
|
|
{
|
|
case SingleModGroup single when setting.Value < (ulong)single.Options.Count:
|
|
dict.Add(single.Name, [single.Options[setting.AsIndex].Name]);
|
|
break;
|
|
case MultiModGroup multi:
|
|
var list = multi.Options.WithIndex().Where(p => setting.HasFlag(p.Index)).Select(p => p.Value.Name).ToList();
|
|
dict.Add(multi.Name, list);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (Enabled, Priority, dict);
|
|
}
|
|
}
|