mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Use ModManager2
This commit is contained in:
parent
70c1a2604f
commit
afa11f85e2
16 changed files with 131 additions and 542 deletions
|
|
@ -56,6 +56,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
CheckInitialized();
|
||||
_communicator.CreatingCharacterBase.Event += new Action<nint, string, nint, nint, nint>(value);
|
||||
}
|
||||
|
|
@ -63,6 +64,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
CheckInitialized();
|
||||
_communicator.CreatingCharacterBase.Event -= new Action<nint, string, nint, nint, nint>(value);
|
||||
}
|
||||
|
|
@ -74,6 +76,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
CheckInitialized();
|
||||
_communicator.CreatedCharacterBase.Event += new Action<nint, string, nint>(value);
|
||||
}
|
||||
|
|
@ -81,6 +84,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
CheckInitialized();
|
||||
_communicator.CreatedCharacterBase.Event -= new Action<nint, string, nint>(value);
|
||||
}
|
||||
|
|
@ -93,10 +97,10 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
private Penumbra _penumbra;
|
||||
private Lumina.GameData? _lumina;
|
||||
|
||||
private ModManager _modManager;
|
||||
private ModManager _modManager;
|
||||
private ResourceLoader _resourceLoader;
|
||||
private Configuration _config;
|
||||
private CollectionManager _collectionManager;
|
||||
private CollectionManager _collectionManager;
|
||||
private DalamudServices _dalamud;
|
||||
private TempCollectionManager _tempCollections;
|
||||
private TempModManager _tempMods;
|
||||
|
|
@ -108,18 +112,18 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
Configuration config, CollectionManager collectionManager, DalamudServices dalamud, TempCollectionManager tempCollections,
|
||||
TempModManager tempMods, ActorService actors, CollectionResolver collectionResolver, CutsceneService cutsceneService)
|
||||
{
|
||||
_communicator = communicator;
|
||||
_penumbra = penumbra;
|
||||
_modManager = modManager;
|
||||
_resourceLoader = resourceLoader;
|
||||
_config = config;
|
||||
_collectionManager = collectionManager;
|
||||
_dalamud = dalamud;
|
||||
_tempCollections = tempCollections;
|
||||
_tempMods = tempMods;
|
||||
_actors = actors;
|
||||
_collectionResolver = collectionResolver;
|
||||
_cutsceneService = cutsceneService;
|
||||
_communicator = communicator;
|
||||
_penumbra = penumbra;
|
||||
_modManager = modManager;
|
||||
_resourceLoader = resourceLoader;
|
||||
_config = config;
|
||||
_collectionManager = collectionManager;
|
||||
_dalamud = dalamud;
|
||||
_tempCollections = tempCollections;
|
||||
_tempMods = tempMods;
|
||||
_actors = actors;
|
||||
_collectionResolver = collectionResolver;
|
||||
_cutsceneService = cutsceneService;
|
||||
|
||||
_lumina = (Lumina.GameData?)_dalamud.GameData.GetType()
|
||||
.GetField("gameData", BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
|
|
@ -129,13 +133,13 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
|
||||
_communicator.CollectionChange.Event += SubscribeToNewCollections;
|
||||
_resourceLoader.ResourceLoaded += OnResourceLoaded;
|
||||
_modManager.ModPathChanged += ModPathChangeSubscriber;
|
||||
_communicator.ModPathChanged.Event += ModPathChangeSubscriber;
|
||||
}
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
if (!Valid)
|
||||
return;
|
||||
return;
|
||||
|
||||
foreach (var collection in _collectionManager)
|
||||
{
|
||||
|
|
@ -145,7 +149,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
|
||||
_resourceLoader.ResourceLoaded -= OnResourceLoaded;
|
||||
_communicator.CollectionChange.Event -= SubscribeToNewCollections;
|
||||
_modManager.ModPathChanged -= ModPathChangeSubscriber;
|
||||
_communicator.ModPathChanged.Event -= ModPathChangeSubscriber;
|
||||
_lumina = null;
|
||||
_communicator = null!;
|
||||
_penumbra = null!;
|
||||
|
|
@ -182,12 +186,12 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
add
|
||||
{
|
||||
CheckInitialized();
|
||||
_modManager.ModDirectoryChanged += value;
|
||||
_communicator.ModDirectoryChanged.Event += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
CheckInitialized();
|
||||
_modManager.ModDirectoryChanged -= value;
|
||||
_communicator.ModDirectoryChanged.Event -= value;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -542,8 +546,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
|
||||
public unsafe (nint, string) GetDrawObjectInfo(nint drawObject)
|
||||
{
|
||||
CheckInitialized();
|
||||
var data = _collectionResolver.IdentifyCollection((DrawObject*) drawObject, true);
|
||||
CheckInitialized();
|
||||
var data = _collectionResolver.IdentifyCollection((DrawObject*)drawObject, true);
|
||||
return (data.AssociatedGameObject, data.ModCollection.Name);
|
||||
}
|
||||
|
||||
|
|
@ -592,7 +596,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
if (!_modManager.TryGetMod(modDirectory, modName, out var mod))
|
||||
return PenumbraApiEc.ModMissing;
|
||||
|
||||
_modManager.ReloadMod(mod.Index);
|
||||
_modManager.ReloadMod(mod);
|
||||
return PenumbraApiEc.Success;
|
||||
}
|
||||
|
||||
|
|
@ -613,7 +617,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
if (!_modManager.TryGetMod(modDirectory, modName, out var mod))
|
||||
return PenumbraApiEc.NothingChanged;
|
||||
|
||||
_modManager.DeleteMod(mod.Index);
|
||||
_modManager.DeleteMod(mod);
|
||||
return PenumbraApiEc.Success;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using Penumbra.Api;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.Interop;
|
||||
using Penumbra.Interop.Services;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.Util;
|
||||
|
|
@ -71,10 +70,10 @@ public sealed partial class CollectionManager : IDisposable, IEnumerable<ModColl
|
|||
Individuals = individuals;
|
||||
|
||||
// The collection manager reacts to changes in mods by itself.
|
||||
_modManager.ModDiscoveryStarted += OnModDiscoveryStarted;
|
||||
_modManager.ModDiscoveryFinished += OnModDiscoveryFinished;
|
||||
_communicator.ModDiscoveryStarted.Event += OnModDiscoveryStarted;
|
||||
_communicator.ModDiscoveryFinished.Event += OnModDiscoveryFinished;
|
||||
_communicator.ModOptionChanged.Event += OnModOptionsChanged;
|
||||
_modManager.ModPathChanged += OnModPathChange;
|
||||
_communicator.ModPathChanged.Event += OnModPathChange;
|
||||
_communicator.CollectionChange.Event += SaveOnChange;
|
||||
_communicator.TemporaryGlobalModChange.Event += OnGlobalModChange;
|
||||
ReadCollections(files);
|
||||
|
|
@ -87,10 +86,10 @@ public sealed partial class CollectionManager : IDisposable, IEnumerable<ModColl
|
|||
{
|
||||
_communicator.CollectionChange.Event -= SaveOnChange;
|
||||
_communicator.TemporaryGlobalModChange.Event -= OnGlobalModChange;
|
||||
_modManager.ModDiscoveryStarted -= OnModDiscoveryStarted;
|
||||
_modManager.ModDiscoveryFinished -= OnModDiscoveryFinished;
|
||||
_communicator.ModDiscoveryStarted.Event -= OnModDiscoveryStarted;
|
||||
_communicator.ModDiscoveryFinished.Event -= OnModDiscoveryFinished;
|
||||
_communicator.ModOptionChanged.Event -= OnModOptionsChanged;
|
||||
_modManager.ModPathChanged -= OnModPathChange;
|
||||
_communicator.ModPathChanged.Event -= OnModPathChange;
|
||||
}
|
||||
|
||||
private void OnGlobalModChange(TemporaryMod mod, bool created, bool removed)
|
||||
|
|
|
|||
|
|
@ -131,7 +131,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);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,24 +1,27 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Penumbra.Services;
|
||||
|
||||
namespace Penumbra.Mods;
|
||||
|
||||
public class ExportManager : IDisposable
|
||||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly Configuration _config;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly ModManager _modManager;
|
||||
|
||||
private DirectoryInfo? _exportDirectory;
|
||||
|
||||
public DirectoryInfo ExportDirectory
|
||||
=> _exportDirectory ?? _modManager.BasePath;
|
||||
|
||||
public ExportManager(Configuration config, ModManager modManager)
|
||||
public ExportManager(Configuration config, CommunicatorService communicator, ModManager modManager)
|
||||
{
|
||||
_config = config;
|
||||
_modManager = modManager;
|
||||
_config = config;
|
||||
_communicator = communicator;
|
||||
_modManager = modManager;
|
||||
UpdateExportDirectory(_config.ExportDirectory, false);
|
||||
_modManager.ModPathChanged += OnModPathChange;
|
||||
_communicator.ModPathChanged.Event += OnModPathChange;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="UpdateExportDirectory(string, bool)"/>
|
||||
|
|
@ -73,7 +76,7 @@ public class ExportManager : IDisposable
|
|||
}
|
||||
|
||||
public void Dispose()
|
||||
=> _modManager.ModPathChanged -= OnModPathChange;
|
||||
=> _communicator.ModPathChanged.Event -= OnModPathChange;
|
||||
|
||||
/// <summary> Automatically migrate the backup file to the new name if any exists. </summary>
|
||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
|
||||
|
|
|
|||
|
|
@ -1,203 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Penumbra.Mods;
|
||||
|
||||
public partial class ModManager
|
||||
{
|
||||
public delegate void ModPathChangeDelegate(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
|
||||
DirectoryInfo? newDirectory);
|
||||
|
||||
public event ModPathChangeDelegate ModPathChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Rename/Move a mod directory.
|
||||
/// Updates all collection settings and sort order settings.
|
||||
/// </summary>
|
||||
public void MoveModDirectory(int idx, string newName)
|
||||
{
|
||||
var mod = this[idx];
|
||||
var oldName = mod.Name;
|
||||
var oldDirectory = mod.ModPath;
|
||||
|
||||
switch (NewDirectoryValid(oldDirectory.Name, newName, out var dir))
|
||||
{
|
||||
case NewDirectoryState.NonExisting:
|
||||
// Nothing to do
|
||||
break;
|
||||
case NewDirectoryState.ExistsEmpty:
|
||||
try
|
||||
{
|
||||
Directory.Delete(dir!.FullName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Penumbra.Log.Error($"Could not delete empty directory {dir!.FullName} to move {mod.Name} to it:\n{e}");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
// Should be caught beforehand.
|
||||
case NewDirectoryState.ExistsNonEmpty:
|
||||
case NewDirectoryState.ExistsAsFile:
|
||||
case NewDirectoryState.ContainsInvalidSymbols:
|
||||
// Nothing to do at all.
|
||||
case NewDirectoryState.Identical:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Directory.Move(oldDirectory.FullName, dir!.FullName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Penumbra.Log.Error($"Could not move {mod.Name} from {oldDirectory.Name} to {dir!.Name}:\n{e}");
|
||||
return;
|
||||
}
|
||||
|
||||
DataEditor.MoveDataFile(oldDirectory, dir);
|
||||
|
||||
dir.Refresh();
|
||||
mod.ModPath = dir;
|
||||
if (!mod.Reload(this, false, out var metaChange))
|
||||
{
|
||||
Penumbra.Log.Error($"Error reloading moved mod {mod.Name}.");
|
||||
return;
|
||||
}
|
||||
|
||||
ModPathChanged.Invoke(ModPathChangeType.Moved, mod, oldDirectory, dir);
|
||||
if (metaChange != ModDataChangeType.None)
|
||||
_communicator.ModDataChanged.Invoke(metaChange, mod, oldName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reload a mod without changing its base directory.
|
||||
/// If the base directory does not exist anymore, the mod will be deleted.
|
||||
/// </summary>
|
||||
public void ReloadMod(int idx)
|
||||
{
|
||||
var mod = this[idx];
|
||||
var oldName = mod.Name;
|
||||
|
||||
ModPathChanged.Invoke(ModPathChangeType.StartingReload, mod, mod.ModPath, mod.ModPath);
|
||||
if (!mod.Reload(this, true, out var metaChange))
|
||||
{
|
||||
Penumbra.Log.Warning(mod.Name.Length == 0
|
||||
? $"Reloading mod {oldName} has failed, new name is empty. Deleting instead."
|
||||
: $"Reloading mod {oldName} failed, {mod.ModPath.FullName} does not exist anymore or it ha. Deleting instead.");
|
||||
|
||||
DeleteMod(idx);
|
||||
return;
|
||||
}
|
||||
|
||||
ModPathChanged.Invoke(ModPathChangeType.Reloaded, mod, mod.ModPath, mod.ModPath);
|
||||
if (metaChange != ModDataChangeType.None)
|
||||
_communicator.ModDataChanged.Invoke(metaChange, mod, oldName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete a mod by its index. The event is invoked before the mod is removed from the list.
|
||||
/// Deletes from filesystem as well as from internal data.
|
||||
/// Updates indices of later mods.
|
||||
/// </summary>
|
||||
public void DeleteMod(int idx)
|
||||
{
|
||||
var mod = this[idx];
|
||||
if (Directory.Exists(mod.ModPath.FullName))
|
||||
try
|
||||
{
|
||||
Directory.Delete(mod.ModPath.FullName, true);
|
||||
Penumbra.Log.Debug($"Deleted directory {mod.ModPath.FullName} for {mod.Name}.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Penumbra.Log.Error($"Could not delete the mod {mod.ModPath.Name}:\n{e}");
|
||||
}
|
||||
|
||||
ModPathChanged.Invoke(ModPathChangeType.Deleted, mod, mod.ModPath, null);
|
||||
_mods.RemoveAt(idx);
|
||||
foreach (var remainingMod in _mods.Skip(idx))
|
||||
--remainingMod.Index;
|
||||
|
||||
Penumbra.Log.Debug($"Deleted mod {mod.Name}.");
|
||||
}
|
||||
|
||||
/// <summary> Load a new mod and add it to the manager if successful. </summary>
|
||||
public void AddMod(DirectoryInfo modFolder)
|
||||
{
|
||||
if (_mods.Any(m => m.ModPath.Name == modFolder.Name))
|
||||
return;
|
||||
|
||||
Mod.Creator.SplitMultiGroups(modFolder);
|
||||
var mod = Mod.LoadMod(this, modFolder, true);
|
||||
if (mod == null)
|
||||
return;
|
||||
|
||||
mod.Index = _mods.Count;
|
||||
_mods.Add(mod);
|
||||
ModPathChanged.Invoke(ModPathChangeType.Added, mod, null, mod.ModPath);
|
||||
Penumbra.Log.Debug($"Added new mod {mod.Name} from {modFolder.FullName}.");
|
||||
}
|
||||
|
||||
public enum NewDirectoryState
|
||||
{
|
||||
NonExisting,
|
||||
ExistsEmpty,
|
||||
ExistsNonEmpty,
|
||||
ExistsAsFile,
|
||||
ContainsInvalidSymbols,
|
||||
Identical,
|
||||
Empty,
|
||||
}
|
||||
|
||||
/// <summary> Return the state of the new potential name of a directory. </summary>
|
||||
public NewDirectoryState NewDirectoryValid(string oldName, string newName, out DirectoryInfo? directory)
|
||||
{
|
||||
directory = null;
|
||||
if (newName.Length == 0)
|
||||
return NewDirectoryState.Empty;
|
||||
|
||||
if (oldName == newName)
|
||||
return NewDirectoryState.Identical;
|
||||
|
||||
var fixedNewName = Mod.Creator.ReplaceBadXivSymbols(newName);
|
||||
if (fixedNewName != newName)
|
||||
return NewDirectoryState.ContainsInvalidSymbols;
|
||||
|
||||
directory = new DirectoryInfo(Path.Combine(BasePath.FullName, fixedNewName));
|
||||
if (File.Exists(directory.FullName))
|
||||
return NewDirectoryState.ExistsAsFile;
|
||||
|
||||
if (!Directory.Exists(directory.FullName))
|
||||
return NewDirectoryState.NonExisting;
|
||||
|
||||
if (directory.EnumerateFileSystemInfos().Any())
|
||||
return NewDirectoryState.ExistsNonEmpty;
|
||||
|
||||
return NewDirectoryState.ExistsEmpty;
|
||||
}
|
||||
|
||||
|
||||
/// <summary> Add new mods to NewMods and remove deleted mods from NewMods. </summary>
|
||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
|
||||
DirectoryInfo? newDirectory)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ModPathChangeType.Added:
|
||||
NewMods.Add(mod);
|
||||
break;
|
||||
case ModPathChangeType.Deleted:
|
||||
NewMods.Remove(mod);
|
||||
break;
|
||||
case ModPathChangeType.Moved:
|
||||
if (oldDirectory != null && newDirectory != null)
|
||||
DataEditor.MoveDataFile(oldDirectory, newDirectory);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Penumbra.Mods;
|
||||
|
||||
public sealed partial class ModManager
|
||||
{
|
||||
public DirectoryInfo BasePath { get; private set; } = null!;
|
||||
public bool Valid { get; private set; }
|
||||
|
||||
public event Action? ModDiscoveryStarted;
|
||||
public event Action? ModDiscoveryFinished;
|
||||
public event Action<string, bool> ModDirectoryChanged;
|
||||
|
||||
// Change the mod base directory and discover available mods.
|
||||
public void DiscoverMods(string newDir)
|
||||
{
|
||||
SetBaseDirectory(newDir, false);
|
||||
DiscoverMods();
|
||||
}
|
||||
|
||||
// Set the mod base directory.
|
||||
// If its not the first time, check if it is the same directory as before.
|
||||
// Also checks if the directory is available and tries to create it if it is not.
|
||||
private void SetBaseDirectory(string newPath, bool firstTime)
|
||||
{
|
||||
if (!firstTime && string.Equals(newPath, Penumbra.Config.ModDirectory, StringComparison.OrdinalIgnoreCase))
|
||||
return;
|
||||
|
||||
if (newPath.Length == 0)
|
||||
{
|
||||
Valid = false;
|
||||
BasePath = new DirectoryInfo(".");
|
||||
if (Penumbra.Config.ModDirectory != BasePath.FullName)
|
||||
ModDirectoryChanged.Invoke(string.Empty, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var newDir = new DirectoryInfo(newPath);
|
||||
if (!newDir.Exists)
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(newDir.FullName);
|
||||
newDir.Refresh();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Penumbra.Log.Error($"Could not create specified mod directory {newDir.FullName}:\n{e}");
|
||||
}
|
||||
|
||||
BasePath = newDir;
|
||||
Valid = Directory.Exists(newDir.FullName);
|
||||
if (Penumbra.Config.ModDirectory != BasePath.FullName)
|
||||
ModDirectoryChanged.Invoke(BasePath.FullName, Valid);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnModDirectoryChange(string newPath, bool _)
|
||||
{
|
||||
Penumbra.Log.Information($"Set new mod base directory from {Penumbra.Config.ModDirectory} to {newPath}.");
|
||||
Penumbra.Config.ModDirectory = newPath;
|
||||
Penumbra.Config.Save();
|
||||
}
|
||||
|
||||
// Discover new mods.
|
||||
public void DiscoverMods()
|
||||
{
|
||||
NewMods.Clear();
|
||||
ModDiscoveryStarted?.Invoke();
|
||||
_mods.Clear();
|
||||
BasePath.Refresh();
|
||||
|
||||
if (Valid && BasePath.Exists)
|
||||
{
|
||||
var options = new ParallelOptions()
|
||||
{
|
||||
MaxDegreeOfParallelism = Environment.ProcessorCount / 2,
|
||||
};
|
||||
var queue = new ConcurrentQueue<Mod>();
|
||||
Parallel.ForEach(BasePath.EnumerateDirectories(), options, dir =>
|
||||
{
|
||||
var mod = Mod.LoadMod(this, dir, false);
|
||||
if (mod != null)
|
||||
queue.Enqueue(mod);
|
||||
});
|
||||
|
||||
foreach (var mod in queue)
|
||||
{
|
||||
mod.Index = _mods.Count;
|
||||
_mods.Add(mod);
|
||||
}
|
||||
}
|
||||
|
||||
ModDiscoveryFinished?.Invoke();
|
||||
Penumbra.Log.Information("Rediscovered mods.");
|
||||
|
||||
if (MigrateModBackups)
|
||||
ModBackup.MigrateZipToPmp(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,12 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Mods;
|
||||
|
||||
|
||||
/// <summary> Describes the state of a potential move-target for a mod. </summary>
|
||||
public enum NewDirectoryState
|
||||
{
|
||||
|
|
@ -20,25 +17,27 @@ public enum NewDirectoryState
|
|||
ContainsInvalidSymbols,
|
||||
Identical,
|
||||
Empty,
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ModManager2 : ModStorage
|
||||
public sealed class ModManager : ModStorage
|
||||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly CommunicatorService _communicator;
|
||||
|
||||
public readonly ModDataEditor DataEditor;
|
||||
public readonly ModOptionEditor OptionEditor;
|
||||
|
||||
public DirectoryInfo BasePath { get; private set; } = null!;
|
||||
public bool Valid { get; private set; }
|
||||
public bool Valid { get; private set; }
|
||||
|
||||
public ModManager2(Configuration config, CommunicatorService communicator, ModDataEditor dataEditor, ModOptionEditor optionEditor)
|
||||
public ModManager(Configuration config, CommunicatorService communicator, ModDataEditor dataEditor, ModOptionEditor optionEditor)
|
||||
{
|
||||
_config = config;
|
||||
_communicator = communicator;
|
||||
DataEditor = dataEditor;
|
||||
OptionEditor = optionEditor;
|
||||
OptionEditor = optionEditor;
|
||||
SetBaseDirectory(config.ModDirectory, true);
|
||||
DiscoverMods();
|
||||
}
|
||||
|
||||
/// <summary> Change the mod base directory and discover available mods. </summary>
|
||||
|
|
@ -75,7 +74,7 @@ public sealed class ModManager2 : ModStorage
|
|||
return;
|
||||
|
||||
Mod.Creator.SplitMultiGroups(modFolder);
|
||||
var mod = Mod.LoadMod(Penumbra.ModManager, modFolder, true);
|
||||
var mod = Mod.LoadMod(this, modFolder, true);
|
||||
if (mod == null)
|
||||
return;
|
||||
|
||||
|
|
@ -133,16 +132,16 @@ public sealed class ModManager2 : ModStorage
|
|||
_communicator.ModPathChanged.Invoke(ModPathChangeType.Reloaded, mod, mod.ModPath, mod.ModPath);
|
||||
if (metaChange != ModDataChangeType.None)
|
||||
_communicator.ModDataChanged.Invoke(metaChange, mod, oldName);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Rename/Move a mod directory.
|
||||
/// Updates all collection settings and sort order settings.
|
||||
/// </summary>
|
||||
/// Updates all collection settings and sort order settings.
|
||||
/// </summary>
|
||||
public void MoveModDirectory(Mod mod, string newName)
|
||||
{
|
||||
var oldName = mod.Name;
|
||||
var oldName = mod.Name;
|
||||
var oldDirectory = mod.ModPath;
|
||||
|
||||
switch (NewDirectoryValid(oldDirectory.Name, newName, out var dir))
|
||||
|
|
@ -195,8 +194,8 @@ public sealed class ModManager2 : ModStorage
|
|||
_communicator.ModPathChanged.Invoke(ModPathChangeType.Moved, mod, oldDirectory, dir);
|
||||
if (metaChange != ModDataChangeType.None)
|
||||
_communicator.ModDataChanged.Invoke(metaChange, mod, oldName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary> Return the state of the new potential name of a directory. </summary>
|
||||
public NewDirectoryState NewDirectoryValid(string oldName, string newName, out DirectoryInfo? directory)
|
||||
{
|
||||
|
|
@ -243,16 +242,16 @@ public sealed class ModManager2 : ModStorage
|
|||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Set the mod base directory.
|
||||
/// If its not the first time, check if it is the same directory as before.
|
||||
/// Also checks if the directory is available and tries to create it if it is not.
|
||||
/// </summary>
|
||||
/// Also checks if the directory is available and tries to create it if it is not.
|
||||
/// </summary>
|
||||
private void SetBaseDirectory(string newPath, bool firstTime)
|
||||
{
|
||||
if (!firstTime && string.Equals(newPath, _config.ModDirectory, StringComparison.OrdinalIgnoreCase))
|
||||
|
|
@ -260,7 +259,7 @@ public sealed class ModManager2 : ModStorage
|
|||
|
||||
if (newPath.Length == 0)
|
||||
{
|
||||
Valid = false;
|
||||
Valid = false;
|
||||
BasePath = new DirectoryInfo(".");
|
||||
if (_config.ModDirectory != BasePath.FullName)
|
||||
TriggerModDirectoryChange(string.Empty, false);
|
||||
|
|
@ -280,8 +279,8 @@ public sealed class ModManager2 : ModStorage
|
|||
}
|
||||
|
||||
BasePath = newDir;
|
||||
Valid = Directory.Exists(newDir.FullName);
|
||||
if (_config.ModDirectory != BasePath.FullName)
|
||||
Valid = Directory.Exists(newDir.FullName);
|
||||
if (!firstTime && _config.ModDirectory != BasePath.FullName)
|
||||
TriggerModDirectoryChange(BasePath.FullName, Valid);
|
||||
}
|
||||
}
|
||||
|
|
@ -295,10 +294,9 @@ public sealed class ModManager2 : ModStorage
|
|||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Iterate through available mods with multiple threads and queue their loads,
|
||||
/// then add the mods from the queue.
|
||||
/// then add the mods from the queue.
|
||||
/// </summary>
|
||||
private void ScanMods()
|
||||
{
|
||||
|
|
@ -309,7 +307,7 @@ public sealed class ModManager2 : ModStorage
|
|||
var queue = new ConcurrentQueue<Mod>();
|
||||
Parallel.ForEach(BasePath.EnumerateDirectories(), options, dir =>
|
||||
{
|
||||
var mod = Mod.LoadMod(Penumbra.ModManager, dir, false);
|
||||
var mod = Mod.LoadMod(this, dir, false);
|
||||
if (mod != null)
|
||||
queue.Enqueue(mod);
|
||||
});
|
||||
|
|
@ -321,111 +319,3 @@ public sealed class ModManager2 : ModStorage
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class ModManager : IReadOnlyList<Mod>, IDisposable
|
||||
{
|
||||
// Set when reading Config and migrating from v4 to v5.
|
||||
public static bool MigrateModBackups = false;
|
||||
|
||||
// An easily accessible set of new mods.
|
||||
// Mods are added when they are created or imported.
|
||||
// Mods are removed when they are deleted or when they are toggled in any collection.
|
||||
// Also gets cleared on mod rediscovery.
|
||||
public readonly HashSet<Mod> NewMods = new();
|
||||
|
||||
private readonly List<Mod> _mods = new();
|
||||
|
||||
public Mod this[int idx]
|
||||
=> _mods[idx];
|
||||
|
||||
public Mod this[Index idx]
|
||||
=> _mods[idx];
|
||||
|
||||
public int Count
|
||||
=> _mods.Count;
|
||||
|
||||
public IEnumerator<Mod> GetEnumerator()
|
||||
=> _mods.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
private readonly Configuration _config;
|
||||
private readonly CommunicatorService _communicator;
|
||||
public readonly ModDataEditor DataEditor;
|
||||
public readonly ModOptionEditor OptionEditor;
|
||||
|
||||
public ModManager(StartTracker time, Configuration config, CommunicatorService communicator, ModDataEditor dataEditor,
|
||||
ModOptionEditor optionEditor)
|
||||
{
|
||||
using var timer = time.Measure(StartTimeType.Mods);
|
||||
_config = config;
|
||||
_communicator = communicator;
|
||||
DataEditor = dataEditor;
|
||||
OptionEditor = optionEditor;
|
||||
ModDirectoryChanged += OnModDirectoryChange;
|
||||
SetBaseDirectory(config.ModDirectory, true);
|
||||
_communicator.ModOptionChanged.Event += OnModOptionChange;
|
||||
ModPathChanged += OnModPathChange;
|
||||
DiscoverMods();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_communicator.ModOptionChanged.Event -= OnModOptionChange;
|
||||
}
|
||||
|
||||
|
||||
// Try to obtain a mod by its directory name (unique identifier, preferred),
|
||||
// or the first mod of the given name if no directory fits.
|
||||
public bool TryGetMod(string modDirectory, string modName, [NotNullWhen(true)] out Mod? mod)
|
||||
{
|
||||
mod = null;
|
||||
foreach (var m in _mods)
|
||||
{
|
||||
if (string.Equals(m.ModPath.Name, modDirectory, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
mod = m;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m.Name == modName)
|
||||
mod ??= m;
|
||||
}
|
||||
|
||||
return mod != null;
|
||||
}
|
||||
|
||||
private static void OnModOptionChange(ModOptionChangeType type, Mod mod, int groupIdx, int _, int _2)
|
||||
{
|
||||
if (type == ModOptionChangeType.PrepareChange)
|
||||
return;
|
||||
|
||||
bool ComputeChangedItems()
|
||||
{
|
||||
mod.ComputeChangedItems();
|
||||
return true;
|
||||
}
|
||||
|
||||
// State can not change on adding groups, as they have no immediate options.
|
||||
var unused = type switch
|
||||
{
|
||||
ModOptionChangeType.GroupAdded => ComputeChangedItems() & mod.SetCounts(),
|
||||
ModOptionChangeType.GroupDeleted => ComputeChangedItems() & mod.SetCounts(),
|
||||
ModOptionChangeType.GroupMoved => false,
|
||||
ModOptionChangeType.GroupTypeChanged => mod.HasOptions = mod.Groups.Any(o => o.IsOption),
|
||||
ModOptionChangeType.PriorityChanged => false,
|
||||
ModOptionChangeType.OptionAdded => ComputeChangedItems() & mod.SetCounts(),
|
||||
ModOptionChangeType.OptionDeleted => ComputeChangedItems() & mod.SetCounts(),
|
||||
ModOptionChangeType.OptionMoved => false,
|
||||
ModOptionChangeType.OptionFilesChanged => ComputeChangedItems()
|
||||
& (0 < (mod.TotalFileCount = mod.AllSubMods.Sum(s => s.Files.Count))),
|
||||
ModOptionChangeType.OptionSwapsChanged => ComputeChangedItems()
|
||||
& (0 < (mod.TotalSwapCount = mod.AllSubMods.Sum(s => s.FileSwaps.Count))),
|
||||
ModOptionChangeType.OptionMetaChanged => ComputeChangedItems()
|
||||
& (0 < (mod.TotalManipulations = mod.AllSubMods.Sum(s => s.Manipulations.Count))),
|
||||
ModOptionChangeType.DisplayChange => false,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ public class ModCacheManager : IDisposable, IReadOnlyList<ModCache>
|
|||
|
||||
private readonly List<ModCache> _cache = new();
|
||||
|
||||
// TODO ModManager2
|
||||
public ModCacheManager(CommunicatorService communicator, IdentifierService identifier, ModManager modManager)
|
||||
{
|
||||
_communicator = communicator;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace Penumbra.Mods;
|
|||
|
||||
public sealed class ModFileSystem : FileSystem<Mod>, IDisposable, ISavable
|
||||
{
|
||||
private readonly ModManager _modManager;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly FilenameService _files;
|
||||
|
||||
|
|
@ -23,17 +23,17 @@ public sealed class ModFileSystem : FileSystem<Mod>, IDisposable, ISavable
|
|||
_communicator = communicator;
|
||||
_files = files;
|
||||
Reload();
|
||||
Changed += OnChange;
|
||||
_modManager.ModDiscoveryFinished += Reload;
|
||||
_communicator.ModDataChanged.Event += OnDataChange;
|
||||
_modManager.ModPathChanged += OnModPathChange;
|
||||
Changed += OnChange;
|
||||
_communicator.ModDiscoveryFinished.Event += Reload;
|
||||
_communicator.ModDataChanged.Event += OnDataChange;
|
||||
_communicator.ModPathChanged.Event += OnModPathChange;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_modManager.ModPathChanged -= OnModPathChange;
|
||||
_modManager.ModDiscoveryFinished -= Reload;
|
||||
_communicator.ModDataChanged.Event -= OnDataChange;
|
||||
_communicator.ModPathChanged.Event -= OnModPathChange;
|
||||
_communicator.ModDiscoveryFinished.Event -= Reload;
|
||||
_communicator.ModDataChanged.Event -= OnDataChange;
|
||||
}
|
||||
|
||||
public struct ImportDate : ISortMode<Mod>
|
||||
|
|
|
|||
|
|
@ -94,7 +94,8 @@ public class PenumbraNew
|
|||
.AddSingleton<ModOptionEditor>()
|
||||
.AddSingleton<ModManager>()
|
||||
.AddSingleton<ExportManager>()
|
||||
.AddSingleton<ModFileSystem>();
|
||||
.AddSingleton<ModFileSystem>()
|
||||
.AddSingleton<ModCacheManager>();
|
||||
|
||||
// Add Resource services
|
||||
services.AddSingleton<ResourceLoader>()
|
||||
|
|
@ -150,8 +151,7 @@ public class PenumbraNew
|
|||
.AddSingleton<ModMetaEditor>()
|
||||
.AddSingleton<ModSwapEditor>()
|
||||
.AddSingleton<ModNormalizer>()
|
||||
.AddSingleton<ModEditor>()
|
||||
.AddSingleton<ModCacheManager>();
|
||||
.AddSingleton<ModEditor>();
|
||||
|
||||
// Add API
|
||||
services.AddSingleton<PenumbraApi>()
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ public class ConfigMigrationService
|
|||
if (_config.Version != 4)
|
||||
return;
|
||||
|
||||
ModManager.MigrateModBackups = true;
|
||||
ModBackup.MigrateModBackups = true;
|
||||
_config.Version = 5;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -270,9 +270,9 @@ public class ItemSwapTab : IDisposable, ITab
|
|||
_modManager.DataEditor.CreateMeta(newDir, _newModName, _config.DefaultModAuthor, CreateDescription(), "1.0", string.Empty);
|
||||
Mod.Creator.CreateDefaultFiles(newDir);
|
||||
_modManager.AddMod(newDir);
|
||||
if (!_swapData.WriteMod(_modManager, _modManager.Last(),
|
||||
if (!_swapData.WriteMod(_modManager, _modManager[^1],
|
||||
_useFileSwaps ? ItemSwapContainer.WriteType.UseSwaps : ItemSwapContainer.WriteType.NoSwaps))
|
||||
_modManager.DeleteMod(_modManager.Count - 1);
|
||||
_modManager.DeleteMod(_modManager[^1]);
|
||||
}
|
||||
|
||||
private void CreateOption()
|
||||
|
|
|
|||
|
|
@ -9,23 +9,22 @@ using Dalamud.Interface.ImGuiFileDialog;
|
|||
using Dalamud.Utility;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Services;
|
||||
|
||||
namespace Penumbra.UI;
|
||||
|
||||
public class FileDialogService : IDisposable
|
||||
{
|
||||
private readonly ModManager _mods;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly FileDialogManager _manager;
|
||||
private readonly ConcurrentDictionary<string, string> _startPaths = new();
|
||||
private bool _isOpen;
|
||||
|
||||
public FileDialogService(ModManager mods, Configuration config)
|
||||
public FileDialogService(CommunicatorService communicator, Configuration config)
|
||||
{
|
||||
_mods = mods;
|
||||
_manager = SetupFileManager(config.ModDirectory);
|
||||
|
||||
_mods.ModDirectoryChanged += OnModDirectoryChange;
|
||||
_communicator = communicator;
|
||||
_manager = SetupFileManager(config.ModDirectory);
|
||||
_communicator.ModDirectoryChanged.Event += OnModDirectoryChange;
|
||||
}
|
||||
|
||||
public void OpenFilePicker(string title, string filters, Action<bool, List<string>> callback, int selectionCountMax, string? startPath,
|
||||
|
|
@ -72,7 +71,7 @@ public class FileDialogService : IDisposable
|
|||
{
|
||||
_startPaths.Clear();
|
||||
_manager.Reset();
|
||||
_mods.ModDirectoryChanged -= OnModDirectoryChange;
|
||||
_communicator.ModDirectoryChanged.Event -= OnModDirectoryChange;
|
||||
}
|
||||
|
||||
private string? GetStartPath(string title, string? startPath, bool forceStartPath)
|
||||
|
|
@ -87,7 +86,7 @@ public class FileDialogService : IDisposable
|
|||
{
|
||||
return (valid, list) =>
|
||||
{
|
||||
_isOpen = false;
|
||||
_isOpen = false;
|
||||
var loc = HandleRoot(GetCurrentLocation());
|
||||
_startPaths[title] = loc;
|
||||
callback(valid, list.Select(HandleRoot).ToList());
|
||||
|
|
|
|||
|
|
@ -25,20 +25,20 @@ namespace Penumbra.UI.ModsTab;
|
|||
|
||||
public sealed partial class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSystemSelector.ModState>
|
||||
{
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly ChatService _chat;
|
||||
private readonly Configuration _config;
|
||||
private readonly FileDialogService _fileDialog;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly CollectionManager _collectionManager;
|
||||
private readonly TutorialService _tutorial;
|
||||
private readonly ModEditor _modEditor;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly ChatService _chat;
|
||||
private readonly Configuration _config;
|
||||
private readonly FileDialogService _fileDialog;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly CollectionManager _collectionManager;
|
||||
private readonly TutorialService _tutorial;
|
||||
private readonly ModEditor _modEditor;
|
||||
|
||||
private TexToolsImporter? _import;
|
||||
public ModSettings SelectedSettings { get; private set; } = ModSettings.Empty;
|
||||
public ModCollection SelectedSettingCollection { get; private set; } = ModCollection.Empty;
|
||||
|
||||
private uint _infoPopupId = 0;
|
||||
private uint _infoPopupId = 0;
|
||||
|
||||
public ModFileSystemSelector(CommunicatorService communicator, ModFileSystem fileSystem, ModManager modManager,
|
||||
CollectionManager collectionManager, Configuration config, TutorialService tutorial, FileDialogService fileDialog, ChatService chat,
|
||||
|
|
@ -81,16 +81,16 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector<Mod, ModF
|
|||
_collectionManager.Current.ModSettingChanged += OnSettingChange;
|
||||
_collectionManager.Current.InheritanceChanged += OnInheritanceChange;
|
||||
_communicator.ModDataChanged.Event += OnModDataChange;
|
||||
_modManager.ModDiscoveryStarted += StoreCurrentSelection;
|
||||
_modManager.ModDiscoveryFinished += RestoreLastSelection;
|
||||
_communicator.ModDiscoveryStarted.Event += StoreCurrentSelection;
|
||||
_communicator.ModDiscoveryFinished.Event += RestoreLastSelection;
|
||||
OnCollectionChange(CollectionType.Current, null, _collectionManager.Current, "");
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
_modManager.ModDiscoveryStarted -= StoreCurrentSelection;
|
||||
_modManager.ModDiscoveryFinished -= RestoreLastSelection;
|
||||
_communicator.ModDiscoveryStarted.Event -= StoreCurrentSelection;
|
||||
_communicator.ModDiscoveryFinished.Event -= RestoreLastSelection;
|
||||
_communicator.ModDataChanged.Event -= OnModDataChange;
|
||||
_collectionManager.Current.ModSettingChanged -= OnSettingChange;
|
||||
_collectionManager.Current.InheritanceChanged -= OnInheritanceChange;
|
||||
|
|
@ -258,8 +258,8 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector<Mod, ModF
|
|||
var size = new Vector2(width * 2, height);
|
||||
ImGui.SetNextWindowPos(ImGui.GetMainViewport().GetCenter(), ImGuiCond.Always, Vector2.One / 2);
|
||||
ImGui.SetNextWindowSize(size);
|
||||
var infoPopupId = ImGui.GetID("Import Status");
|
||||
using var popup = ImRaii.Popup("Import Status", ImGuiWindowFlags.Modal);
|
||||
var infoPopupId = ImGui.GetID("Import Status");
|
||||
using var popup = ImRaii.Popup("Import Status", ImGuiWindowFlags.Modal);
|
||||
if (_import == null || !popup.Success)
|
||||
return;
|
||||
|
||||
|
|
@ -320,7 +320,7 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector<Mod, ModF
|
|||
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), size, tt, SelectedLeaf == null || !keys, true)
|
||||
&& Selected != null)
|
||||
_modManager.DeleteMod(Selected.Index);
|
||||
_modManager.DeleteMod(Selected);
|
||||
}
|
||||
|
||||
private void AddHelpButton(Vector2 size)
|
||||
|
|
@ -336,7 +336,7 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector<Mod, ModF
|
|||
var mods = folder.GetAllDescendants(ISortMode<Mod>.Lexicographical).OfType<ModFileSystem.Leaf>().Select(l =>
|
||||
{
|
||||
// Any mod handled here should not stay new.
|
||||
_modManager.NewMods.Remove(l.Value);
|
||||
_modManager.SetKnown(l.Value);
|
||||
return l.Value;
|
||||
});
|
||||
|
||||
|
|
@ -428,7 +428,7 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector<Mod, ModF
|
|||
}
|
||||
|
||||
private static void HandleException(Exception e)
|
||||
=> Penumbra.ChatService.NotificationMessage(e.Message, "Failure", NotificationType.Warning);
|
||||
=> Penumbra.ChatService.NotificationMessage(e.Message, "Failure", NotificationType.Warning);
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -618,7 +618,7 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector<Mod, ModF
|
|||
/// <summary> Only get the text color for a mod if no filters are set. </summary>
|
||||
private ColorId GetTextColor(Mod mod, ModSettings? settings, ModCollection collection)
|
||||
{
|
||||
if (Penumbra.ModManager.NewMods.Contains(mod))
|
||||
if (_modManager.IsNew(mod))
|
||||
return ColorId.NewMod;
|
||||
|
||||
if (settings == null)
|
||||
|
|
@ -638,7 +638,7 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector<Mod, ModF
|
|||
|
||||
private bool CheckStateFilters(Mod mod, ModSettings? settings, ModCollection collection, ref ModState state)
|
||||
{
|
||||
var isNew = _modManager.NewMods.Contains(mod);
|
||||
var isNew = _modManager.IsNew(mod);
|
||||
// Handle mod details.
|
||||
if (CheckFlags(mod.TotalFileCount, ModFilter.HasNoFiles, ModFilter.HasFiles)
|
||||
|| CheckFlags(mod.TotalSwapCount, ModFilter.HasNoFileSwaps, ModFilter.HasFileSwaps)
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ public class ModPanelEditTab : ITab
|
|||
if (ImGuiUtil.DrawDisabledButton("Reload Mod", buttonSize, "Reload the current mod from its files.\n"
|
||||
+ "If the mod directory or meta file do not exist anymore or if the new mod name is empty, the mod is deleted instead.",
|
||||
false))
|
||||
_modManager.ReloadMod(_mod.Index);
|
||||
_modManager.ReloadMod(_mod);
|
||||
|
||||
BackupButtons(buttonSize);
|
||||
MoveDirectory.Draw(_modManager, _mod, buttonSize);
|
||||
|
|
@ -255,13 +255,13 @@ public class ModPanelEditTab : ITab
|
|||
/// <summary> A text input for the new directory name and a button to apply the move. </summary>
|
||||
private static class MoveDirectory
|
||||
{
|
||||
private static string? _currentModDirectory;
|
||||
private static ModManager.NewDirectoryState _state = ModManager.NewDirectoryState.Identical;
|
||||
private static string? _currentModDirectory;
|
||||
private static NewDirectoryState _state = NewDirectoryState.Identical;
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
_currentModDirectory = null;
|
||||
_state = ModManager.NewDirectoryState.Identical;
|
||||
_state = NewDirectoryState.Identical;
|
||||
}
|
||||
|
||||
public static void Draw(ModManager modManager, Mod mod, Vector2 buttonSize)
|
||||
|
|
@ -276,20 +276,20 @@ public class ModPanelEditTab : ITab
|
|||
|
||||
var (disabled, tt) = _state switch
|
||||
{
|
||||
ModManager.NewDirectoryState.Identical => (true, "Current directory name is identical to new one."),
|
||||
ModManager.NewDirectoryState.Empty => (true, "Please enter a new directory name first."),
|
||||
ModManager.NewDirectoryState.NonExisting => (false, $"Move mod from {mod.ModPath.Name} to {_currentModDirectory}."),
|
||||
ModManager.NewDirectoryState.ExistsEmpty => (false, $"Move mod from {mod.ModPath.Name} to {_currentModDirectory}."),
|
||||
ModManager.NewDirectoryState.ExistsNonEmpty => (true, $"{_currentModDirectory} already exists and is not empty."),
|
||||
ModManager.NewDirectoryState.ExistsAsFile => (true, $"{_currentModDirectory} exists as a file."),
|
||||
ModManager.NewDirectoryState.ContainsInvalidSymbols => (true,
|
||||
NewDirectoryState.Identical => (true, "Current directory name is identical to new one."),
|
||||
NewDirectoryState.Empty => (true, "Please enter a new directory name first."),
|
||||
NewDirectoryState.NonExisting => (false, $"Move mod from {mod.ModPath.Name} to {_currentModDirectory}."),
|
||||
NewDirectoryState.ExistsEmpty => (false, $"Move mod from {mod.ModPath.Name} to {_currentModDirectory}."),
|
||||
NewDirectoryState.ExistsNonEmpty => (true, $"{_currentModDirectory} already exists and is not empty."),
|
||||
NewDirectoryState.ExistsAsFile => (true, $"{_currentModDirectory} exists as a file."),
|
||||
NewDirectoryState.ContainsInvalidSymbols => (true,
|
||||
$"{_currentModDirectory} contains invalid symbols for FFXIV."),
|
||||
_ => (true, "Unknown error."),
|
||||
};
|
||||
ImGui.SameLine();
|
||||
if (ImGuiUtil.DrawDisabledButton("Rename Mod Directory", buttonSize, tt, disabled) && _currentModDirectory != null)
|
||||
{
|
||||
modManager.MoveModDirectory(mod.Index, _currentModDirectory);
|
||||
modManager.MoveModDirectory(mod, _currentModDirectory);
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ public class ModPanelSettingsTab : ITab
|
|||
if (!ImGui.Checkbox("Enabled", ref enabled))
|
||||
return;
|
||||
|
||||
_modManager.NewMods.Remove(_selector.Selected!);
|
||||
_modManager.SetKnown(_selector.Selected!);
|
||||
_collectionManager.Current.SetModState(_selector.Selected!.Index, enabled);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue