mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
Add ExportManager.
This commit is contained in:
parent
2b7292adb8
commit
a8000fbf14
11 changed files with 141 additions and 89 deletions
|
|
@ -256,7 +256,7 @@ public unsafe class MetaState : IDisposable
|
|||
using var decals =
|
||||
new DecalReverter(_characterUtility, _resources, resolveData.ModCollection, UsesDecal(0, data));
|
||||
var ret = _changeCustomize.Original(human, data, skipEquipment);
|
||||
_inChangeCustomize = false;
|
||||
_inChangeCustomize = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,17 +10,15 @@ public class ModBackup
|
|||
{
|
||||
public static bool CreatingBackup { get; private set; }
|
||||
|
||||
private readonly ModManager _modManager;
|
||||
private readonly Mod _mod;
|
||||
public readonly string Name;
|
||||
public readonly bool Exists;
|
||||
private readonly Mod _mod;
|
||||
public readonly string Name;
|
||||
public readonly bool Exists;
|
||||
|
||||
public ModBackup(ModManager modManager, Mod mod)
|
||||
{
|
||||
_modManager = modManager;
|
||||
_mod = mod;
|
||||
Name = Path.Combine(_modManager.ExportDirectory.FullName, _mod.ModPath.Name) + ".pmp";
|
||||
Exists = File.Exists(Name);
|
||||
public ModBackup(ExportManager exportManager, Mod mod)
|
||||
{
|
||||
_mod = mod;
|
||||
Name = Path.Combine(exportManager.ExportDirectory.FullName, _mod.ModPath.Name) + ".pmp";
|
||||
Exists = File.Exists(Name);
|
||||
}
|
||||
|
||||
/// <summary> Migrate file extensions. </summary>
|
||||
|
|
@ -118,7 +116,7 @@ public class ModBackup
|
|||
/// Restore a mod from a pre-existing backup. Does not check if the mod contained in the backup is even similar.
|
||||
/// Does an automatic reload after extraction.
|
||||
/// </summary>
|
||||
public void Restore()
|
||||
public void Restore(ModManager modManager)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -130,7 +128,7 @@ public class ModBackup
|
|||
|
||||
ZipFile.ExtractToDirectory(Name, _mod.ModPath.FullName);
|
||||
Penumbra.Log.Debug($"Extracted exported file {Name} to {_mod.ModPath.FullName}.");
|
||||
_modManager.ReloadMod(_mod.Index);
|
||||
modManager.ReloadMod(_mod.Index);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
|||
89
Penumbra/Mods/Manager/ExportManager.cs
Normal file
89
Penumbra/Mods/Manager/ExportManager.cs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Penumbra.Mods;
|
||||
|
||||
public class ExportManager : IDisposable
|
||||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly ModManager _modManager;
|
||||
|
||||
private DirectoryInfo? _exportDirectory;
|
||||
|
||||
public DirectoryInfo ExportDirectory
|
||||
=> _exportDirectory ?? _modManager.BasePath;
|
||||
|
||||
public ExportManager(Configuration config, ModManager modManager)
|
||||
{
|
||||
_config = config;
|
||||
_modManager = modManager;
|
||||
UpdateExportDirectory(_config.ExportDirectory, false);
|
||||
_modManager.ModPathChanged += OnModPathChange;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="UpdateExportDirectory(string, bool)"/>
|
||||
public void UpdateExportDirectory(string newDirectory)
|
||||
=> UpdateExportDirectory(newDirectory, true);
|
||||
|
||||
/// <summary>
|
||||
/// Update the export directory to a new directory. Can also reset it to null with empty input.
|
||||
/// If the directory is changed, all existing backups will be moved to the new one.
|
||||
/// </summary>
|
||||
/// <param name="newDirectory">The new directory name.</param>
|
||||
/// <param name="change">Can be used to stop saving for the initial setting</param>
|
||||
private void UpdateExportDirectory(string newDirectory, bool change)
|
||||
{
|
||||
if (newDirectory.Length == 0)
|
||||
{
|
||||
if (_exportDirectory == null)
|
||||
return;
|
||||
|
||||
_exportDirectory = null;
|
||||
_config.ExportDirectory = string.Empty;
|
||||
_config.Save();
|
||||
return;
|
||||
}
|
||||
|
||||
var dir = new DirectoryInfo(newDirectory);
|
||||
if (dir.FullName.Equals(_exportDirectory?.FullName, StringComparison.OrdinalIgnoreCase))
|
||||
return;
|
||||
|
||||
if (!dir.Exists)
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(dir.FullName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Penumbra.Log.Error($"Could not create Export Directory:\n{e}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (change)
|
||||
foreach (var mod in _modManager)
|
||||
new ModBackup(this, mod).Move(dir.FullName);
|
||||
|
||||
_exportDirectory = dir;
|
||||
|
||||
if (!change)
|
||||
return;
|
||||
|
||||
_config.ExportDirectory = dir.FullName;
|
||||
_config.Save();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
=> _modManager.ModPathChanged -= OnModPathChange;
|
||||
|
||||
/// <summary> Automatically migrate the backup file to the new name if any exists. </summary>
|
||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
|
||||
DirectoryInfo? newDirectory)
|
||||
{
|
||||
if (type is not ModPathChangeType.Moved || oldDirectory == null || newDirectory == null)
|
||||
return;
|
||||
|
||||
mod.ModPath = oldDirectory;
|
||||
new ModBackup(this, mod).Move(null, newDirectory.Name);
|
||||
mod.ModPath = newDirectory;
|
||||
}
|
||||
}
|
||||
|
|
@ -57,7 +57,6 @@ public partial class ModManager
|
|||
}
|
||||
|
||||
DataEditor.MoveDataFile(oldDirectory, dir);
|
||||
new ModBackup(this, mod).Move(null, dir.Name);
|
||||
|
||||
dir.Refresh();
|
||||
mod.ModPath = dir;
|
||||
|
|
|
|||
|
|
@ -9,11 +9,6 @@ namespace Penumbra.Mods;
|
|||
public sealed partial class ModManager
|
||||
{
|
||||
public DirectoryInfo BasePath { get; private set; } = null!;
|
||||
private DirectoryInfo? _exportDirectory;
|
||||
|
||||
public DirectoryInfo ExportDirectory
|
||||
=> _exportDirectory ?? BasePath;
|
||||
|
||||
public bool Valid { get; private set; }
|
||||
|
||||
public event Action? ModDiscoveryStarted;
|
||||
|
|
@ -105,45 +100,4 @@ public sealed partial class ModManager
|
|||
if (MigrateModBackups)
|
||||
ModBackup.MigrateZipToPmp(this);
|
||||
}
|
||||
|
||||
public void UpdateExportDirectory(string newDirectory, bool change)
|
||||
{
|
||||
if (newDirectory.Length == 0)
|
||||
{
|
||||
if (_exportDirectory == null)
|
||||
return;
|
||||
|
||||
_exportDirectory = null;
|
||||
_config.ExportDirectory = string.Empty;
|
||||
_config.Save();
|
||||
return;
|
||||
}
|
||||
|
||||
var dir = new DirectoryInfo(newDirectory);
|
||||
if (dir.FullName.Equals(_exportDirectory?.FullName, StringComparison.OrdinalIgnoreCase))
|
||||
return;
|
||||
|
||||
if (!dir.Exists)
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(dir.FullName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Penumbra.Log.Error($"Could not create Export Directory:\n{e}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (change)
|
||||
foreach (var mod in _mods)
|
||||
new ModBackup(this, mod).Move(dir.FullName);
|
||||
|
||||
_exportDirectory = dir;
|
||||
|
||||
if (change)
|
||||
{
|
||||
_config.ExportDirectory = dir.FullName;
|
||||
_config.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ public sealed partial class ModManager : IReadOnlyList<Mod>, IDisposable
|
|||
OptionEditor = optionEditor;
|
||||
ModDirectoryChanged += OnModDirectoryChange;
|
||||
SetBaseDirectory(config.ModDirectory, true);
|
||||
UpdateExportDirectory(_config.ExportDirectory, false);
|
||||
_communicator.ModOptionChanged.Event += OnModOptionChange;
|
||||
ModPathChanged += OnModPathChange;
|
||||
DiscoverMods();
|
||||
|
|
|
|||
|
|
@ -47,11 +47,11 @@ public readonly struct ModSaveGroup : ISavable
|
|||
public ModSaveGroup(Mod mod, int groupIdx)
|
||||
{
|
||||
_basePath = mod.ModPath;
|
||||
_groupIdx = groupIdx;
|
||||
if (_groupIdx < 0)
|
||||
_defaultMod = mod.Default;
|
||||
else
|
||||
_group = mod.Groups[groupIdx];
|
||||
_groupIdx = groupIdx;
|
||||
_group = mod.Groups[_groupIdx];
|
||||
}
|
||||
|
||||
public ModSaveGroup(DirectoryInfo basePath, IModGroup group, int groupIdx)
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ public class PenumbraNew
|
|||
.AddSingleton<ModDataEditor>()
|
||||
.AddSingleton<ModOptionEditor>()
|
||||
.AddSingleton<ModManager>()
|
||||
.AddSingleton<ExportManager>()
|
||||
.AddSingleton<ModFileSystem>();
|
||||
|
||||
// Add Resource services
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
|
|
@ -87,8 +88,9 @@ public class FileDialogService : IDisposable
|
|||
return (valid, list) =>
|
||||
{
|
||||
_isOpen = false;
|
||||
_startPaths[title] = GetCurrentLocation();
|
||||
callback(valid, list);
|
||||
var loc = HandleRoot(GetCurrentLocation());
|
||||
_startPaths[title] = loc;
|
||||
callback(valid, list.Select(HandleRoot).ToList());
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -97,14 +99,20 @@ public class FileDialogService : IDisposable
|
|||
return (valid, list) =>
|
||||
{
|
||||
_isOpen = false;
|
||||
var loc = GetCurrentLocation();
|
||||
if (loc.Length == 2)
|
||||
loc += '\\';
|
||||
var loc = HandleRoot(GetCurrentLocation());
|
||||
_startPaths[title] = loc;
|
||||
callback(valid, list);
|
||||
callback(valid, HandleRoot(list));
|
||||
};
|
||||
}
|
||||
|
||||
private static string HandleRoot(string path)
|
||||
{
|
||||
if (path.Length == 2 && path[1] == ':')
|
||||
return path + '\\';
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
// TODO: maybe change this from reflection when its public.
|
||||
private string GetCurrentLocation()
|
||||
=> (_manager.GetType().GetField("dialog", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(_manager) as FileDialog)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ public class ModPanelEditTab : ITab
|
|||
private readonly ChatService _chat;
|
||||
private readonly FilenameService _filenames;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly ExportManager _exportManager;
|
||||
private readonly ModFileSystem _fileSystem;
|
||||
private readonly ModFileSystemSelector _selector;
|
||||
private readonly ModEditWindow _editWindow;
|
||||
|
|
@ -36,15 +37,16 @@ public class ModPanelEditTab : ITab
|
|||
private Mod _mod = null!;
|
||||
|
||||
public ModPanelEditTab(ModManager modManager, ModFileSystemSelector selector, ModFileSystem fileSystem, ChatService chat,
|
||||
ModEditWindow editWindow, ModEditor editor, FilenameService filenames)
|
||||
ModEditWindow editWindow, ModEditor editor, FilenameService filenames, ExportManager exportManager)
|
||||
{
|
||||
_modManager = modManager;
|
||||
_selector = selector;
|
||||
_fileSystem = fileSystem;
|
||||
_chat = chat;
|
||||
_editWindow = editWindow;
|
||||
_editor = editor;
|
||||
_filenames = filenames;
|
||||
_modManager = modManager;
|
||||
_selector = selector;
|
||||
_fileSystem = fileSystem;
|
||||
_chat = chat;
|
||||
_editWindow = editWindow;
|
||||
_editor = editor;
|
||||
_filenames = filenames;
|
||||
_exportManager = exportManager;
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> Label
|
||||
|
|
@ -147,7 +149,7 @@ public class ModPanelEditTab : ITab
|
|||
|
||||
private void BackupButtons(Vector2 buttonSize)
|
||||
{
|
||||
var backup = new ModBackup(_modManager, _mod);
|
||||
var backup = new ModBackup(_exportManager, _mod);
|
||||
var tt = ModBackup.CreatingBackup
|
||||
? "Already exporting a mod."
|
||||
: backup.Exists
|
||||
|
|
@ -168,7 +170,7 @@ public class ModPanelEditTab : ITab
|
|||
: $"Exported mod \"{backup.Name}\" does not exist.";
|
||||
ImGui.SameLine();
|
||||
if (ImGuiUtil.DrawDisabledButton("Restore From Export", buttonSize, tt, !backup.Exists))
|
||||
backup.Restore();
|
||||
backup.Restore(_modManager);
|
||||
}
|
||||
|
||||
/// <summary> Anything about editing the regular meta information about the mod. </summary>
|
||||
|
|
@ -306,11 +308,11 @@ public class ModPanelEditTab : ITab
|
|||
private static int _newDescriptionIdx = -1;
|
||||
private static int _newDescriptionOptionIdx = -1;
|
||||
private static Mod? _mod;
|
||||
private static FilenameService? _fileNames;
|
||||
private static FilenameService? _fileNames;
|
||||
|
||||
public static void OpenPopup(FilenameService filenames, Mod mod, int groupIdx, int optionIdx = -1)
|
||||
{
|
||||
_fileNames = filenames;
|
||||
_fileNames = filenames;
|
||||
_newDescriptionIdx = groupIdx;
|
||||
_newDescriptionOptionIdx = optionIdx;
|
||||
_newDescription = groupIdx < 0
|
||||
|
|
@ -598,7 +600,8 @@ public class ModPanelEditTab : ITab
|
|||
if (_dragDropGroupIdx == groupIdx)
|
||||
{
|
||||
var sourceOption = _dragDropOptionIdx;
|
||||
panel._delayedActions.Enqueue(() => panel._modManager.OptionEditor.MoveOption(panel._mod, groupIdx, sourceOption, optionIdx));
|
||||
panel._delayedActions.Enqueue(
|
||||
() => panel._modManager.OptionEditor.MoveOption(panel._mod, groupIdx, sourceOption, optionIdx));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ using ImGuiNET;
|
|||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.Interop;
|
||||
using Penumbra.Interop.Services;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Services;
|
||||
|
|
@ -31,7 +30,8 @@ public class SettingsTab : ITab
|
|||
private readonly TutorialService _tutorial;
|
||||
private readonly Penumbra _penumbra;
|
||||
private readonly FileDialogService _fileDialog;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly ExportManager _exportManager;
|
||||
private readonly ModFileSystemSelector _selector;
|
||||
private readonly CharacterUtility _characterUtility;
|
||||
private readonly ResidentResourceManager _residentResources;
|
||||
|
|
@ -39,7 +39,7 @@ public class SettingsTab : ITab
|
|||
|
||||
public SettingsTab(Configuration config, FontReloader fontReloader, TutorialService tutorial, Penumbra penumbra,
|
||||
FileDialogService fileDialog, ModManager modManager, ModFileSystemSelector selector, CharacterUtility characterUtility,
|
||||
ResidentResourceManager residentResources, DalamudServices dalamud)
|
||||
ResidentResourceManager residentResources, DalamudServices dalamud, ExportManager exportManager)
|
||||
{
|
||||
_config = config;
|
||||
_fontReloader = fontReloader;
|
||||
|
|
@ -51,6 +51,7 @@ public class SettingsTab : ITab
|
|||
_characterUtility = characterUtility;
|
||||
_residentResources = residentResources;
|
||||
_dalamud = dalamud;
|
||||
_exportManager = exportManager;
|
||||
}
|
||||
|
||||
public void DrawHeader()
|
||||
|
|
@ -114,7 +115,7 @@ public class SettingsTab : ITab
|
|||
|
||||
/// <summary> Check a potential new root directory for validity and return the button text and whether it is valid. </summary>
|
||||
private static (string Text, bool Valid) CheckRootDirectoryPath(string newName, string old, bool selected)
|
||||
{
|
||||
{
|
||||
static bool IsSubPathOf(string basePath, string subPath)
|
||||
{
|
||||
if (basePath.Length == 0)
|
||||
|
|
@ -127,7 +128,7 @@ public class SettingsTab : ITab
|
|||
if (newName.Length > RootDirectoryMaxLength)
|
||||
return ($"Path is too long. The maximum length is {RootDirectoryMaxLength}.", false);
|
||||
|
||||
if (Path.GetDirectoryName(newName) == null)
|
||||
if (Path.GetDirectoryName(newName).IsNullOrEmpty())
|
||||
return ("Path is not allowed to be a drive root. Please add a directory.", false);
|
||||
|
||||
var desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
|
|
@ -553,7 +554,7 @@ public class SettingsTab : ITab
|
|||
_tempExportDirectory = tmp;
|
||||
|
||||
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||
_modManager.UpdateExportDirectory(_tempExportDirectory, true);
|
||||
_exportManager.UpdateExportDirectory(_tempExportDirectory);
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGuiUtil.DrawDisabledButton($"{FontAwesomeIcon.Folder.ToIconString()}##export", UiHelpers.IconButtonSize,
|
||||
|
|
@ -567,7 +568,7 @@ public class SettingsTab : ITab
|
|||
_fileDialog.OpenFolderPicker("Choose Default Export Directory", (b, s) =>
|
||||
{
|
||||
if (b)
|
||||
Penumbra.ModManager.UpdateExportDirectory(s, true);
|
||||
_exportManager.UpdateExportDirectory(s);
|
||||
}, startDir, false);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue