mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Now that was a lot of work.
This commit is contained in:
parent
297be487b5
commit
1e5ed1c414
44 changed files with 1182 additions and 766 deletions
|
|
@ -60,7 +60,7 @@ public class DuplicateManager(ModManager modManager, SaveService saveService, Co
|
|||
|
||||
private void HandleDuplicate(Mod mod, FullPath duplicate, FullPath remaining, bool useModManager)
|
||||
{
|
||||
ModEditor.ApplyToAllOptions(mod, HandleSubMod);
|
||||
ModEditor.ApplyToAllContainers(mod, HandleSubMod);
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -73,7 +73,7 @@ public class DuplicateManager(ModManager modManager, SaveService saveService, Co
|
|||
|
||||
return;
|
||||
|
||||
void HandleSubMod(IModDataContainer subMod, int groupIdx, int optionIdx)
|
||||
void HandleSubMod(IModDataContainer subMod)
|
||||
{
|
||||
var changes = false;
|
||||
var dict = subMod.Files.ToDictionary(kvp => kvp.Key,
|
||||
|
|
@ -82,14 +82,9 @@ public class DuplicateManager(ModManager modManager, SaveService saveService, Co
|
|||
return;
|
||||
|
||||
if (useModManager)
|
||||
{
|
||||
modManager.OptionEditor.OptionSetFiles(mod, groupIdx, optionIdx, dict, SaveType.ImmediateSync);
|
||||
}
|
||||
modManager.OptionEditor.SetFiles(subMod, dict, SaveType.ImmediateSync);
|
||||
else
|
||||
{
|
||||
subMod.Files = dict;
|
||||
saveService.ImmediateSaveSync(new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
|
||||
}
|
||||
saveService.ImmediateSaveSync(new ModSaveGroup(mod.ModPath, subMod, config.ReplaceNonAsciiOnImport));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ public class ModEditor(
|
|||
public int GroupIdx { get; private set; }
|
||||
public int DataIdx { get; private set; }
|
||||
|
||||
public IModGroup? Group { get; private set; }
|
||||
public IModDataContainer? 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);
|
||||
|
|
@ -63,10 +63,10 @@ public class ModEditor(
|
|||
{
|
||||
if (groupIdx == -1 && dataIdx == 0)
|
||||
{
|
||||
Group = null;
|
||||
Option = Mod.Default;
|
||||
GroupIdx = groupIdx;
|
||||
DataIdx = dataIdx;
|
||||
Group = null;
|
||||
Option = Mod.Default;
|
||||
GroupIdx = groupIdx;
|
||||
DataIdx = dataIdx;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -75,18 +75,18 @@ public class ModEditor(
|
|||
Group = Mod.Groups[groupIdx];
|
||||
if (dataIdx >= 0 && dataIdx < Group.DataContainers.Count)
|
||||
{
|
||||
Option = Group.DataContainers[dataIdx];
|
||||
GroupIdx = groupIdx;
|
||||
DataIdx = dataIdx;
|
||||
Option = Group.DataContainers[dataIdx];
|
||||
GroupIdx = groupIdx;
|
||||
DataIdx = dataIdx;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Group = null;
|
||||
Option = Mod?.Default;
|
||||
GroupIdx = -1;
|
||||
DataIdx = 0;
|
||||
Group = null;
|
||||
Option = Mod?.Default;
|
||||
GroupIdx = -1;
|
||||
DataIdx = 0;
|
||||
if (message)
|
||||
Penumbra.Log.Error($"Loading invalid option {groupIdx} {dataIdx} for Mod {Mod?.Name ?? "Unknown"}.");
|
||||
}
|
||||
|
|
@ -105,23 +105,11 @@ 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<IModDataContainer, int, int> action)
|
||||
public static void ApplyToAllContainers(Mod mod, Action<IModDataContainer> action)
|
||||
{
|
||||
action(mod.Default, -1, 0);
|
||||
foreach (var (group, groupIdx) in mod.Groups.WithIndex())
|
||||
{
|
||||
switch (group)
|
||||
{
|
||||
case SingleModGroup single:
|
||||
for (var optionIdx = 0; optionIdx < single.OptionData.Count; ++optionIdx)
|
||||
action(single.OptionData[optionIdx], groupIdx, optionIdx);
|
||||
break;
|
||||
case MultiModGroup multi:
|
||||
for (var optionIdx = 0; optionIdx < multi.OptionData.Count; ++optionIdx)
|
||||
action(multi.OptionData[optionIdx], groupIdx, optionIdx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
action(mod.Default);
|
||||
foreach (var container in mod.Groups.SelectMany(g => g.DataContainers))
|
||||
action(container);
|
||||
}
|
||||
|
||||
// Does not delete the base directory itself even if it is completely empty at the end.
|
||||
|
|
|
|||
|
|
@ -24,8 +24,7 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
|
|||
num += dict.TryAdd(path.Item2, file.File) ? 0 : 1;
|
||||
}
|
||||
|
||||
var (groupIdx, dataIdx) = option.GetDataIndices();
|
||||
modManager.OptionEditor.OptionSetFiles(mod, groupIdx, dataIdx, dict);
|
||||
modManager.OptionEditor.SetFiles(option, dict);
|
||||
files.UpdatePaths(mod, option);
|
||||
Changes = false;
|
||||
return num;
|
||||
|
|
@ -40,15 +39,15 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
|
|||
/// <summary> Remove all path redirections where the pointed-to file does not exist. </summary>
|
||||
public void RemoveMissingPaths(Mod mod, IModDataContainer option)
|
||||
{
|
||||
void HandleSubMod(IModDataContainer subMod, int groupIdx, int optionIdx)
|
||||
void HandleSubMod(IModDataContainer subMod)
|
||||
{
|
||||
var newDict = subMod.Files.Where(kvp => CheckAgainstMissing(mod, subMod, kvp.Value, kvp.Key, subMod == option))
|
||||
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
if (newDict.Count != subMod.Files.Count)
|
||||
modManager.OptionEditor.OptionSetFiles(mod, groupIdx, optionIdx, newDict);
|
||||
modManager.OptionEditor.SetFiles(subMod, newDict);
|
||||
}
|
||||
|
||||
ModEditor.ApplyToAllOptions(mod, HandleSubMod);
|
||||
ModEditor.ApplyToAllContainers(mod, HandleSubMod);
|
||||
files.ClearMissingFiles();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public class ModMerger : IDisposable
|
|||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly ModOptionEditor _editor;
|
||||
private readonly ModGroupEditor _editor;
|
||||
private readonly ModFileSystemSelector _selector;
|
||||
private readonly DuplicateManager _duplicates;
|
||||
private readonly ModManager _mods;
|
||||
|
|
@ -32,14 +32,14 @@ public class ModMerger : IDisposable
|
|||
private readonly Dictionary<string, string> _fileToFile = [];
|
||||
private readonly HashSet<string> _createdDirectories = [];
|
||||
private readonly HashSet<int> _createdGroups = [];
|
||||
private readonly HashSet<IModDataOption> _createdOptions = [];
|
||||
private readonly HashSet<IModOption> _createdOptions = [];
|
||||
|
||||
public readonly HashSet<IModDataContainer> SelectedOptions = [];
|
||||
|
||||
public readonly IReadOnlyList<string> Warnings = [];
|
||||
public Exception? Error { get; private set; }
|
||||
|
||||
public ModMerger(ModManager mods, ModOptionEditor editor, ModFileSystemSelector selector, DuplicateManager duplicates,
|
||||
public ModMerger(ModManager mods, ModGroupEditor editor, ModFileSystemSelector selector, DuplicateManager duplicates,
|
||||
CommunicatorService communicator, ModCreator creator, Configuration config)
|
||||
{
|
||||
_editor = editor;
|
||||
|
|
@ -100,22 +100,23 @@ public class ModMerger : IDisposable
|
|||
var (group, groupIdx, groupCreated) = _editor.FindOrAddModGroup(MergeToMod!, originalGroup.Type, originalGroup.Name);
|
||||
if (groupCreated)
|
||||
_createdGroups.Add(groupIdx);
|
||||
if (group.Type != originalGroup.Type)
|
||||
((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}.");
|
||||
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 group.DataContainers)
|
||||
{
|
||||
var (option, _, optionCreated) = _editor.FindOrAddOption(MergeToMod!, groupIdx, originalOption.GetName());
|
||||
var (option, _, optionCreated) = _editor.FindOrAddOption(group, originalOption.GetName());
|
||||
if (optionCreated)
|
||||
{
|
||||
_createdOptions.Add((IModDataOption)option);
|
||||
MergeIntoOption([originalOption], (IModDataOption)option, false);
|
||||
_createdOptions.Add(option!);
|
||||
// #TODO DataContainer <> Option.
|
||||
MergeIntoOption([originalOption], (IModDataContainer)option!, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(
|
||||
$"Could not merge {MergeFromMod!.Name} into {MergeToMod!.Name}: The option {option.FullName} already existed.");
|
||||
$"Could not merge {MergeFromMod!.Name} into {MergeToMod!.Name}: The option {option!.FullName} already existed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -138,9 +139,9 @@ public class ModMerger : IDisposable
|
|||
var (group, groupIdx, groupCreated) = _editor.FindOrAddModGroup(MergeToMod!, GroupType.Multi, groupName, SaveType.None);
|
||||
if (groupCreated)
|
||||
_createdGroups.Add(groupIdx);
|
||||
var (option, _, optionCreated) = _editor.FindOrAddOption(MergeToMod!, groupIdx, optionName, SaveType.None);
|
||||
var (option, _, optionCreated) = _editor.FindOrAddOption(group!, optionName, SaveType.None);
|
||||
if (optionCreated)
|
||||
_createdOptions.Add((IModDataOption)option);
|
||||
_createdOptions.Add(option!);
|
||||
var dir = ModCreator.NewOptionDirectory(MergeToMod!.ModPath, groupName, _config.ReplaceNonAsciiOnImport);
|
||||
if (!dir.Exists)
|
||||
_createdDirectories.Add(dir.FullName);
|
||||
|
|
@ -148,7 +149,8 @@ public class ModMerger : IDisposable
|
|||
if (!dir.Exists)
|
||||
_createdDirectories.Add(dir.FullName);
|
||||
CopyFiles(dir);
|
||||
MergeIntoOption(MergeFromMod!.AllDataContainers.Reverse(), (IModDataOption)option, true);
|
||||
// #TODO DataContainer <> Option.
|
||||
MergeIntoOption(MergeFromMod!.AllDataContainers.Reverse(), (IModDataContainer)option!, true);
|
||||
}
|
||||
|
||||
private void MergeIntoOption(IEnumerable<IModDataContainer> mergeOptions, IModDataContainer option, bool fromFileToFile)
|
||||
|
|
@ -184,10 +186,9 @@ public class ModMerger : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
_editor.SetFiles(option, redirections, SaveType.None);
|
||||
_editor.SetFileSwaps(option, swaps, SaveType.None);
|
||||
_editor.SetManipulations(option, manips, SaveType.ImmediateSync);
|
||||
return;
|
||||
|
||||
bool GetFullPath(FullPath input, out FullPath ret)
|
||||
|
|
@ -261,30 +262,31 @@ public class ModMerger : IDisposable
|
|||
if (mods.Count == 1)
|
||||
{
|
||||
var files = CopySubModFiles(mods[0], dir);
|
||||
_editor.OptionSetFiles(result, -1, 0, files);
|
||||
_editor.OptionSetFileSwaps(result, -1, 0, mods[0].FileSwaps);
|
||||
_editor.OptionSetManipulations(result, -1, 0, mods[0].Manipulations);
|
||||
_editor.SetFiles(result.Default, files);
|
||||
_editor.SetFileSwaps(result.Default, mods[0].FileSwaps);
|
||||
_editor.SetManipulations(result.Default, mods[0].Manipulations);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var originalOption in mods)
|
||||
{
|
||||
if (originalOption.Group is not {} originalGroup)
|
||||
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].FileSwaps);
|
||||
_editor.OptionSetManipulations(result, -1, 0, mods[0].Manipulations);
|
||||
_editor.SetFiles(result.Default, files);
|
||||
_editor.SetFileSwaps(result.Default, mods[0].FileSwaps);
|
||||
_editor.SetManipulations(result.Default, mods[0].Manipulations);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
// TODO DataContainer <> Option.
|
||||
var (group, _, _) = _editor.FindOrAddModGroup(result, originalGroup.Type, originalGroup.Name);
|
||||
var (option, _, _) = _editor.FindOrAddOption(group!, 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.FileSwaps);
|
||||
_editor.OptionSetManipulations(result, groupIdx, optionIdx, originalOption.Manipulations);
|
||||
_editor.SetFiles((IModDataContainer)option, files);
|
||||
_editor.SetFileSwaps((IModDataContainer)option, originalOption.FileSwaps);
|
||||
_editor.SetManipulations((IModDataContainer)option, originalOption.Manipulations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -339,16 +341,15 @@ public class ModMerger : IDisposable
|
|||
{
|
||||
foreach (var option in _createdOptions)
|
||||
{
|
||||
var (groupIdx, optionIdx) = option.GetOptionIndices();
|
||||
_editor.DeleteOption(MergeToMod!, groupIdx, optionIdx);
|
||||
_editor.DeleteOption(option);
|
||||
Penumbra.Log.Verbose($"[Merger] Removed option {option.FullName}.");
|
||||
}
|
||||
|
||||
foreach (var group in _createdGroups)
|
||||
{
|
||||
var groupName = MergeToMod!.Groups[group];
|
||||
_editor.DeleteModGroup(MergeToMod!, group);
|
||||
Penumbra.Log.Verbose($"[Merger] Removed option group {groupName}.");
|
||||
_editor.DeleteModGroup(groupName);
|
||||
Penumbra.Log.Verbose($"[Merger] Removed option group {groupName.Name}.");
|
||||
}
|
||||
|
||||
foreach (var dir in _createdDirectories)
|
||||
|
|
|
|||
|
|
@ -145,12 +145,12 @@ public class ModMetaEditor(ModManager modManager)
|
|||
Split(currentOption.Manipulations);
|
||||
}
|
||||
|
||||
public void Apply(Mod mod, int groupIdx, int optionIdx)
|
||||
public void Apply(IModDataContainer container)
|
||||
{
|
||||
if (!Changes)
|
||||
return;
|
||||
|
||||
modManager.OptionEditor.OptionSetManipulations(mod, groupIdx, optionIdx, Recombine().ToHashSet());
|
||||
modManager.OptionEditor.SetManipulations(container, Recombine().ToHashSet());
|
||||
Changes = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -283,12 +283,12 @@ public class ModNormalizer(ModManager _modManager, Configuration _config)
|
|||
switch (group)
|
||||
{
|
||||
case SingleModGroup single:
|
||||
foreach (var (_, optionIdx) in single.OptionData.WithIndex())
|
||||
_modManager.OptionEditor.OptionSetFiles(Mod, groupIdx, optionIdx, _redirections[groupIdx + 1][optionIdx]);
|
||||
foreach (var (option, optionIdx) in single.OptionData.WithIndex())
|
||||
_modManager.OptionEditor.SetFiles(option, _redirections[groupIdx + 1][optionIdx]);
|
||||
break;
|
||||
case MultiModGroup multi:
|
||||
foreach (var (_, optionIdx) in multi.OptionData.WithIndex())
|
||||
_modManager.OptionEditor.OptionSetFiles(Mod, groupIdx, optionIdx, _redirections[groupIdx + 1][optionIdx]);
|
||||
foreach (var (option, optionIdx) in multi.OptionData.WithIndex())
|
||||
_modManager.OptionEditor.SetFiles(option, _redirections[groupIdx + 1][optionIdx]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ public class ModSwapEditor(ModManager modManager)
|
|||
Changes = false;
|
||||
}
|
||||
|
||||
public void Apply(Mod mod, int groupIdx, int optionIdx)
|
||||
public void Apply(IModDataContainer container)
|
||||
{
|
||||
if (!Changes)
|
||||
return;
|
||||
|
||||
modManager.OptionEditor.OptionSetFileSwaps(mod, groupIdx, optionIdx, _swaps);
|
||||
modManager.OptionEditor.SetFileSwaps(container, _swaps);
|
||||
Changes = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue