Change moddata to list.

This commit is contained in:
Ottermandias 2022-03-22 16:11:59 +01:00
parent 2cece9c422
commit 4a4d93baf3
4 changed files with 96 additions and 93 deletions

View file

@ -7,10 +7,8 @@ using System.Linq;
using System.Security.Cryptography;
using Dalamud.Logging;
using Penumbra.GameData.ByteString;
using Penumbra.GameData.Util;
using Penumbra.Importer;
using Penumbra.Mods;
using Penumbra.Util;
namespace Penumbra.Mod;
@ -62,8 +60,8 @@ public class ModCleanup
private static ModData CreateNewMod( DirectoryInfo newDir, string newSortOrder )
{
Penumbra.ModManager.AddMod( newDir );
var newMod = Penumbra.ModManager.Mods[ newDir.Name ];
var idx = Penumbra.ModManager.AddMod( newDir );
var newMod = Penumbra.ModManager.Mods[idx];
newMod.Move( newSortOrder );
newMod.ComputeChangedItems();
ModFileSystem.InvokeChange();

View file

@ -6,20 +6,36 @@ using Dalamud.Logging;
using Penumbra.GameData.ByteString;
using Penumbra.Meta;
using Penumbra.Mod;
using Penumbra.Util;
namespace Penumbra.Mods;
public enum ModChangeType
{
Added,
Removed,
Changed,
}
public delegate void ModChangeDelegate( ModChangeType type, int modIndex, ModData modData );
// The ModManager handles the basic mods installed to the mod directory.
// It also contains the CollectionManager that handles all collections.
public class ModManager
{
public DirectoryInfo BasePath { get; private set; } = null!;
public Dictionary< string, ModData > Mods { get; } = new();
private List< ModData > ModsInternal { get; init; } = new();
public IReadOnlyList< ModData > Mods
=> ModsInternal;
public ModFolder StructuredMods { get; } = ModFileSystem.Root;
public CollectionManager Collections { get; }
public event ModChangeDelegate? ModChange;
public bool Valid { get; private set; }
public Configuration Config
@ -38,7 +54,7 @@ public class ModManager
return;
}
if( !newPath.Any() )
if( newPath.Length == 0 )
{
Valid = false;
BasePath = new DirectoryInfo( "." );
@ -84,7 +100,7 @@ public class ModManager
{
mod.Move( path );
var fixedPath = mod.SortOrder.FullPath;
if( !fixedPath.Any() || string.Equals( fixedPath, mod.Meta.Name, StringComparison.InvariantCultureIgnoreCase ) )
if( fixedPath.Length == 0 || string.Equals( fixedPath, mod.Meta.Name, StringComparison.InvariantCultureIgnoreCase ) )
{
Config.ModSortOrder.Remove( mod.BasePath.Name );
return true;
@ -103,16 +119,16 @@ public class ModManager
{
var changes = false;
foreach( var kvp in Config.ModSortOrder.ToArray() )
foreach( var (folder, path) in Config.ModSortOrder.ToArray() )
{
if( kvp.Value.Any() && Mods.TryGetValue( kvp.Key, out var mod ) )
if( path.Length > 0 && ModsInternal.FindFirst( m => m.BasePath.Name == folder, out var mod ) )
{
changes |= SetSortOrderPath( mod, kvp.Value );
changes |= SetSortOrderPath( mod, path );
}
else if( removeOldPaths )
{
changes = true;
Config.ModSortOrder.Remove( kvp.Key );
Config.ModSortOrder.Remove( folder );
}
}
@ -124,7 +140,7 @@ public class ModManager
public void DiscoverMods()
{
Mods.Clear();
ModsInternal.Clear();
BasePath.Refresh();
StructuredMods.SubFolders.Clear();
@ -139,7 +155,7 @@ public class ModManager
continue;
}
Mods.Add( modFolder.Name, mod );
ModsInternal.Add( mod );
}
SetModStructure();
@ -151,8 +167,7 @@ public class ModManager
public void DeleteMod( DirectoryInfo modFolder )
{
modFolder.Refresh();
if( modFolder.Exists )
if( Directory.Exists( modFolder.FullName ) )
{
try
{
@ -162,22 +177,25 @@ public class ModManager
{
PluginLog.Error( $"Could not delete the mod {modFolder.Name}:\n{e}" );
}
}
if( Mods.TryGetValue( modFolder.Name, out var mod ) )
{
mod.SortOrder.ParentFolder.RemoveMod( mod );
Mods.Remove( modFolder.Name );
Collections.RemoveModFromCaches( modFolder );
}
var idx = ModsInternal.FindIndex( m => m.BasePath.Name == modFolder.Name );
if( idx >= 0 )
{
var mod = ModsInternal[ idx ];
mod.SortOrder.ParentFolder.RemoveMod( mod );
ModsInternal.RemoveAt( idx );
Collections.RemoveModFromCaches( modFolder );
ModChange?.Invoke( ModChangeType.Removed, idx, mod );
}
}
public bool AddMod( DirectoryInfo modFolder )
public int AddMod( DirectoryInfo modFolder )
{
var mod = ModData.LoadMod( StructuredMods, modFolder );
if( mod == null )
{
return false;
return -1;
}
if( Config.ModSortOrder.TryGetValue( mod.BasePath.Name, out var sortOrder ) )
@ -188,22 +206,24 @@ public class ModManager
}
}
if( Mods.ContainsKey( modFolder.Name ) )
if( ModsInternal.Any( m => m.BasePath.Name == modFolder.Name ) )
{
return false;
return -1;
}
Mods.Add( modFolder.Name, mod );
ModsInternal.Add( mod );
ModChange?.Invoke( ModChangeType.Added, ModsInternal.Count - 1, mod );
foreach( var collection in Collections.Collections.Values )
{
collection.AddMod( mod );
}
return true;
return ModsInternal.Count - 1;
}
public bool UpdateMod( ModData mod, bool reloadMeta = false, bool recomputeMeta = false, bool force = false )
public bool UpdateMod( int idx, bool reloadMeta = false, bool recomputeMeta = false, bool force = false )
{
var mod = Mods[ idx ];
var oldName = mod.Meta.Name;
var metaChanges = mod.Meta.RefreshFromFile( mod.MetaFile ) || force;
var fileChanges = mod.Resources.RefreshModFiles( mod.BasePath );
@ -242,60 +262,17 @@ public class ModManager
}
Collections.UpdateCollections( mod, metaChanges, fileChanges, nameChange, reloadMeta );
ModChange?.Invoke( ModChangeType.Changed, idx, mod );
return true;
}
public bool UpdateMod( ModData mod, bool reloadMeta = false, bool recomputeMeta = false, bool force = false )
=> UpdateMod( Mods.IndexOf( mod ), reloadMeta, recomputeMeta, force );
public FullPath? ResolveSwappedOrReplacementPath( Utf8GamePath gameResourcePath )
{
var ret = Collections.DefaultCollection.ResolveSwappedOrReplacementPath( gameResourcePath );
ret ??= Collections.ForcedCollection.ResolveSwappedOrReplacementPath( gameResourcePath );
return ret;
}
// private void FileSystemWatcherOnChanged( object sender, FileSystemEventArgs e )
// {
// #if DEBUG
// PluginLog.Verbose( "file changed: {FullPath}", e.FullPath );
// #endif
//
// if( _plugin.ImportInProgress )
// {
// return;
// }
//
// if( _plugin.Configuration.DisableFileSystemNotifications )
// {
// return;
// }
//
// var file = e.FullPath;
//
// if( !ResolvedFiles.Any( x => x.Value.FullName == file ) )
// {
// return;
// }
//
// PluginLog.Log( "a loaded file has been modified - file: {FullPath}", file );
// _plugin.GameUtils.ReloadPlayerResources();
// }
//
// private void FileSystemPasta()
// {
// haha spaghet
// _fileSystemWatcher?.Dispose();
// _fileSystemWatcher = new FileSystemWatcher( _basePath.FullName )
// {
// NotifyFilter = NotifyFilters.LastWrite |
// NotifyFilters.FileName |
// NotifyFilters.DirectoryName,
// IncludeSubdirectories = true,
// EnableRaisingEvents = true
// };
//
// _fileSystemWatcher.Changed += FileSystemWatcherOnChanged;
// _fileSystemWatcher.Created += FileSystemWatcherOnChanged;
// _fileSystemWatcher.Deleted += FileSystemWatcherOnChanged;
// _fileSystemWatcher.Renamed += FileSystemWatcherOnChanged;
// }
}

View file

@ -70,9 +70,6 @@ public static class ModManagerEditExtensions
}
}
manager.Mods.Remove( mod.BasePath.Name );
manager.Mods[ newDir.Name ] = mod;
var oldBasePath = mod.BasePath;
mod.BasePath = newDir;
mod.MetaFile = ModData.MetaFileInfo( newDir );

View file

@ -1,28 +1,16 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Penumbra.Util;
public static class ArrayExtensions
{
public static int IndexOf< T >( this T[] array, Predicate< T > match )
{
for( var i = 0; i < array.Length; ++i )
{
if( match( array[ i ] ) )
{
return i;
}
}
return -1;
}
public static int IndexOf< T >( this IList< T > array, Func< T, bool > predicate )
public static int IndexOf< T >( this IReadOnlyList< T > array, Predicate< T > predicate )
{
for( var i = 0; i < array.Count; ++i )
{
if( predicate.Invoke( array[ i ] ) )
if( predicate( array[ i ] ) )
{
return i;
}
@ -30,4 +18,47 @@ public static class ArrayExtensions
return -1;
}
public static int IndexOf< T >( this IReadOnlyList< T > array, T needle )
{
for( var i = 0; i < array.Count; ++i )
{
if( needle!.Equals( array[i] ) )
{
return i;
}
}
return -1;
}
public static bool FindFirst< T >( this IReadOnlyList< T > array, Predicate< T > predicate, [NotNullWhen( true )] out T? result )
{
foreach( var obj in array )
{
if( predicate( obj ) )
{
result = obj!;
return true;
}
}
result = default;
return false;
}
public static bool FindFirst< T >( this IReadOnlyList< T > array, T needle, [NotNullWhen( true )] out T? result ) where T : IEquatable< T >
{
foreach( var obj in array )
{
if( obj.Equals( needle ) )
{
result = obj!;
return true;
}
}
result = default;
return false;
}
}