mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +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.Subclasses;
|
||||
using Penumbra.Services;
|
||||
|
|
@ -81,7 +82,7 @@ public class DuplicateManager(ModManager modManager, SaveService saveService, Co
|
|||
|
||||
if (useModManager)
|
||||
{
|
||||
modManager.OptionEditor.OptionSetFiles(mod, groupIdx, optionIdx, dict);
|
||||
modManager.OptionEditor.OptionSetFiles(mod, groupIdx, optionIdx, dict, SaveType.ImmediateSync);
|
||||
}
|
||||
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>
|
||||
internal void DeduplicateMod(DirectoryInfo modDirectory)
|
||||
internal void DeduplicateMod(DirectoryInfo modDirectory, bool useModManager = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
var mod = new Mod(modDirectory);
|
||||
modManager.Creator.ReloadMod(mod, true, out _);
|
||||
if (!useModManager || !modManager.TryGetMod(modDirectory.Name, string.Empty, out var mod))
|
||||
{
|
||||
mod = new Mod(modDirectory);
|
||||
modManager.Creator.ReloadMod(mod, true, out _);
|
||||
}
|
||||
|
||||
Clear();
|
||||
var files = new ModFileCollection();
|
||||
files.UpdateAll(mod, mod.Default);
|
||||
CheckDuplicates(files.Available.OrderByDescending(f => f.FileSize).ToArray(), CancellationToken.None);
|
||||
DeleteDuplicates(files, mod, mod.Default, false);
|
||||
CheckDuplicates([.. files.Available.OrderByDescending(f => f.FileSize)], CancellationToken.None);
|
||||
DeleteDuplicates(files, mod, mod.Default, useModManager);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ public class ModMerger : IDisposable
|
|||
|
||||
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 ModMerger(ModManager mods, ModOptionEditor editor, ModFileSystemSelector selector, DuplicateManager duplicates,
|
||||
|
|
@ -78,7 +78,8 @@ public class ModMerger : IDisposable
|
|||
MergeWithOptions();
|
||||
else
|
||||
MergeIntoOption(OptionGroupName, OptionName);
|
||||
_duplicates.DeduplicateMod(MergeToMod.ModPath);
|
||||
|
||||
_duplicates.DeduplicateMod(MergeToMod.ModPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -134,10 +135,10 @@ public class ModMerger : IDisposable
|
|||
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)
|
||||
_createdGroups.Add(groupIdx);
|
||||
var (option, optionCreated) = _editor.FindOrAddOption(MergeToMod!, groupIdx, optionName);
|
||||
var (option, optionCreated) = _editor.FindOrAddOption(MergeToMod!, groupIdx, optionName, SaveType.None);
|
||||
if (optionCreated)
|
||||
_createdOptions.Add(option);
|
||||
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 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 manip in originalOption.Manipulations)
|
||||
|
|
@ -204,9 +184,31 @@ public class ModMerger : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
_editor.OptionSetFiles(MergeToMod!, option.GroupIdx, option.OptionIdx, redirections);
|
||||
_editor.OptionSetFileSwaps(MergeToMod!, option.GroupIdx, option.OptionIdx, swaps);
|
||||
_editor.OptionSetManipulations(MergeToMod!, option.GroupIdx, option.OptionIdx, manips);
|
||||
_editor.OptionSetFiles(MergeToMod!, option.GroupIdx, option.OptionIdx, redirections, SaveType.None);
|
||||
_editor.OptionSetFileSwaps(MergeToMod!, option.GroupIdx, option.OptionIdx, swaps, SaveType.None);
|
||||
_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)
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
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))
|
||||
return;
|
||||
|
|
@ -96,18 +96,18 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
|
|||
Name = newName,
|
||||
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);
|
||||
}
|
||||
|
||||
/// <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);
|
||||
if (idx >= 0)
|
||||
return (mod.Groups[idx], idx, false);
|
||||
|
||||
AddModGroup(mod, type, newName);
|
||||
AddModGroup(mod, type, newName, saveType);
|
||||
if (mod.Groups[^1].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>
|
||||
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 subMod = new SubMod(mod) { Name = newName };
|
||||
|
|
@ -241,19 +241,19 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
|
|||
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);
|
||||
}
|
||||
|
||||
/// <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 idx = group.IndexOf(o => o.Name == newName);
|
||||
if (idx >= 0)
|
||||
return ((SubMod)group[idx], false);
|
||||
|
||||
AddOption(mod, groupIdx, newName);
|
||||
AddOption(mod, groupIdx, newName, saveType);
|
||||
if (group[^1].Name != newName)
|
||||
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>
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
/// <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);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -364,7 +366,8 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
|
|||
}
|
||||
|
||||
/// <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);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ public sealed class CrashHandlerService : IDisposable, IService
|
|||
}
|
||||
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