A lot of interface stuff, some more cleanup and fixes. Main functionality should be mostly fine, importing works. Missing a lot of mod edit options.

This commit is contained in:
Ottermandias 2022-04-26 21:35:09 +02:00
parent 8dd681bdda
commit dbb9931189
77 changed files with 3332 additions and 2066 deletions

View file

@ -0,0 +1,65 @@
using System;
using System.IO;
using System.Linq;
using Dalamud.Logging;
namespace Penumbra.Mods;
public partial class Mod
{
public partial class Manager
{
public delegate void ModPathChangeDelegate( ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
DirectoryInfo? newDirectory );
public event ModPathChangeDelegate? ModPathChanged;
public void MoveModDirectory( Index idx, DirectoryInfo newDirectory )
{
var mod = this[ idx ];
// TODO
}
public void DeleteMod( int idx )
{
var mod = this[ idx ];
if( Directory.Exists( mod.BasePath.FullName ) )
{
try
{
Directory.Delete( mod.BasePath.FullName, true );
}
catch( Exception e )
{
PluginLog.Error( $"Could not delete the mod {mod.BasePath.Name}:\n{e}" );
}
}
_mods.RemoveAt( idx );
foreach( var remainingMod in _mods.Skip( idx ) )
{
--remainingMod.Index;
}
ModPathChanged?.Invoke( ModPathChangeType.Deleted, mod, mod.BasePath, null );
}
public void AddMod( DirectoryInfo modFolder )
{
if( _mods.Any( m => m.BasePath.Name == modFolder.Name ) )
{
return;
}
var mod = LoadMod( modFolder );
if( mod == null )
{
return;
}
mod.Index = _mods.Count;
_mods.Add( mod );
ModPathChanged?.Invoke( ModPathChangeType.Added, mod, null, mod.BasePath );
}
}
}

View file

@ -2,11 +2,11 @@ using System;
namespace Penumbra.Mods;
public sealed partial class Mod2
public sealed partial class Mod
{
public partial class Manager
{
public delegate void ModMetaChangeDelegate( MetaChangeType type, Mod2 mod );
public delegate void ModMetaChangeDelegate( MetaChangeType type, Mod mod, string? oldName );
public event ModMetaChangeDelegate? ModMetaChanged;
public void ChangeModName( Index idx, string newName )
@ -14,9 +14,10 @@ public sealed partial class Mod2
var mod = this[ idx ];
if( mod.Name != newName )
{
var oldName = mod.Name;
mod.Name = newName;
mod.SaveMeta();
ModMetaChanged?.Invoke( MetaChangeType.Name, mod );
ModMetaChanged?.Invoke( MetaChangeType.Name, mod, oldName.Text );
}
}
@ -27,7 +28,7 @@ public sealed partial class Mod2
{
mod.Author = newAuthor;
mod.SaveMeta();
ModMetaChanged?.Invoke( MetaChangeType.Author, mod );
ModMetaChanged?.Invoke( MetaChangeType.Author, mod, null );
}
}
@ -38,7 +39,7 @@ public sealed partial class Mod2
{
mod.Description = newDescription;
mod.SaveMeta();
ModMetaChanged?.Invoke( MetaChangeType.Description, mod );
ModMetaChanged?.Invoke( MetaChangeType.Description, mod, null );
}
}
@ -49,7 +50,7 @@ public sealed partial class Mod2
{
mod.Version = newVersion;
mod.SaveMeta();
ModMetaChanged?.Invoke( MetaChangeType.Version, mod );
ModMetaChanged?.Invoke( MetaChangeType.Version, mod, null );
}
}
@ -60,7 +61,7 @@ public sealed partial class Mod2
{
mod.Website = newWebsite;
mod.SaveMeta();
ModMetaChanged?.Invoke( MetaChangeType.Website, mod );
ModMetaChanged?.Invoke( MetaChangeType.Website, mod, null );
}
}
}

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Dalamud.Logging;
using OtterGui.Filesystem;
using Penumbra.GameData.ByteString;
using Penumbra.Meta.Manipulations;
using Penumbra.Util;
@ -13,25 +14,43 @@ public enum ModOptionChangeType
GroupRenamed,
GroupAdded,
GroupDeleted,
GroupMoved,
GroupTypeChanged,
PriorityChanged,
OptionAdded,
OptionDeleted,
OptionChanged,
OptionMoved,
OptionFilesChanged,
OptionSwapsChanged,
OptionMetaChanged,
OptionUpdated,
DisplayChange,
}
public sealed partial class Mod2
public sealed partial class Mod
{
public sealed partial class Manager
{
public delegate void ModOptionChangeDelegate( ModOptionChangeType type, Mod2 mod, int groupIdx, int optionIdx );
public delegate void ModOptionChangeDelegate( ModOptionChangeType type, Mod mod, int groupIdx, int optionIdx, int movedToIdx );
public event ModOptionChangeDelegate ModOptionChanged;
public void RenameModGroup( Mod2 mod, int groupIdx, string newName )
public void ChangeModGroupType( Mod mod, int groupIdx, SelectType type )
{
var group = mod._groups[ groupIdx ];
if( group.Type == type )
{
return;
}
mod._groups[ groupIdx ] = group.Convert( type );
ModOptionChanged.Invoke( ModOptionChangeType.GroupTypeChanged, mod, groupIdx, -1, -1 );
}
public void RenameModGroup( Mod mod, int groupIdx, string newName )
{
var group = mod._groups[ groupIdx ];
var oldName = group.Name;
if( oldName == newName || !VerifyFileName( mod, group, newName ) )
if( oldName == newName || !VerifyFileName( mod, group, newName, true ) )
{
return;
}
@ -43,33 +62,41 @@ public sealed partial class Mod2
_ => newName,
};
ModOptionChanged.Invoke( ModOptionChangeType.GroupRenamed, mod, groupIdx, 0 );
ModOptionChanged.Invoke( ModOptionChangeType.GroupRenamed, mod, groupIdx, -1, -1 );
}
public void AddModGroup( Mod2 mod, SelectType type, string newName )
public void AddModGroup( Mod mod, SelectType type, string newName )
{
if( !VerifyFileName( mod, null, newName ) )
if( !VerifyFileName( mod, null, newName, true ) )
{
return;
}
var maxPriority = mod._groups.Max( o => o.Priority ) + 1;
var maxPriority = mod._groups.Count == 0 ? 0 : mod._groups.Max( o => o.Priority ) + 1;
mod._groups.Add( type == SelectType.Multi
? new MultiModGroup { Name = newName, Priority = maxPriority }
: new SingleModGroup { Name = newName, Priority = maxPriority } );
ModOptionChanged.Invoke( ModOptionChangeType.GroupAdded, mod, mod._groups.Count - 1, 0 );
ModOptionChanged.Invoke( ModOptionChangeType.GroupAdded, mod, mod._groups.Count - 1, -1, -1 );
}
public void DeleteModGroup( Mod2 mod, int groupIdx )
public void DeleteModGroup( Mod mod, int groupIdx )
{
var group = mod._groups[ groupIdx ];
mod._groups.RemoveAt( groupIdx );
group.DeleteFile( BasePath );
ModOptionChanged.Invoke( ModOptionChangeType.GroupDeleted, mod, groupIdx, 0 );
group.DeleteFile( mod.BasePath );
ModOptionChanged.Invoke( ModOptionChangeType.GroupDeleted, mod, groupIdx, -1, -1 );
}
public void ChangeGroupDescription( Mod2 mod, int groupIdx, string newDescription )
public void MoveModGroup( Mod mod, int groupIdxFrom, int groupIdxTo )
{
if( mod._groups.Move( groupIdxFrom, groupIdxTo ) )
{
ModOptionChanged.Invoke( ModOptionChangeType.GroupMoved, mod, groupIdxFrom, -1, groupIdxTo );
}
}
public void ChangeGroupDescription( Mod mod, int groupIdx, string newDescription )
{
var group = mod._groups[ groupIdx ];
if( group.Description == newDescription )
@ -83,10 +110,10 @@ public sealed partial class Mod2
MultiModGroup m => m.Description = newDescription,
_ => newDescription,
};
ModOptionChanged.Invoke( ModOptionChangeType.DisplayChange, mod, groupIdx, 0 );
ModOptionChanged.Invoke( ModOptionChangeType.DisplayChange, mod, groupIdx, -1, -1 );
}
public void ChangeGroupPriority( Mod2 mod, int groupIdx, int newPriority )
public void ChangeGroupPriority( Mod mod, int groupIdx, int newPriority )
{
var group = mod._groups[ groupIdx ];
if( group.Priority == newPriority )
@ -100,14 +127,14 @@ public sealed partial class Mod2
MultiModGroup m => m.Priority = newPriority,
_ => newPriority,
};
ModOptionChanged.Invoke( ModOptionChangeType.PriorityChanged, mod, groupIdx, -1 );
ModOptionChanged.Invoke( ModOptionChangeType.PriorityChanged, mod, groupIdx, -1, -1 );
}
public void ChangeOptionPriority( Mod2 mod, int groupIdx, int optionIdx, int newPriority )
public void ChangeOptionPriority( Mod mod, int groupIdx, int optionIdx, int newPriority )
{
switch( mod._groups[ groupIdx ] )
{
case SingleModGroup s:
case SingleModGroup:
ChangeGroupPriority( mod, groupIdx, newPriority );
break;
case MultiModGroup m:
@ -117,12 +144,12 @@ public sealed partial class Mod2
}
m.PrioritizedOptions[ optionIdx ] = ( m.PrioritizedOptions[ optionIdx ].Mod, newPriority );
ModOptionChanged.Invoke( ModOptionChangeType.PriorityChanged, mod, groupIdx, optionIdx );
ModOptionChanged.Invoke( ModOptionChangeType.PriorityChanged, mod, groupIdx, optionIdx, -1 );
return;
}
}
public void RenameOption( Mod2 mod, int groupIdx, int optionIdx, string newName )
public void RenameOption( Mod mod, int groupIdx, int optionIdx, string newName )
{
switch( mod._groups[ groupIdx ] )
{
@ -145,10 +172,10 @@ public sealed partial class Mod2
return;
}
ModOptionChanged.Invoke( ModOptionChangeType.DisplayChange, mod, groupIdx, optionIdx );
ModOptionChanged.Invoke( ModOptionChangeType.DisplayChange, mod, groupIdx, optionIdx, -1 );
}
public void AddOption( Mod2 mod, int groupIdx, string newName )
public void AddOption( Mod mod, int groupIdx, string newName )
{
switch( mod._groups[ groupIdx ] )
{
@ -160,10 +187,30 @@ public sealed partial class Mod2
break;
}
ModOptionChanged.Invoke( ModOptionChangeType.OptionAdded, mod, groupIdx, mod._groups[ groupIdx ].Count - 1 );
ModOptionChanged.Invoke( ModOptionChangeType.OptionAdded, mod, groupIdx, mod._groups[ groupIdx ].Count - 1, -1 );
}
public void DeleteOption( Mod2 mod, int groupIdx, int optionIdx )
public void AddOption( Mod mod, int groupIdx, ISubMod option, int priority = 0 )
{
if( option is not SubMod o )
{
return;
}
switch( mod._groups[ groupIdx ] )
{
case SingleModGroup s:
s.OptionData.Add( o );
break;
case MultiModGroup m:
m.PrioritizedOptions.Add( ( o, priority ) );
break;
}
ModOptionChanged.Invoke( ModOptionChangeType.OptionAdded, mod, groupIdx, mod._groups[ groupIdx ].Count - 1, -1 );
}
public void DeleteOption( Mod mod, int groupIdx, int optionIdx )
{
switch( mod._groups[ groupIdx ] )
{
@ -175,10 +222,19 @@ public sealed partial class Mod2
break;
}
ModOptionChanged.Invoke( ModOptionChangeType.OptionDeleted, mod, groupIdx, optionIdx );
ModOptionChanged.Invoke( ModOptionChangeType.OptionDeleted, mod, groupIdx, optionIdx, -1 );
}
public void OptionSetManipulation( Mod2 mod, int groupIdx, int optionIdx, MetaManipulation manip, bool delete = false )
public void MoveOption( Mod mod, int groupIdx, int optionIdxFrom, int optionIdxTo )
{
var group = mod._groups[ groupIdx ];
if( group.MoveOption( optionIdxFrom, optionIdxTo ) )
{
ModOptionChanged.Invoke( ModOptionChangeType.OptionMoved, mod, groupIdx, optionIdxFrom, optionIdxTo );
}
}
public void OptionSetManipulation( Mod mod, int groupIdx, int optionIdx, MetaManipulation manip, bool delete = false )
{
var subMod = GetSubMod( mod, groupIdx, optionIdx );
if( delete )
@ -206,41 +262,94 @@ public sealed partial class Mod2
}
}
ModOptionChanged.Invoke( ModOptionChangeType.OptionChanged, mod, groupIdx, optionIdx );
ModOptionChanged.Invoke( ModOptionChangeType.OptionMetaChanged, mod, groupIdx, optionIdx, -1 );
}
public void OptionSetFile( Mod2 mod, int groupIdx, int optionIdx, Utf8GamePath gamePath, FullPath? newPath )
public void OptionSetManipulations( Mod mod, int groupIdx, int optionIdx, HashSet< MetaManipulation > manipulations )
{
var subMod = GetSubMod( mod, groupIdx, optionIdx );
if( subMod.Manipulations.SetEquals( manipulations ) )
{
return;
}
subMod.ManipulationData.Clear();
subMod.ManipulationData.UnionWith( manipulations );
ModOptionChanged.Invoke( ModOptionChangeType.OptionMetaChanged, mod, groupIdx, optionIdx, -1 );
}
public void OptionSetFile( Mod mod, int groupIdx, int optionIdx, Utf8GamePath gamePath, FullPath? newPath )
{
var subMod = GetSubMod( mod, groupIdx, optionIdx );
if( OptionSetFile( subMod.FileData, gamePath, newPath ) )
{
ModOptionChanged.Invoke( ModOptionChangeType.OptionChanged, mod, groupIdx, optionIdx );
ModOptionChanged.Invoke( ModOptionChangeType.OptionFilesChanged, mod, groupIdx, optionIdx, -1 );
}
}
public void OptionSetFileSwap( Mod2 mod, int groupIdx, int optionIdx, Utf8GamePath gamePath, FullPath? newPath )
public void OptionSetFiles( Mod mod, int groupIdx, int optionIdx, Dictionary< Utf8GamePath, FullPath > replacements )
{
var subMod = GetSubMod( mod, groupIdx, optionIdx );
if( subMod.FileData.Equals( replacements ) )
{
return;
}
subMod.FileData.SetTo( replacements );
ModOptionChanged.Invoke( ModOptionChangeType.OptionFilesChanged, mod, groupIdx, optionIdx, -1 );
}
public void OptionSetFileSwap( Mod mod, int groupIdx, int optionIdx, Utf8GamePath gamePath, FullPath? newPath )
{
var subMod = GetSubMod( mod, groupIdx, optionIdx );
if( OptionSetFile( subMod.FileSwapData, gamePath, newPath ) )
{
ModOptionChanged.Invoke( ModOptionChangeType.OptionChanged, mod, groupIdx, optionIdx );
ModOptionChanged.Invoke( ModOptionChangeType.OptionSwapsChanged, mod, groupIdx, optionIdx, -1 );
}
}
private bool VerifyFileName( Mod2 mod, IModGroup? group, string newName )
public void OptionSetFileSwaps( Mod mod, int groupIdx, int optionIdx, Dictionary< Utf8GamePath, FullPath > swaps )
{
var subMod = GetSubMod( mod, groupIdx, optionIdx );
if( subMod.FileSwapData.Equals( swaps ) )
{
return;
}
subMod.FileSwapData.SetTo( swaps );
ModOptionChanged.Invoke( ModOptionChangeType.OptionSwapsChanged, mod, groupIdx, optionIdx, -1 );
}
public void OptionUpdate( Mod mod, int groupIdx, int optionIdx, Dictionary< Utf8GamePath, FullPath > replacements,
HashSet< MetaManipulation > manipulations, Dictionary< Utf8GamePath, FullPath > swaps )
{
var subMod = GetSubMod( mod, groupIdx, optionIdx );
subMod.FileData.SetTo( replacements );
subMod.ManipulationData.Clear();
subMod.ManipulationData.UnionWith( manipulations );
subMod.FileSwapData.SetTo( swaps );
ModOptionChanged.Invoke( ModOptionChangeType.OptionUpdated, mod, groupIdx, optionIdx, -1 );
}
public static bool VerifyFileName( Mod mod, IModGroup? group, string newName, bool message )
{
var path = newName.RemoveInvalidPathSymbols();
if( mod.Groups.Any( o => !ReferenceEquals( o, group )
if( path.Length == 0
|| mod.Groups.Any( o => !ReferenceEquals( o, group )
&& string.Equals( o.Name.RemoveInvalidPathSymbols(), path, StringComparison.InvariantCultureIgnoreCase ) ) )
{
PluginLog.Warning( $"Could not name option {newName} because option with same filename {path} already exists." );
if( message )
{
PluginLog.Warning( $"Could not name option {newName} because option with same filename {path} already exists." );
}
return false;
}
return true;
}
private static SubMod GetSubMod( Mod2 mod, int groupIdx, int optionIdx )
private static SubMod GetSubMod( Mod mod, int groupIdx, int optionIdx )
{
return mod._groups[ groupIdx ] switch
{
@ -278,7 +387,7 @@ public sealed partial class Mod2
return true;
}
private static void OnModOptionChange( ModOptionChangeType type, Mod2 mod, int groupIdx, int _ )
private static void OnModOptionChange( ModOptionChangeType type, Mod mod, int groupIdx, int _, int _2 )
{
// File deletion is handled in the actual function.
if( type != ModOptionChangeType.GroupDeleted )
@ -289,10 +398,11 @@ public sealed partial class Mod2
// State can not change on adding groups, as they have no immediate options.
mod.HasOptions = type switch
{
ModOptionChangeType.GroupDeleted => mod.HasOptions = mod.Groups.Any( o => o.IsOption ),
ModOptionChangeType.OptionAdded => mod.HasOptions |= mod._groups[ groupIdx ].IsOption,
ModOptionChangeType.OptionDeleted => mod.HasOptions = mod.Groups.Any( o => o.IsOption ),
_ => mod.HasOptions,
ModOptionChangeType.GroupDeleted => mod.HasOptions = mod.Groups.Any( o => o.IsOption ),
ModOptionChangeType.GroupTypeChanged => mod.HasOptions = mod.Groups.Any( o => o.IsOption ),
ModOptionChangeType.OptionAdded => mod.HasOptions |= mod._groups[ groupIdx ].IsOption,
ModOptionChangeType.OptionDeleted => mod.HasOptions = mod.Groups.Any( o => o.IsOption ),
_ => mod.HasOptions,
};
}
}

View file

@ -4,7 +4,7 @@ using Dalamud.Logging;
namespace Penumbra.Mods;
public sealed partial class Mod2
public sealed partial class Mod
{
public sealed partial class Manager
{
@ -50,7 +50,7 @@ public sealed partial class Mod2
}
BasePath = newDir;
Valid = true;
Valid = Directory.Exists( newDir.FullName );
if( Penumbra.Config.ModDirectory != BasePath.FullName )
{
Penumbra.Config.ModDirectory = BasePath.FullName;
@ -74,7 +74,7 @@ public sealed partial class Mod2
{
continue;
}
mod.Index = _mods.Count;
_mods.Add( mod );
}

View file

@ -4,22 +4,22 @@ using System.Collections.Generic;
namespace Penumbra.Mods;
public sealed partial class Mod2
public sealed partial class Mod
{
public sealed partial class Manager : IEnumerable< Mod2 >
public sealed partial class Manager : IEnumerable< Mod >
{
private readonly List< Mod2 > _mods = new();
private readonly List< Mod > _mods = new();
public Mod2 this[ Index idx ]
public Mod this[ Index idx ]
=> _mods[ idx ];
public IReadOnlyList< Mod2 > Mods
public IReadOnlyList< Mod > Mods
=> _mods;
public int Count
=> _mods.Count;
public IEnumerator< Mod2 > GetEnumerator()
public IEnumerator< Mod > GetEnumerator()
=> _mods.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()

View file

@ -1,77 +0,0 @@
using System;
using System.IO;
using Dalamud.Logging;
namespace Penumbra.Mods;
public partial class Mod2
{
public partial class Manager
{
public delegate void ModPathChangeDelegate( ModPathChangeType type, Mod2 mod, DirectoryInfo? oldDirectory,
DirectoryInfo? newDirectory );
public event ModPathChangeDelegate? ModPathChanged;
public void MoveModDirectory( Index idx, DirectoryInfo newDirectory )
{
var mod = this[ idx ];
// TODO
}
public void DeleteMod( Index idx )
{
var mod = this[ idx ];
if( Directory.Exists( mod.BasePath.FullName ) )
{
try
{
Directory.Delete( mod.BasePath.FullName, true );
}
catch( Exception e )
{
PluginLog.Error( $"Could not delete the mod {mod.BasePath.Name}:\n{e}" );
}
}
// TODO
// mod.Order.ParentFolder.RemoveMod( mod );
// _mods.RemoveAt( idx );
//for( var i = idx; i < _mods.Count; ++i )
//{
// --_mods[i].Index;
//}
ModPathChanged?.Invoke( ModPathChangeType.Deleted, mod, mod.BasePath, null );
}
public Mod2 AddMod( DirectoryInfo modFolder )
{
// TODO
//var mod = LoadMod( StructuredMods, modFolder );
//if( mod == null )
//{
// return -1;
//}
//
//if( Config.ModSortOrder.TryGetValue( mod.BasePath.Name, out var sortOrder ) )
//{
// if( SetSortOrderPath( mod, sortOrder ) )
// {
// Config.Save();
// }
//}
//
//if( _mods.Any( m => m.BasePath.Name == modFolder.Name ) )
//{
// return -1;
//}
//
//_mods.Add( mod );
//ModChange?.Invoke( ChangeType.Added, _mods.Count - 1, mod );
//
return this[^1];
}
}
}

View file

@ -1,12 +0,0 @@
using System.IO;
namespace Penumbra.Mods;
public sealed partial class Mod2
{
public sealed partial class Manager
{
public static string ModFileSystemFile
=> Path.Combine( Dalamud.PluginInterface.GetPluginConfigDirectory(), "sort_order.json" );
}
}