mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-15 21:24:18 +01:00
Fix issue with merging and deduplicating.
This commit is contained in:
parent
5cebddb0ab
commit
a65009dfb0
5 changed files with 59 additions and 50 deletions
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
||||||
Subproject commit f641a34ffa80e89bd61701f60f15d15c4c5b361e
|
Subproject commit f48c6886cbc163c5a292fa8b9fd919cb01c11d7b
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using OtterGui.Classes;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
using Penumbra.Mods.Subclasses;
|
using Penumbra.Mods.Subclasses;
|
||||||
using Penumbra.Services;
|
using Penumbra.Services;
|
||||||
|
|
@ -81,7 +82,7 @@ public class DuplicateManager(ModManager modManager, SaveService saveService, Co
|
||||||
|
|
||||||
if (useModManager)
|
if (useModManager)
|
||||||
{
|
{
|
||||||
modManager.OptionEditor.OptionSetFiles(mod, groupIdx, optionIdx, dict);
|
modManager.OptionEditor.OptionSetFiles(mod, groupIdx, optionIdx, dict, SaveType.ImmediateSync);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -216,18 +217,21 @@ public class DuplicateManager(ModManager modManager, SaveService saveService, Co
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Deduplicate a mod simply by its directory without any confirmation or waiting time. </summary>
|
/// <summary> Deduplicate a mod simply by its directory without any confirmation or waiting time. </summary>
|
||||||
internal void DeduplicateMod(DirectoryInfo modDirectory)
|
internal void DeduplicateMod(DirectoryInfo modDirectory, bool useModManager = false)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var mod = new Mod(modDirectory);
|
if (!useModManager || !modManager.TryGetMod(modDirectory.Name, string.Empty, out var mod))
|
||||||
modManager.Creator.ReloadMod(mod, true, out _);
|
{
|
||||||
|
mod = new Mod(modDirectory);
|
||||||
|
modManager.Creator.ReloadMod(mod, true, out _);
|
||||||
|
}
|
||||||
|
|
||||||
Clear();
|
Clear();
|
||||||
var files = new ModFileCollection();
|
var files = new ModFileCollection();
|
||||||
files.UpdateAll(mod, mod.Default);
|
files.UpdateAll(mod, mod.Default);
|
||||||
CheckDuplicates(files.Available.OrderByDescending(f => f.FileSize).ToArray(), CancellationToken.None);
|
CheckDuplicates([.. files.Available.OrderByDescending(f => f.FileSize)], CancellationToken.None);
|
||||||
DeleteDuplicates(files, mod, mod.Default, false);
|
DeleteDuplicates(files, mod, mod.Default, useModManager);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ public class ModMerger : IDisposable
|
||||||
|
|
||||||
public readonly HashSet<SubMod> SelectedOptions = [];
|
public readonly HashSet<SubMod> SelectedOptions = [];
|
||||||
|
|
||||||
public readonly IReadOnlyList<string> Warnings = new List<string>();
|
public readonly IReadOnlyList<string> Warnings = [];
|
||||||
public Exception? Error { get; private set; }
|
public Exception? Error { get; private set; }
|
||||||
|
|
||||||
public ModMerger(ModManager mods, ModOptionEditor editor, ModFileSystemSelector selector, DuplicateManager duplicates,
|
public ModMerger(ModManager mods, ModOptionEditor editor, ModFileSystemSelector selector, DuplicateManager duplicates,
|
||||||
|
|
@ -78,7 +78,8 @@ public class ModMerger : IDisposable
|
||||||
MergeWithOptions();
|
MergeWithOptions();
|
||||||
else
|
else
|
||||||
MergeIntoOption(OptionGroupName, OptionName);
|
MergeIntoOption(OptionGroupName, OptionName);
|
||||||
_duplicates.DeduplicateMod(MergeToMod.ModPath);
|
|
||||||
|
_duplicates.DeduplicateMod(MergeToMod.ModPath, true);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -134,10 +135,10 @@ public class ModMerger : IDisposable
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var (group, groupIdx, groupCreated) = _editor.FindOrAddModGroup(MergeToMod!, GroupType.Multi, groupName);
|
var (group, groupIdx, groupCreated) = _editor.FindOrAddModGroup(MergeToMod!, GroupType.Multi, groupName, SaveType.None);
|
||||||
if (groupCreated)
|
if (groupCreated)
|
||||||
_createdGroups.Add(groupIdx);
|
_createdGroups.Add(groupIdx);
|
||||||
var (option, optionCreated) = _editor.FindOrAddOption(MergeToMod!, groupIdx, optionName);
|
var (option, optionCreated) = _editor.FindOrAddOption(MergeToMod!, groupIdx, optionName, SaveType.None);
|
||||||
if (optionCreated)
|
if (optionCreated)
|
||||||
_createdOptions.Add(option);
|
_createdOptions.Add(option);
|
||||||
var dir = ModCreator.NewOptionDirectory(MergeToMod!.ModPath, groupName, _config.ReplaceNonAsciiOnImport);
|
var dir = ModCreator.NewOptionDirectory(MergeToMod!.ModPath, groupName, _config.ReplaceNonAsciiOnImport);
|
||||||
|
|
@ -156,27 +157,6 @@ public class ModMerger : IDisposable
|
||||||
var swaps = option.FileSwapData.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
var swaps = option.FileSwapData.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||||
var manips = option.ManipulationData.ToHashSet();
|
var manips = option.ManipulationData.ToHashSet();
|
||||||
|
|
||||||
bool GetFullPath(FullPath input, out FullPath ret)
|
|
||||||
{
|
|
||||||
if (fromFileToFile)
|
|
||||||
{
|
|
||||||
if (!_fileToFile.TryGetValue(input.FullName, out var s))
|
|
||||||
{
|
|
||||||
ret = input;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = new FullPath(s);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Utf8RelPath.FromFile(input, MergeFromMod!.ModPath, out var relPath))
|
|
||||||
throw new Exception($"Could not create relative path from {input} and {MergeFromMod!.ModPath}.");
|
|
||||||
|
|
||||||
ret = new FullPath(MergeToMod!.ModPath, relPath);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var originalOption in mergeOptions)
|
foreach (var originalOption in mergeOptions)
|
||||||
{
|
{
|
||||||
foreach (var manip in originalOption.Manipulations)
|
foreach (var manip in originalOption.Manipulations)
|
||||||
|
|
@ -204,9 +184,31 @@ public class ModMerger : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_editor.OptionSetFiles(MergeToMod!, option.GroupIdx, option.OptionIdx, redirections);
|
_editor.OptionSetFiles(MergeToMod!, option.GroupIdx, option.OptionIdx, redirections, SaveType.None);
|
||||||
_editor.OptionSetFileSwaps(MergeToMod!, option.GroupIdx, option.OptionIdx, swaps);
|
_editor.OptionSetFileSwaps(MergeToMod!, option.GroupIdx, option.OptionIdx, swaps, SaveType.None);
|
||||||
_editor.OptionSetManipulations(MergeToMod!, option.GroupIdx, option.OptionIdx, manips);
|
_editor.OptionSetManipulations(MergeToMod!, option.GroupIdx, option.OptionIdx, manips, SaveType.ImmediateSync);
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool GetFullPath(FullPath input, out FullPath ret)
|
||||||
|
{
|
||||||
|
if (fromFileToFile)
|
||||||
|
{
|
||||||
|
if (!_fileToFile.TryGetValue(input.FullName, out var s))
|
||||||
|
{
|
||||||
|
ret = input;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = new FullPath(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Utf8RelPath.FromFile(input, MergeFromMod!.ModPath, out var relPath))
|
||||||
|
throw new Exception($"Could not create relative path from {input} and {MergeFromMod!.ModPath}.");
|
||||||
|
|
||||||
|
ret = new FullPath(MergeToMod!.ModPath, relPath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CopyFiles(DirectoryInfo directory)
|
private void CopyFiles(DirectoryInfo directory)
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Add a new, empty option group of the given type and name. </summary>
|
/// <summary> Add a new, empty option group of the given type and name. </summary>
|
||||||
public void AddModGroup(Mod mod, GroupType type, string newName)
|
public void AddModGroup(Mod mod, GroupType type, string newName, SaveType saveType = SaveType.ImmediateSync)
|
||||||
{
|
{
|
||||||
if (!VerifyFileName(mod, null, newName, true))
|
if (!VerifyFileName(mod, null, newName, true))
|
||||||
return;
|
return;
|
||||||
|
|
@ -96,18 +96,18 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
|
||||||
Name = newName,
|
Name = newName,
|
||||||
Priority = maxPriority,
|
Priority = maxPriority,
|
||||||
});
|
});
|
||||||
saveService.ImmediateSave(new ModSaveGroup(mod, mod.Groups.Count - 1, config.ReplaceNonAsciiOnImport));
|
saveService.Save(saveType, new ModSaveGroup(mod, mod.Groups.Count - 1, config.ReplaceNonAsciiOnImport));
|
||||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupAdded, mod, mod.Groups.Count - 1, -1, -1);
|
communicator.ModOptionChanged.Invoke(ModOptionChangeType.GroupAdded, mod, mod.Groups.Count - 1, -1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Add a new mod, empty option group of the given type and name if it does not exist already. </summary>
|
/// <summary> Add a new mod, empty option group of the given type and name if it does not exist already. </summary>
|
||||||
public (IModGroup, int, bool) FindOrAddModGroup(Mod mod, GroupType type, string newName)
|
public (IModGroup, int, bool) FindOrAddModGroup(Mod mod, GroupType type, string newName, SaveType saveType = SaveType.ImmediateSync)
|
||||||
{
|
{
|
||||||
var idx = mod.Groups.IndexOf(g => g.Name == newName);
|
var idx = mod.Groups.IndexOf(g => g.Name == newName);
|
||||||
if (idx >= 0)
|
if (idx >= 0)
|
||||||
return (mod.Groups[idx], idx, false);
|
return (mod.Groups[idx], idx, false);
|
||||||
|
|
||||||
AddModGroup(mod, type, newName);
|
AddModGroup(mod, type, newName, saveType);
|
||||||
if (mod.Groups[^1].Name != newName)
|
if (mod.Groups[^1].Name != newName)
|
||||||
throw new Exception($"Could not create new mod group with name {newName}.");
|
throw new Exception($"Could not create new mod group with name {newName}.");
|
||||||
|
|
||||||
|
|
@ -226,7 +226,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Add a new empty option of the given name for the given group. </summary>
|
/// <summary> Add a new empty option of the given name for the given group. </summary>
|
||||||
public void AddOption(Mod mod, int groupIdx, string newName)
|
public void AddOption(Mod mod, int groupIdx, string newName, SaveType saveType = SaveType.Queue)
|
||||||
{
|
{
|
||||||
var group = mod.Groups[groupIdx];
|
var group = mod.Groups[groupIdx];
|
||||||
var subMod = new SubMod(mod) { Name = newName };
|
var subMod = new SubMod(mod) { Name = newName };
|
||||||
|
|
@ -241,19 +241,19 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveService.QueueSave(new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
|
saveService.Save(saveType, new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
|
||||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionAdded, mod, groupIdx, group.Count - 1, -1);
|
communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionAdded, mod, groupIdx, group.Count - 1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Add a new empty option of the given name for the given group if it does not exist already. </summary>
|
/// <summary> Add a new empty option of the given name for the given group if it does not exist already. </summary>
|
||||||
public (SubMod, bool) FindOrAddOption(Mod mod, int groupIdx, string newName)
|
public (SubMod, bool) FindOrAddOption(Mod mod, int groupIdx, string newName, SaveType saveType = SaveType.Queue)
|
||||||
{
|
{
|
||||||
var group = mod.Groups[groupIdx];
|
var group = mod.Groups[groupIdx];
|
||||||
var idx = group.IndexOf(o => o.Name == newName);
|
var idx = group.IndexOf(o => o.Name == newName);
|
||||||
if (idx >= 0)
|
if (idx >= 0)
|
||||||
return ((SubMod)group[idx], false);
|
return ((SubMod)group[idx], false);
|
||||||
|
|
||||||
AddOption(mod, groupIdx, newName);
|
AddOption(mod, groupIdx, newName, saveType);
|
||||||
if (group[^1].Name != newName)
|
if (group[^1].Name != newName)
|
||||||
throw new Exception($"Could not create new option with name {newName} in {group.Name}.");
|
throw new Exception($"Could not create new option with name {newName} in {group.Name}.");
|
||||||
|
|
||||||
|
|
@ -324,7 +324,8 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Set the meta manipulations for a given option. Replaces existing manipulations. </summary>
|
/// <summary> Set the meta manipulations for a given option. Replaces existing manipulations. </summary>
|
||||||
public void OptionSetManipulations(Mod mod, int groupIdx, int optionIdx, HashSet<MetaManipulation> manipulations)
|
public void OptionSetManipulations(Mod mod, int groupIdx, int optionIdx, HashSet<MetaManipulation> manipulations,
|
||||||
|
SaveType saveType = SaveType.Queue)
|
||||||
{
|
{
|
||||||
var subMod = GetSubMod(mod, groupIdx, optionIdx);
|
var subMod = GetSubMod(mod, groupIdx, optionIdx);
|
||||||
if (subMod.Manipulations.Count == manipulations.Count
|
if (subMod.Manipulations.Count == manipulations.Count
|
||||||
|
|
@ -333,12 +334,13 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
|
||||||
|
|
||||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, groupIdx, optionIdx, -1);
|
communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, groupIdx, optionIdx, -1);
|
||||||
subMod.ManipulationData.SetTo(manipulations);
|
subMod.ManipulationData.SetTo(manipulations);
|
||||||
saveService.QueueSave(new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
|
saveService.Save(saveType, new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
|
||||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMetaChanged, mod, groupIdx, optionIdx, -1);
|
communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMetaChanged, mod, groupIdx, optionIdx, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Set the file redirections for a given option. Replaces existing redirections. </summary>
|
/// <summary> Set the file redirections for a given option. Replaces existing redirections. </summary>
|
||||||
public void OptionSetFiles(Mod mod, int groupIdx, int optionIdx, IReadOnlyDictionary<Utf8GamePath, FullPath> replacements)
|
public void OptionSetFiles(Mod mod, int groupIdx, int optionIdx, IReadOnlyDictionary<Utf8GamePath, FullPath> replacements,
|
||||||
|
SaveType saveType = SaveType.Queue)
|
||||||
{
|
{
|
||||||
var subMod = GetSubMod(mod, groupIdx, optionIdx);
|
var subMod = GetSubMod(mod, groupIdx, optionIdx);
|
||||||
if (subMod.FileData.SetEquals(replacements))
|
if (subMod.FileData.SetEquals(replacements))
|
||||||
|
|
@ -346,7 +348,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
|
||||||
|
|
||||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, groupIdx, optionIdx, -1);
|
communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, groupIdx, optionIdx, -1);
|
||||||
subMod.FileData.SetTo(replacements);
|
subMod.FileData.SetTo(replacements);
|
||||||
saveService.QueueSave(new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
|
saveService.Save(saveType, new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
|
||||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionFilesChanged, mod, groupIdx, optionIdx, -1);
|
communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionFilesChanged, mod, groupIdx, optionIdx, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -364,7 +366,8 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Set the file swaps for a given option. Replaces existing swaps. </summary>
|
/// <summary> Set the file swaps for a given option. Replaces existing swaps. </summary>
|
||||||
public void OptionSetFileSwaps(Mod mod, int groupIdx, int optionIdx, IReadOnlyDictionary<Utf8GamePath, FullPath> swaps)
|
public void OptionSetFileSwaps(Mod mod, int groupIdx, int optionIdx, IReadOnlyDictionary<Utf8GamePath, FullPath> swaps,
|
||||||
|
SaveType saveType = SaveType.Queue)
|
||||||
{
|
{
|
||||||
var subMod = GetSubMod(mod, groupIdx, optionIdx);
|
var subMod = GetSubMod(mod, groupIdx, optionIdx);
|
||||||
if (subMod.FileSwapData.SetEquals(swaps))
|
if (subMod.FileSwapData.SetEquals(swaps))
|
||||||
|
|
@ -372,7 +375,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
|
||||||
|
|
||||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, groupIdx, optionIdx, -1);
|
communicator.ModOptionChanged.Invoke(ModOptionChangeType.PrepareChange, mod, groupIdx, optionIdx, -1);
|
||||||
subMod.FileSwapData.SetTo(swaps);
|
subMod.FileSwapData.SetTo(swaps);
|
||||||
saveService.QueueSave(new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
|
saveService.Save(saveType, new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
|
||||||
communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionSwapsChanged, mod, groupIdx, optionIdx, -1);
|
communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionSwapsChanged, mod, groupIdx, optionIdx, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,7 @@ public sealed class CrashHandlerService : IDisposable, IService
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Penumbra.Log.Debug($"Could not delete {dir}:\n{ex}");
|
Penumbra.Log.Verbose($"Could not delete {dir}. This is generally not an error:\n{ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue