This sucks so hard...

This commit is contained in:
Ottermandias 2024-04-24 23:04:04 +02:00
parent 07afbfb229
commit 6b1743b776
33 changed files with 852 additions and 695 deletions

View file

@ -29,7 +29,7 @@ public class DuplicateManager(ModManager modManager, SaveService saveService, Co
Worker = Task.Run(() => CheckDuplicates(filesTmp, _cancellationTokenSource.Token), _cancellationTokenSource.Token);
}
public void DeleteDuplicates(ModFileCollection files, Mod mod, SubMod option, bool useModManager)
public void DeleteDuplicates(ModFileCollection files, Mod mod, IModDataContainer option, bool useModManager)
{
if (!Worker.IsCompleted || _duplicates.Count == 0)
return;
@ -72,7 +72,7 @@ public class DuplicateManager(ModManager modManager, SaveService saveService, Co
return;
void HandleSubMod(SubMod subMod, int groupIdx, int optionIdx)
void HandleSubMod(IModDataContainer subMod, int groupIdx, int optionIdx)
{
var changes = false;
var dict = subMod.Files.ToDictionary(kvp => kvp.Key,
@ -86,7 +86,7 @@ public class DuplicateManager(ModManager modManager, SaveService saveService, Co
}
else
{
subMod.FileData = dict;
subMod.Files = dict;
saveService.ImmediateSaveSync(new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
}
}

View file

@ -5,12 +5,12 @@ namespace Penumbra.Mods.Editor;
public class FileRegistry : IEquatable<FileRegistry>
{
public readonly List<(SubMod, Utf8GamePath)> SubModUsage = [];
public FullPath File { get; private init; }
public Utf8RelPath RelPath { get; private init; }
public long FileSize { get; private init; }
public int CurrentUsage;
public bool IsOnPlayer;
public readonly List<(IModDataContainer, Utf8GamePath)> SubModUsage = [];
public FullPath File { get; private init; }
public Utf8RelPath RelPath { get; private init; }
public long FileSize { get; private init; }
public int CurrentUsage;
public bool IsOnPlayer;
public static bool FromFile(DirectoryInfo modPath, FileInfo file, [NotNullWhen(true)] out FileRegistry? registry)
{

View file

@ -1,4 +1,3 @@
using System;
using OtterGui;
using OtterGui.Compression;
using Penumbra.Mods.Subclasses;
@ -25,20 +24,20 @@ public class ModEditor(
public readonly MdlMaterialEditor MdlMaterialEditor = mdlMaterialEditor;
public readonly FileCompactor Compactor = compactor;
public Mod? Mod { get; private set; }
public int GroupIdx { get; private set; }
public int OptionIdx { get; private set; }
public Mod? Mod { get; private set; }
public int GroupIdx { get; private set; }
public int DataIdx { get; private set; }
public IModGroup? Group { get; private set; }
public SubMod? Option { get; private set; }
public IModGroup? Group { get; private set; }
public IModDataContainer? Option { get; private set; }
public void LoadMod(Mod mod)
=> LoadMod(mod, -1, 0);
public void LoadMod(Mod mod, int groupIdx, int optionIdx)
public void LoadMod(Mod mod, int groupIdx, int dataIdx)
{
Mod = mod;
LoadOption(groupIdx, optionIdx, true);
LoadOption(groupIdx, dataIdx, true);
Files.UpdateAll(mod, Option!);
SwapEditor.Revert(Option!);
MetaEditor.Load(Mod!, Option!);
@ -46,9 +45,9 @@ public class ModEditor(
MdlMaterialEditor.ScanModels(Mod!);
}
public void LoadOption(int groupIdx, int optionIdx)
public void LoadOption(int groupIdx, int dataIdx)
{
LoadOption(groupIdx, optionIdx, true);
LoadOption(groupIdx, dataIdx, true);
SwapEditor.Revert(Option!);
Files.UpdatePaths(Mod!, Option!);
MetaEditor.Load(Mod!, Option!);
@ -57,44 +56,38 @@ public class ModEditor(
}
/// <summary> Load the correct option by indices for the currently loaded mod if possible, unload if not. </summary>
private void LoadOption(int groupIdx, int optionIdx, bool message)
private void LoadOption(int groupIdx, int dataIdx, bool message)
{
if (Mod != null && Mod.Groups.Count > groupIdx)
{
if (groupIdx == -1 && optionIdx == 0)
if (groupIdx == -1 && dataIdx == 0)
{
Group = null;
Option = Mod.Default;
GroupIdx = groupIdx;
OptionIdx = optionIdx;
Group = null;
Option = Mod.Default;
GroupIdx = groupIdx;
DataIdx = dataIdx;
return;
}
if (groupIdx >= 0)
{
Group = Mod.Groups[groupIdx];
switch(Group)
if (dataIdx >= 0 && dataIdx < Group.DataContainers.Count)
{
case SingleModGroup single when optionIdx >= 0 && optionIdx < single.OptionData.Count:
Option = single.OptionData[optionIdx];
GroupIdx = groupIdx;
OptionIdx = optionIdx;
return;
case MultiModGroup multi when optionIdx >= 0 && optionIdx < multi.PrioritizedOptions.Count:
Option = multi.PrioritizedOptions[optionIdx].Mod;
GroupIdx = groupIdx;
OptionIdx = optionIdx;
return;
Option = Group.DataContainers[dataIdx];
GroupIdx = groupIdx;
DataIdx = dataIdx;
return;
}
}
}
Group = null;
Option = Mod?.Default;
GroupIdx = -1;
OptionIdx = 0;
Group = null;
Option = Mod?.Default;
GroupIdx = -1;
DataIdx = 0;
if (message)
Penumbra.Log.Error($"Loading invalid option {groupIdx} {optionIdx} for Mod {Mod?.Name ?? "Unknown"}.");
Penumbra.Log.Error($"Loading invalid option {groupIdx} {dataIdx} for Mod {Mod?.Name ?? "Unknown"}.");
}
public void Clear()
@ -111,7 +104,7 @@ public class ModEditor(
=> Clear();
/// <summary> Apply a option action to all available option in a mod, including the default option. </summary>
public static void ApplyToAllOptions(Mod mod, Action<SubMod, int, int> action)
public static void ApplyToAllOptions(Mod mod, Action<IModDataContainer, int, int> action)
{
action(mod.Default, -1, 0);
foreach (var (group, groupIdx) in mod.Groups.WithIndex())
@ -123,8 +116,8 @@ public class ModEditor(
action(single.OptionData[optionIdx], groupIdx, optionIdx);
break;
case MultiModGroup multi:
for (var optionIdx = 0; optionIdx < multi.PrioritizedOptions.Count; ++optionIdx)
action(multi.PrioritizedOptions[optionIdx].Mod, groupIdx, optionIdx);
for (var optionIdx = 0; optionIdx < multi.OptionData.Count; ++optionIdx)
action(multi.OptionData[optionIdx], groupIdx, optionIdx);
break;
}
}

View file

@ -38,13 +38,13 @@ public class ModFileCollection : IDisposable
public bool Ready { get; private set; } = true;
public void UpdateAll(Mod mod, SubMod option)
public void UpdateAll(Mod mod, IModDataContainer option)
{
UpdateFiles(mod, new CancellationToken());
UpdatePaths(mod, option, false, new CancellationToken());
}
public void UpdatePaths(Mod mod, SubMod option)
public void UpdatePaths(Mod mod, IModDataContainer option)
=> UpdatePaths(mod, option, true, new CancellationToken());
public void Clear()
@ -59,7 +59,7 @@ public class ModFileCollection : IDisposable
public void ClearMissingFiles()
=> _missing.Clear();
public void RemoveUsedPath(SubMod option, FileRegistry? file, Utf8GamePath gamePath)
public void RemoveUsedPath(IModDataContainer option, FileRegistry? file, Utf8GamePath gamePath)
{
_usedPaths.Remove(gamePath);
if (file != null)
@ -69,10 +69,10 @@ public class ModFileCollection : IDisposable
}
}
public void RemoveUsedPath(SubMod option, FullPath file, Utf8GamePath gamePath)
public void RemoveUsedPath(IModDataContainer option, FullPath file, Utf8GamePath gamePath)
=> RemoveUsedPath(option, _available.FirstOrDefault(f => f.File.Equals(file)), gamePath);
public void AddUsedPath(SubMod option, FileRegistry? file, Utf8GamePath gamePath)
public void AddUsedPath(IModDataContainer option, FileRegistry? file, Utf8GamePath gamePath)
{
_usedPaths.Add(gamePath);
if (file == null)
@ -82,7 +82,7 @@ public class ModFileCollection : IDisposable
file.SubModUsage.Add((option, gamePath));
}
public void AddUsedPath(SubMod option, FullPath file, Utf8GamePath gamePath)
public void AddUsedPath(IModDataContainer option, FullPath file, Utf8GamePath gamePath)
=> AddUsedPath(option, _available.FirstOrDefault(f => f.File.Equals(file)), gamePath);
public void ChangeUsedPath(FileRegistry file, int pathIdx, Utf8GamePath gamePath)
@ -154,14 +154,14 @@ public class ModFileCollection : IDisposable
_usedPaths.Clear();
}
private void UpdatePaths(Mod mod, SubMod option, bool clearRegistries, CancellationToken tok)
private void UpdatePaths(Mod mod, IModDataContainer option, bool clearRegistries, CancellationToken tok)
{
tok.ThrowIfCancellationRequested();
ClearPaths(clearRegistries, tok);
tok.ThrowIfCancellationRequested();
foreach (var subMod in mod.AllSubMods)
foreach (var subMod in mod.AllDataContainers)
{
foreach (var (gamePath, file) in subMod.Files)
{

View file

@ -14,7 +14,7 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
Changes = false;
}
public int Apply(Mod mod, SubMod option)
public int Apply(Mod mod, IModDataContainer option)
{
var dict = new Dictionary<Utf8GamePath, FullPath>();
var num = 0;
@ -24,23 +24,23 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
num += dict.TryAdd(path.Item2, file.File) ? 0 : 1;
}
var (groupIdx, optionIdx) = option.GetIndices();
modManager.OptionEditor.OptionSetFiles(mod, groupIdx, optionIdx, dict);
var (groupIdx, dataIdx) = option.GetDataIndices();
modManager.OptionEditor.OptionSetFiles(mod, groupIdx, dataIdx, dict);
files.UpdatePaths(mod, option);
Changes = false;
return num;
}
public void Revert(Mod mod, SubMod option)
public void Revert(Mod mod, IModDataContainer option)
{
files.UpdateAll(mod, option);
Changes = false;
}
/// <summary> Remove all path redirections where the pointed-to file does not exist. </summary>
public void RemoveMissingPaths(Mod mod, SubMod option)
public void RemoveMissingPaths(Mod mod, IModDataContainer option)
{
void HandleSubMod(SubMod subMod, int groupIdx, int optionIdx)
void HandleSubMod(IModDataContainer subMod, int groupIdx, int optionIdx)
{
var newDict = subMod.Files.Where(kvp => CheckAgainstMissing(mod, subMod, kvp.Value, kvp.Key, subMod == option))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
@ -62,7 +62,7 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
/// If path is empty, it will be deleted instead.
/// If pathIdx is equal to the total number of paths, path will be added, otherwise replaced.
/// </summary>
public bool SetGamePath(SubMod option, int fileIdx, int pathIdx, Utf8GamePath path)
public bool SetGamePath(IModDataContainer option, int fileIdx, int pathIdx, Utf8GamePath path)
{
if (!CanAddGamePath(path) || fileIdx < 0 || fileIdx > files.Available.Count)
return false;
@ -85,7 +85,7 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
/// Transform a set of files to the appropriate game paths with the given number of folders skipped,
/// and add them to the given option.
/// </summary>
public int AddPathsToSelected(SubMod option, IEnumerable<FileRegistry> files1, int skipFolders = 0)
public int AddPathsToSelected(IModDataContainer option, IEnumerable<FileRegistry> files1, int skipFolders = 0)
{
var failed = 0;
foreach (var file in files1)
@ -112,7 +112,7 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
}
/// <summary> Remove all paths in the current option from the given files. </summary>
public void RemovePathsFromSelected(SubMod option, IEnumerable<FileRegistry> files1)
public void RemovePathsFromSelected(IModDataContainer option, IEnumerable<FileRegistry> files1)
{
foreach (var file in files1)
{
@ -130,7 +130,7 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
}
/// <summary> Delete all given files from your filesystem </summary>
public void DeleteFiles(Mod mod, SubMod option, IEnumerable<FileRegistry> files1)
public void DeleteFiles(Mod mod, IModDataContainer option, IEnumerable<FileRegistry> files1)
{
var deletions = 0;
foreach (var file in files1)
@ -156,7 +156,7 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
}
private bool CheckAgainstMissing(Mod mod, SubMod option, FullPath file, Utf8GamePath key, bool removeUsed)
private bool CheckAgainstMissing(Mod mod, IModDataContainer option, FullPath file, Utf8GamePath key, bool removeUsed)
{
if (!files.Missing.Contains(file))
return true;

View file

@ -1,6 +1,5 @@
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Utility;
using ImGuizmoNET;
using OtterGui;
using OtterGui.Classes;
using Penumbra.Api.Enums;
@ -33,9 +32,9 @@ public class ModMerger : IDisposable
private readonly Dictionary<string, string> _fileToFile = [];
private readonly HashSet<string> _createdDirectories = [];
private readonly HashSet<int> _createdGroups = [];
private readonly HashSet<SubMod> _createdOptions = [];
private readonly HashSet<IModDataOption> _createdOptions = [];
public readonly HashSet<SubMod> SelectedOptions = [];
public readonly HashSet<IModDataContainer> SelectedOptions = [];
public readonly IReadOnlyList<string> Warnings = [];
public Exception? Error { get; private set; }
@ -94,7 +93,7 @@ public class ModMerger : IDisposable
private void MergeWithOptions()
{
MergeIntoOption(Enumerable.Repeat(MergeFromMod!.Default, 1), MergeToMod!.Default, false);
MergeIntoOption([MergeFromMod!.Default], MergeToMod!.Default, false);
foreach (var originalGroup in MergeFromMod!.Groups)
{
@ -105,20 +104,13 @@ public class ModMerger : IDisposable
((List<string>)Warnings).Add(
$"The merged group {group.Name} already existed, but has a different type {group.Type} than the original group of type {originalGroup.Type}.");
var optionEnumerator = group switch
foreach (var originalOption in group.DataContainers)
{
SingleModGroup single => single.OptionData,
MultiModGroup multi => multi.PrioritizedOptions.Select(o => o.Mod),
_ => [],
};
foreach (var originalOption in optionEnumerator)
{
var (option, _, optionCreated) = _editor.FindOrAddOption(MergeToMod!, groupIdx, originalOption.Name);
var (option, _, optionCreated) = _editor.FindOrAddOption(MergeToMod!, groupIdx, originalOption.GetName());
if (optionCreated)
{
_createdOptions.Add(option);
MergeIntoOption(Enumerable.Repeat(originalOption, 1), option, false);
_createdOptions.Add((IModDataOption)option);
MergeIntoOption([originalOption], (IModDataOption)option, false);
}
else
{
@ -136,7 +128,7 @@ public class ModMerger : IDisposable
if (groupName.Length == 0 && optionName.Length == 0)
{
CopyFiles(MergeToMod!.ModPath);
MergeIntoOption(MergeFromMod!.AllSubMods.Reverse(), MergeToMod!.Default, true);
MergeIntoOption(MergeFromMod!.AllDataContainers.Reverse(), MergeToMod!.Default, true);
}
else if (groupName.Length * optionName.Length == 0)
{
@ -148,7 +140,7 @@ public class ModMerger : IDisposable
_createdGroups.Add(groupIdx);
var (option, _, optionCreated) = _editor.FindOrAddOption(MergeToMod!, groupIdx, optionName, SaveType.None);
if (optionCreated)
_createdOptions.Add(option);
_createdOptions.Add((IModDataOption)option);
var dir = ModCreator.NewOptionDirectory(MergeToMod!.ModPath, groupName, _config.ReplaceNonAsciiOnImport);
if (!dir.Exists)
_createdDirectories.Add(dir.FullName);
@ -156,14 +148,14 @@ public class ModMerger : IDisposable
if (!dir.Exists)
_createdDirectories.Add(dir.FullName);
CopyFiles(dir);
MergeIntoOption(MergeFromMod!.AllSubMods.Reverse(), option, true);
MergeIntoOption(MergeFromMod!.AllDataContainers.Reverse(), (IModDataOption)option, true);
}
private void MergeIntoOption(IEnumerable<SubMod> mergeOptions, SubMod option, bool fromFileToFile)
private void MergeIntoOption(IEnumerable<IModDataContainer> mergeOptions, IModDataContainer option, bool fromFileToFile)
{
var redirections = option.FileData.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
var swaps = option.FileSwapData.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
var manips = option.ManipulationData.ToHashSet();
var redirections = option.Files.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
var swaps = option.FileSwaps.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
var manips = option.Manipulations.ToHashSet();
foreach (var originalOption in mergeOptions)
{
@ -171,31 +163,31 @@ public class ModMerger : IDisposable
{
if (!manips.Add(manip))
throw new Exception(
$"Could not add meta manipulation {manip} from {originalOption.FullName} to {option.FullName} because another manipulation of the same data already exists in this option.");
$"Could not add meta manipulation {manip} from {originalOption.GetFullName()} to {option.GetFullName()} because another manipulation of the same data already exists in this option.");
}
foreach (var (swapA, swapB) in originalOption.FileSwaps)
{
if (!swaps.TryAdd(swapA, swapB))
throw new Exception(
$"Could not add file swap {swapB} -> {swapA} from {originalOption.FullName} to {option.FullName} because another swap of the key already exists.");
$"Could not add file swap {swapB} -> {swapA} from {originalOption.GetFullName()} to {option.GetFullName()} because another swap of the key already exists.");
}
foreach (var (gamePath, path) in originalOption.Files)
{
if (!GetFullPath(path, out var newFile))
throw new Exception(
$"Could not add file redirection {path} -> {gamePath} from {originalOption.FullName} to {option.FullName} because the file does not exist in the new mod.");
$"Could not add file redirection {path} -> {gamePath} from {originalOption.GetFullName()} to {option.GetFullName()} because the file does not exist in the new mod.");
if (!redirections.TryAdd(gamePath, newFile))
throw new Exception(
$"Could not add file redirection {path} -> {gamePath} from {originalOption.FullName} to {option.FullName} because a redirection for the game path already exists.");
$"Could not add file redirection {path} -> {gamePath} from {originalOption.GetFullName()} to {option.GetFullName()} because a redirection for the game path already exists.");
}
}
var (groupIdx, optionIdx) = option.GetIndices();
_editor.OptionSetFiles(MergeToMod!, groupIdx, optionIdx, redirections, SaveType.None);
_editor.OptionSetFileSwaps(MergeToMod!, groupIdx, optionIdx, swaps, SaveType.None);
_editor.OptionSetManipulations(MergeToMod!, groupIdx, optionIdx, manips, SaveType.ImmediateSync);
var (groupIdx, dataIdx) = option.GetDataIndices();
_editor.OptionSetFiles(MergeToMod!, groupIdx, dataIdx, redirections, SaveType.None);
_editor.OptionSetFileSwaps(MergeToMod!, groupIdx, dataIdx, swaps, SaveType.None);
_editor.OptionSetManipulations(MergeToMod!, groupIdx, dataIdx, manips, SaveType.ImmediateSync);
return;
bool GetFullPath(FullPath input, out FullPath ret)
@ -270,30 +262,29 @@ public class ModMerger : IDisposable
{
var files = CopySubModFiles(mods[0], dir);
_editor.OptionSetFiles(result, -1, 0, files);
_editor.OptionSetFileSwaps(result, -1, 0, mods[0].FileSwapData);
_editor.OptionSetManipulations(result, -1, 0, mods[0].ManipulationData);
_editor.OptionSetFileSwaps(result, -1, 0, mods[0].FileSwaps);
_editor.OptionSetManipulations(result, -1, 0, mods[0].Manipulations);
}
else
{
foreach (var originalOption in mods)
{
if (originalOption.IsDefault)
if (originalOption.Group is not {} originalGroup)
{
var files = CopySubModFiles(mods[0], dir);
_editor.OptionSetFiles(result, -1, 0, files);
_editor.OptionSetFileSwaps(result, -1, 0, mods[0].FileSwapData);
_editor.OptionSetManipulations(result, -1, 0, mods[0].ManipulationData);
_editor.OptionSetFileSwaps(result, -1, 0, mods[0].FileSwaps);
_editor.OptionSetManipulations(result, -1, 0, mods[0].Manipulations);
}
else
{
var originalGroup = originalOption.Group;
var (group, groupIdx, _) = _editor.FindOrAddModGroup(result, originalGroup.Type, originalGroup.Name);
var (option, optionIdx, _) = _editor.FindOrAddOption(result, groupIdx, originalOption.Name);
var (group, groupIdx, _) = _editor.FindOrAddModGroup(result, originalGroup.Type, originalGroup.Name);
var (option, optionIdx, _) = _editor.FindOrAddOption(result, groupIdx, originalOption.GetName());
var folder = Path.Combine(dir.FullName, group.Name, option.Name);
var files = CopySubModFiles(originalOption, new DirectoryInfo(folder));
_editor.OptionSetFiles(result, groupIdx, optionIdx, files);
_editor.OptionSetFileSwaps(result, groupIdx, optionIdx, originalOption.FileSwapData);
_editor.OptionSetManipulations(result, groupIdx, optionIdx, originalOption.ManipulationData);
_editor.OptionSetFileSwaps(result, groupIdx, optionIdx, originalOption.FileSwaps);
_editor.OptionSetManipulations(result, groupIdx, optionIdx, originalOption.Manipulations);
}
}
}
@ -315,11 +306,11 @@ public class ModMerger : IDisposable
}
}
private static Dictionary<Utf8GamePath, FullPath> CopySubModFiles(SubMod option, DirectoryInfo newMod)
private static Dictionary<Utf8GamePath, FullPath> CopySubModFiles(IModDataContainer option, DirectoryInfo newMod)
{
var ret = new Dictionary<Utf8GamePath, FullPath>(option.FileData.Count);
var ret = new Dictionary<Utf8GamePath, FullPath>(option.Files.Count);
var parentPath = ((Mod)option.Mod).ModPath.FullName;
foreach (var (path, file) in option.FileData)
foreach (var (path, file) in option.Files)
{
var target = Path.GetRelativePath(parentPath, file.FullName);
target = Path.Combine(newMod.FullName, target);
@ -348,7 +339,7 @@ public class ModMerger : IDisposable
{
foreach (var option in _createdOptions)
{
var (groupIdx, optionIdx) = option.GetIndices();
var (groupIdx, optionIdx) = option.GetOptionIndices();
_editor.DeleteOption(MergeToMod!, groupIdx, optionIdx);
Penumbra.Log.Verbose($"[Merger] Removed option {option.FullName}.");
}

View file

@ -103,7 +103,7 @@ public class ModMetaEditor(ModManager modManager)
Changes = true;
}
public void Load(Mod mod, SubMod currentOption)
public void Load(Mod mod, IModDataContainer currentOption)
{
OtherImcCount = 0;
OtherEqpCount = 0;
@ -111,7 +111,7 @@ public class ModMetaEditor(ModManager modManager)
OtherGmpCount = 0;
OtherEstCount = 0;
OtherRspCount = 0;
foreach (var option in mod.AllSubMods)
foreach (var option in mod.AllDataContainers)
{
if (option == currentOption)
continue;

View file

@ -1,3 +1,4 @@
using System;
using Dalamud.Interface.Internal.Notifications;
using OtterGui;
using OtterGui.Classes;
@ -168,27 +169,11 @@ public class ModNormalizer(ModManager _modManager, Configuration _config)
foreach (var (group, groupIdx) in Mod.Groups.WithIndex())
{
var groupDir = ModCreator.CreateModFolder(directory, group.Name, _config.ReplaceNonAsciiOnImport, true);
switch (group)
{
case SingleModGroup single:
_redirections[groupIdx + 1].EnsureCapacity(single.OptionData.Count);
for (var i = _redirections[groupIdx + 1].Count; i < single.OptionData.Count; ++i)
_redirections[groupIdx + 1].Add([]);
foreach (var (option, optionIdx) in single.OptionData.WithIndex())
HandleSubMod(groupDir, option, _redirections[groupIdx + 1][optionIdx]);
break;
case MultiModGroup multi:
_redirections[groupIdx + 1].EnsureCapacity(multi.PrioritizedOptions.Count);
for (var i = _redirections[groupIdx + 1].Count; i < multi.PrioritizedOptions.Count; ++i)
_redirections[groupIdx + 1].Add([]);
foreach (var ((option, _), optionIdx) in multi.PrioritizedOptions.WithIndex())
HandleSubMod(groupDir, option, _redirections[groupIdx + 1][optionIdx]);
break;
}
_redirections[groupIdx + 1].EnsureCapacity(group.DataContainers.Count);
for (var i = _redirections[groupIdx + 1].Count; i < group.DataContainers.Count; ++i)
_redirections[groupIdx + 1].Add([]);
foreach (var (data, dataIdx) in group.DataContainers.WithIndex())
HandleSubMod(groupDir, data, _redirections[groupIdx + 1][dataIdx]);
}
return true;
@ -200,13 +185,14 @@ public class ModNormalizer(ModManager _modManager, Configuration _config)
return false;
void HandleSubMod(DirectoryInfo groupDir, SubMod option, Dictionary<Utf8GamePath, FullPath> newDict)
void HandleSubMod(DirectoryInfo groupDir, IModDataContainer option, Dictionary<Utf8GamePath, FullPath> newDict)
{
var optionDir = ModCreator.CreateModFolder(groupDir, option.Name, _config.ReplaceNonAsciiOnImport, true);
var name = option.GetName();
var optionDir = ModCreator.CreateModFolder(groupDir, name, _config.ReplaceNonAsciiOnImport, true);
newDict.Clear();
newDict.EnsureCapacity(option.FileData.Count);
foreach (var (gamePath, fullPath) in option.FileData)
newDict.EnsureCapacity(option.Files.Count);
foreach (var (gamePath, fullPath) in option.Files)
{
var relPath = new Utf8RelPath(gamePath).ToString();
var newFullPath = Path.Combine(optionDir.FullName, relPath);
@ -300,7 +286,7 @@ public class ModNormalizer(ModManager _modManager, Configuration _config)
_modManager.OptionEditor.OptionSetFiles(Mod, groupIdx, optionIdx, _redirections[groupIdx + 1][optionIdx]);
break;
case MultiModGroup multi:
foreach (var (_, optionIdx) in multi.PrioritizedOptions.WithIndex())
foreach (var (_, optionIdx) in multi.OptionData.WithIndex())
_modManager.OptionEditor.OptionSetFiles(Mod, groupIdx, optionIdx, _redirections[groupIdx + 1][optionIdx]);
break;
}

View file

@ -11,7 +11,7 @@ public class ModSwapEditor(ModManager modManager)
public IReadOnlyDictionary<Utf8GamePath, FullPath> Swaps
=> _swaps;
public void Revert(SubMod option)
public void Revert(IModDataContainer option)
{
_swaps.SetTo(option.FileSwaps);
Changes = false;