mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-02-21 15:27:51 +01:00
Some mod movement.
This commit is contained in:
parent
c12dbf3f8a
commit
577669b21f
26 changed files with 726 additions and 732 deletions
162
Penumbra/Mods/Manager/ModFileSystem.cs
Normal file
162
Penumbra/Mods/Manager/ModFileSystem.cs
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Mods.Manager;
|
||||
|
||||
public sealed class ModFileSystem : FileSystem<Mod>, IDisposable, ISavable
|
||||
{
|
||||
private readonly ModManager _modManager;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly FilenameService _files;
|
||||
|
||||
// Create a new ModFileSystem from the currently loaded mods and the current sort order file.
|
||||
public ModFileSystem(ModManager modManager, CommunicatorService communicator, FilenameService files)
|
||||
{
|
||||
_modManager = modManager;
|
||||
_communicator = communicator;
|
||||
_files = files;
|
||||
Reload();
|
||||
Changed += OnChange;
|
||||
_communicator.ModDiscoveryFinished.Event += Reload;
|
||||
_communicator.ModDataChanged.Event += OnDataChange;
|
||||
_communicator.ModPathChanged.Event += OnModPathChange;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_communicator.ModPathChanged.Event -= OnModPathChange;
|
||||
_communicator.ModDiscoveryFinished.Event -= Reload;
|
||||
_communicator.ModDataChanged.Event -= OnDataChange;
|
||||
}
|
||||
|
||||
public struct ImportDate : ISortMode<Mod>
|
||||
{
|
||||
public string Name
|
||||
=> "Import Date (Older First)";
|
||||
|
||||
public string Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their import date.";
|
||||
|
||||
public IEnumerable<IPath> GetChildren(Folder f)
|
||||
=> f.GetSubFolders().Cast<IPath>().Concat(f.GetLeaves().OrderBy(l => l.Value.ImportDate));
|
||||
}
|
||||
|
||||
public struct InverseImportDate : ISortMode<Mod>
|
||||
{
|
||||
public string Name
|
||||
=> "Import Date (Newer First)";
|
||||
|
||||
public string Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their inverse import date.";
|
||||
|
||||
public IEnumerable<IPath> GetChildren(Folder f)
|
||||
=> f.GetSubFolders().Cast<IPath>().Concat(f.GetLeaves().OrderByDescending(l => l.Value.ImportDate));
|
||||
}
|
||||
|
||||
// Reload the whole filesystem from currently loaded mods and the current sort order file.
|
||||
// Used on construction and on mod rediscoveries.
|
||||
private void Reload()
|
||||
{
|
||||
// TODO
|
||||
if (Load(new FileInfo(_files.FilesystemFile), _modManager, ModToIdentifier, ModToName))
|
||||
Penumbra.SaveService.ImmediateSave(this);
|
||||
|
||||
Penumbra.Log.Debug("Reloaded mod filesystem.");
|
||||
}
|
||||
|
||||
// Save the filesystem on every filesystem change except full reloading.
|
||||
private void OnChange(FileSystemChangeType type, IPath _1, IPath? _2, IPath? _3)
|
||||
{
|
||||
if (type != FileSystemChangeType.Reload)
|
||||
Penumbra.SaveService.QueueSave(this);
|
||||
}
|
||||
|
||||
// Update sort order when defaulted mod names change.
|
||||
private void OnDataChange(ModDataChangeType type, Mod mod, string? oldName)
|
||||
{
|
||||
if (type.HasFlag(ModDataChangeType.Name) && oldName != null)
|
||||
{
|
||||
var old = oldName.FixName();
|
||||
if (Find(old, out var child) && child is not Folder)
|
||||
Rename(child, mod.Name.Text);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the filesystem if a mod has been added or removed.
|
||||
// Save it, if the mod directory has been moved, since this will change the save format.
|
||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldPath, DirectoryInfo? newPath)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ModPathChangeType.Added:
|
||||
var originalName = mod.Name.Text.FixName();
|
||||
var name = originalName;
|
||||
var counter = 1;
|
||||
while (Find(name, out _))
|
||||
name = $"{originalName} ({++counter})";
|
||||
|
||||
CreateLeaf(Root, name, mod);
|
||||
break;
|
||||
case ModPathChangeType.Deleted:
|
||||
if (FindLeaf(mod, out var leaf))
|
||||
Delete(leaf);
|
||||
|
||||
break;
|
||||
case ModPathChangeType.Moved:
|
||||
Penumbra.SaveService.QueueSave(this);
|
||||
break;
|
||||
case ModPathChangeType.Reloaded:
|
||||
// Nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Search the entire filesystem for the leaf corresponding to a mod.
|
||||
public bool FindLeaf(Mod mod, [NotNullWhen(true)] out Leaf? leaf)
|
||||
{
|
||||
leaf = Root.GetAllDescendants(ISortMode<Mod>.Lexicographical)
|
||||
.OfType<Leaf>()
|
||||
.FirstOrDefault(l => l.Value == mod);
|
||||
return leaf != null;
|
||||
}
|
||||
|
||||
|
||||
// Used for saving and loading.
|
||||
private static string ModToIdentifier(Mod mod)
|
||||
=> mod.ModPath.Name;
|
||||
|
||||
private static string ModToName(Mod mod)
|
||||
=> mod.Name.Text.FixName();
|
||||
|
||||
// Return whether a mod has a custom path or is just a numbered default path.
|
||||
public static bool ModHasDefaultPath(Mod mod, string fullPath)
|
||||
{
|
||||
var regex = new Regex($@"^{Regex.Escape(ModToName(mod))}( \(\d+\))?$");
|
||||
return regex.IsMatch(fullPath);
|
||||
}
|
||||
|
||||
private static (string, bool) SaveMod(Mod mod, string fullPath)
|
||||
// Only save pairs with non-default paths.
|
||||
=> ModHasDefaultPath(mod, fullPath)
|
||||
? (string.Empty, false)
|
||||
: (ModToIdentifier(mod), true);
|
||||
|
||||
public string ToFilename(FilenameService fileNames)
|
||||
=> fileNames.FilesystemFile;
|
||||
|
||||
public void Save(StreamWriter writer)
|
||||
=> SaveToFile(writer, SaveMod, true);
|
||||
|
||||
public string TypeName
|
||||
=> "Mod File System";
|
||||
|
||||
public string LogName(string _)
|
||||
=> "to file";
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue