Update Mod Merger for other group types.

This commit is contained in:
Ottermandias 2025-06-07 22:10:59 +02:00
parent 535694e9c8
commit 4c0e6d2a67
2 changed files with 139 additions and 48 deletions

View file

@ -6,6 +6,7 @@ using OtterGui.Extensions;
using OtterGui.Services;
using Penumbra.Api.Enums;
using Penumbra.Communication;
using Penumbra.Mods.Groups;
using Penumbra.Mods.Manager;
using Penumbra.Mods.Manager.OptionEditor;
using Penumbra.Mods.SubMods;
@ -44,13 +45,13 @@ public class ModMerger : IDisposable, IService
public ModMerger(ModManager mods, ModGroupEditor editor, ModSelection selection, DuplicateManager duplicates,
CommunicatorService communicator, ModCreator creator, Configuration config)
{
_editor = editor;
_selection = selection;
_duplicates = duplicates;
_communicator = communicator;
_creator = creator;
_config = config;
_mods = mods;
_editor = editor;
_selection = selection;
_duplicates = duplicates;
_communicator = communicator;
_creator = creator;
_config = config;
_mods = mods;
_selection.Subscribe(OnSelectionChange, ModSelection.Priority.ModMerger);
_communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModMerger);
}
@ -99,26 +100,117 @@ public class ModMerger : IDisposable, IService
foreach (var originalGroup in MergeFromMod!.Groups)
{
var (group, groupIdx, groupCreated) = _editor.FindOrAddModGroup(MergeToMod!, originalGroup.Type, originalGroup.Name);
if (groupCreated)
_createdGroups.Add(groupIdx);
if (group == null)
throw new Exception(
$"The merged group {originalGroup.Name} already existed, but had a different type than the original group of type {originalGroup.Type}.");
foreach (var originalOption in originalGroup.DataContainers)
switch (originalGroup.Type)
{
var (option, _, optionCreated) = _editor.FindOrAddOption(group, originalOption.GetName());
if (optionCreated)
case GroupType.Single:
case GroupType.Multi:
{
_createdOptions.Add(option!);
// #TODO DataContainer <> Option.
MergeIntoOption([originalOption], (IModDataContainer)option!, false);
var (group, groupIdx, groupCreated) = _editor.FindOrAddModGroup(MergeToMod!, originalGroup.Type, originalGroup.Name);
if (group is null)
throw new Exception(
$"The merged group {originalGroup.Name} already existed, but had a different type than the original group of type {originalGroup.Type}.");
if (groupCreated)
{
_createdGroups.Add(groupIdx);
group.Description = originalGroup.Description;
group.Image = originalGroup.Image;
group.DefaultSettings = originalGroup.DefaultSettings;
group.Page = originalGroup.Page;
group.Priority = originalGroup.Priority;
}
foreach (var originalOption in originalGroup.Options)
{
var (option, _, optionCreated) = _editor.FindOrAddOption(group, originalOption.Name);
if (optionCreated)
{
_createdOptions.Add(option!);
MergeIntoOption([(IModDataContainer)originalOption], (IModDataContainer)option!, false);
option!.Description = originalOption.Description;
if (option is MultiSubMod multiOption)
multiOption.Priority = ((MultiSubMod)originalOption).Priority;
}
else
{
throw new Exception(
$"Could not merge {MergeFromMod!.Name} into {MergeToMod!.Name}: The option {option!.FullName} already existed.");
}
}
break;
}
else
case GroupType.Imc when originalGroup is ImcModGroup imc:
{
throw new Exception(
$"Could not merge {MergeFromMod!.Name} into {MergeToMod!.Name}: The option {option!.FullName} already existed.");
var group = _editor.ImcEditor.AddModGroup(MergeToMod!, imc.Name, imc.Identifier, imc.DefaultEntry);
if (group is null)
throw new Exception(
$"The merged group {originalGroup.Name} already existed, but groups of type {originalGroup.Type} can not be merged.");
group.AllVariants = imc.AllVariants;
group.OnlyAttributes = imc.OnlyAttributes;
group.Description = imc.Description;
group.Image = imc.Image;
group.DefaultSettings = imc.DefaultSettings;
group.Page = imc.Page;
group.Priority = imc.Priority;
foreach (var originalOption in imc.OptionData)
{
if (originalOption.IsDisableSubMod)
{
_editor.ImcEditor.ChangeCanBeDisabled(group, true);
var disable = group.OptionData.First(s => s.IsDisableSubMod);
disable.Description = originalOption.Description;
disable.Name = originalOption.Name;
continue;
}
var newOption = _editor.ImcEditor.AddOption(group, originalOption.Name);
if (newOption is null)
throw new Exception(
$"Could not merge {MergeFromMod!.Name} into {MergeToMod!.Name}: Unknown error when creating IMC option {originalOption.FullName}.");
newOption.Description = originalOption.Description;
newOption.AttributeMask = originalOption.AttributeMask;
}
break;
}
case GroupType.Combining when originalGroup is CombiningModGroup combining:
{
var group = _editor.CombiningEditor.AddModGroup(MergeToMod!, combining.Name);
if (group is null)
throw new Exception(
$"The merged group {originalGroup.Name} already existed, but groups of type {originalGroup.Type} can not be merged.");
group.Description = combining.Description;
group.Image = combining.Image;
group.DefaultSettings = combining.DefaultSettings;
group.Page = combining.Page;
group.Priority = combining.Priority;
foreach (var originalOption in combining.OptionData)
{
var option = _editor.CombiningEditor.AddOption(group, originalOption.Name);
if (option is null)
throw new Exception(
$"Could not merge {MergeFromMod!.Name} into {MergeToMod!.Name}: Unknown error when creating combining option {originalOption.FullName}.");
option.Description = originalOption.Description;
}
if (group.Data.Count != combining.Data.Count)
throw new Exception(
$"Could not merge {MergeFromMod!.Name} into {MergeToMod!.Name}: Unknown error caused data container counts in combining group {originalGroup.Name} to differ.");
foreach (var (originalContainer, container) in combining.Data.Zip(group.Data))
{
container.Name = originalContainer.Name;
MergeIntoOption([originalContainer], container, false);
}
break;
}
}
}
@ -151,7 +243,6 @@ public class ModMerger : IDisposable, IService
if (!dir.Exists)
_createdDirectories.Add(dir.FullName);
CopyFiles(dir);
// #TODO DataContainer <> Option.
MergeIntoOption(MergeFromMod!.AllDataContainers.Reverse(), (IModDataContainer)option!, true);
}

View file

@ -15,8 +15,8 @@ public abstract class ModOptionEditor<TGroup, TOption>(
where TOption : class, IModOption
{
protected readonly CommunicatorService Communicator = communicator;
protected readonly SaveService SaveService = saveService;
protected readonly Configuration Config = config;
protected readonly SaveService SaveService = saveService;
protected readonly Configuration Config = config;
/// <summary> Add a new, empty option group of the given type and name. </summary>
public TGroup? AddModGroup(Mod mod, string newName, SaveType saveType = SaveType.ImmediateSync)
@ -25,7 +25,7 @@ public abstract class ModOptionEditor<TGroup, TOption>(
return null;
var maxPriority = mod.Groups.Count == 0 ? ModPriority.Default : mod.Groups.Max(o => o.Priority) + 1;
var group = CreateGroup(mod, newName, maxPriority);
var group = CreateGroup(mod, newName, maxPriority);
mod.Groups.Add(group);
SaveService.Save(saveType, new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupAdded, mod, group, null, null, -1);
@ -92,8 +92,8 @@ public abstract class ModOptionEditor<TGroup, TOption>(
/// <summary> Delete the given option from the given group. </summary>
public void DeleteOption(TOption option)
{
var mod = option.Mod;
var group = option.Group;
var mod = option.Mod;
var group = option.Group;
var optionIdx = option.GetIndex();
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, group, option, null, -1);
RemoveOption((TGroup)group, optionIdx);
@ -104,7 +104,7 @@ public abstract class ModOptionEditor<TGroup, TOption>(
/// <summary> Move an option inside the given option group. </summary>
public void MoveOption(TOption option, int optionIdxTo)
{
var idx = option.GetIndex();
var idx = option.GetIndex();
var group = (TGroup)option.Group;
if (!MoveOption(group, idx, optionIdxTo))
return;
@ -113,10 +113,10 @@ public abstract class ModOptionEditor<TGroup, TOption>(
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMoved, group.Mod, group, option, null, idx);
}
protected abstract TGroup CreateGroup(Mod mod, string newName, ModPriority priority, SaveType saveType = SaveType.ImmediateSync);
protected abstract TGroup CreateGroup(Mod mod, string newName, ModPriority priority, SaveType saveType = SaveType.ImmediateSync);
protected abstract TOption? CloneOption(TGroup group, IModOption option);
protected abstract void RemoveOption(TGroup group, int optionIndex);
protected abstract bool MoveOption(TGroup group, int optionIdxFrom, int optionIdxTo);
protected abstract void RemoveOption(TGroup group, int optionIndex);
protected abstract bool MoveOption(TGroup group, int optionIdxFrom, int optionIdxTo);
}
public static class ModOptionChangeTypeExtension
@ -132,22 +132,22 @@ public static class ModOptionChangeTypeExtension
{
(requiresSaving, requiresReloading, wasPrepared) = type switch
{
ModOptionChangeType.GroupRenamed => (true, false, false),
ModOptionChangeType.GroupAdded => (true, false, false),
ModOptionChangeType.GroupDeleted => (true, true, false),
ModOptionChangeType.GroupMoved => (true, false, false),
ModOptionChangeType.GroupTypeChanged => (true, true, true),
ModOptionChangeType.PriorityChanged => (true, true, true),
ModOptionChangeType.OptionAdded => (true, true, true),
ModOptionChangeType.OptionDeleted => (true, true, false),
ModOptionChangeType.OptionMoved => (true, false, false),
ModOptionChangeType.OptionFilesChanged => (false, true, false),
ModOptionChangeType.OptionFilesAdded => (false, true, true),
ModOptionChangeType.OptionSwapsChanged => (false, true, false),
ModOptionChangeType.OptionMetaChanged => (false, true, false),
ModOptionChangeType.DisplayChange => (false, false, false),
ModOptionChangeType.GroupRenamed => (true, false, false),
ModOptionChangeType.GroupAdded => (true, false, false),
ModOptionChangeType.GroupDeleted => (true, true, false),
ModOptionChangeType.GroupMoved => (true, false, false),
ModOptionChangeType.GroupTypeChanged => (true, true, true),
ModOptionChangeType.PriorityChanged => (true, true, true),
ModOptionChangeType.OptionAdded => (true, true, true),
ModOptionChangeType.OptionDeleted => (true, true, false),
ModOptionChangeType.OptionMoved => (true, false, false),
ModOptionChangeType.OptionFilesChanged => (false, true, false),
ModOptionChangeType.OptionFilesAdded => (false, true, true),
ModOptionChangeType.OptionSwapsChanged => (false, true, false),
ModOptionChangeType.OptionMetaChanged => (false, true, false),
ModOptionChangeType.DisplayChange => (false, false, false),
ModOptionChangeType.DefaultOptionChanged => (true, false, false),
_ => (false, false, false),
_ => (false, false, false),
};
}
}