Tmp for Mod2

This commit is contained in:
Ottermandias 2022-04-09 16:29:20 +02:00
parent 069ae772a5
commit 48e442a9fd
30 changed files with 697 additions and 252 deletions

View file

@ -0,0 +1,77 @@
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

@ -0,0 +1,12 @@
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" );
}
}

View file

@ -0,0 +1,67 @@
using System;
namespace Penumbra.Mods;
public sealed partial class Mod2
{
public partial class Manager
{
public delegate void ModMetaChangeDelegate( MetaChangeType type, Mod2 mod );
public event ModMetaChangeDelegate? ModMetaChanged;
public void ChangeModName( Index idx, string newName )
{
var mod = this[ idx ];
if( mod.Name != newName )
{
mod.Name = newName;
mod.SaveMeta();
ModMetaChanged?.Invoke( MetaChangeType.Name, mod );
}
}
public void ChangeModAuthor( Index idx, string newAuthor )
{
var mod = this[ idx ];
if( mod.Author != newAuthor )
{
mod.Author = newAuthor;
mod.SaveMeta();
ModMetaChanged?.Invoke( MetaChangeType.Author, mod );
}
}
public void ChangeModDescription( Index idx, string newDescription )
{
var mod = this[ idx ];
if( mod.Description != newDescription )
{
mod.Description = newDescription;
mod.SaveMeta();
ModMetaChanged?.Invoke( MetaChangeType.Description, mod );
}
}
public void ChangeModVersion( Index idx, string newVersion )
{
var mod = this[ idx ];
if( mod.Version != newVersion )
{
mod.Version = newVersion;
mod.SaveMeta();
ModMetaChanged?.Invoke( MetaChangeType.Version, mod );
}
}
public void ChangeModWebsite( Index idx, string newWebsite )
{
var mod = this[ idx ];
if( mod.Website != newWebsite )
{
mod.Website = newWebsite;
mod.SaveMeta();
ModMetaChanged?.Invoke( MetaChangeType.Website, mod );
}
}
}
}

View file

@ -0,0 +1,299 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Dalamud.Logging;
using Penumbra.GameData.ByteString;
using Penumbra.Meta.Manipulations;
using Penumbra.Util;
namespace Penumbra.Mods;
public enum ModOptionChangeType
{
GroupRenamed,
GroupAdded,
GroupDeleted,
PriorityChanged,
OptionAdded,
OptionDeleted,
OptionChanged,
DisplayChange,
}
public sealed partial class Mod2
{
public sealed partial class Manager
{
public delegate void ModOptionChangeDelegate( ModOptionChangeType type, Mod2 mod, int groupIdx, int optionIdx );
public event ModOptionChangeDelegate ModOptionChanged;
public void RenameModGroup( Mod2 mod, int groupIdx, string newName )
{
var group = mod._groups[ groupIdx ];
var oldName = group.Name;
if( oldName == newName || !VerifyFileName( mod, group, newName ) )
{
return;
}
var _ = group switch
{
SingleModGroup s => s.Name = newName,
MultiModGroup m => m.Name = newName,
_ => newName,
};
ModOptionChanged.Invoke( ModOptionChangeType.GroupRenamed, mod, groupIdx, 0 );
}
public void AddModGroup( Mod2 mod, SelectType type, string newName )
{
if( !VerifyFileName( mod, null, newName ) )
{
return;
}
var maxPriority = 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 );
}
public void DeleteModGroup( Mod2 mod, int groupIdx )
{
var group = mod._groups[ groupIdx ];
mod._groups.RemoveAt( groupIdx );
group.DeleteFile( BasePath );
ModOptionChanged.Invoke( ModOptionChangeType.GroupDeleted, mod, groupIdx, 0 );
}
public void ChangeGroupDescription( Mod2 mod, int groupIdx, string newDescription )
{
var group = mod._groups[ groupIdx ];
if( group.Description == newDescription )
{
return;
}
var _ = group switch
{
SingleModGroup s => s.Description = newDescription,
MultiModGroup m => m.Description = newDescription,
_ => newDescription,
};
ModOptionChanged.Invoke( ModOptionChangeType.DisplayChange, mod, groupIdx, 0 );
}
public void ChangeGroupPriority( Mod2 mod, int groupIdx, int newPriority )
{
var group = mod._groups[ groupIdx ];
if( group.Priority == newPriority )
{
return;
}
var _ = group switch
{
SingleModGroup s => s.Priority = newPriority,
MultiModGroup m => m.Priority = newPriority,
_ => newPriority,
};
ModOptionChanged.Invoke( ModOptionChangeType.PriorityChanged, mod, groupIdx, -1 );
}
public void ChangeOptionPriority( Mod2 mod, int groupIdx, int optionIdx, int newPriority )
{
switch( mod._groups[ groupIdx ] )
{
case SingleModGroup s:
ChangeGroupPriority( mod, groupIdx, newPriority );
break;
case MultiModGroup m:
if( m.PrioritizedOptions[ optionIdx ].Priority == newPriority )
{
return;
}
m.PrioritizedOptions[ optionIdx ] = ( m.PrioritizedOptions[ optionIdx ].Mod, newPriority );
ModOptionChanged.Invoke( ModOptionChangeType.PriorityChanged, mod, groupIdx, optionIdx );
return;
}
}
public void RenameOption( Mod2 mod, int groupIdx, int optionIdx, string newName )
{
switch( mod._groups[ groupIdx ] )
{
case SingleModGroup s:
if( s.OptionData[ optionIdx ].Name == newName )
{
return;
}
s.OptionData[ optionIdx ].Name = newName;
break;
case MultiModGroup m:
var option = m.PrioritizedOptions[ optionIdx ].Mod;
if( option.Name == newName )
{
return;
}
option.Name = newName;
return;
}
ModOptionChanged.Invoke( ModOptionChangeType.DisplayChange, mod, groupIdx, optionIdx );
}
public void AddOption( Mod2 mod, int groupIdx, string newName )
{
switch( mod._groups[ groupIdx ] )
{
case SingleModGroup s:
s.OptionData.Add( new SubMod { Name = newName } );
break;
case MultiModGroup m:
m.PrioritizedOptions.Add( ( new SubMod { Name = newName }, 0 ) );
break;
}
ModOptionChanged.Invoke( ModOptionChangeType.OptionAdded, mod, groupIdx, mod._groups[ groupIdx ].Count - 1 );
}
public void DeleteOption( Mod2 mod, int groupIdx, int optionIdx )
{
switch( mod._groups[ groupIdx ] )
{
case SingleModGroup s:
s.OptionData.RemoveAt( optionIdx );
break;
case MultiModGroup m:
m.PrioritizedOptions.RemoveAt( optionIdx );
break;
}
ModOptionChanged.Invoke( ModOptionChangeType.OptionDeleted, mod, groupIdx, optionIdx );
}
public void OptionSetManipulation( Mod2 mod, int groupIdx, int optionIdx, MetaManipulation manip, bool delete = false )
{
var subMod = GetSubMod( mod, groupIdx, optionIdx );
if( delete )
{
if( !subMod.ManipulationData.Remove( manip ) )
{
return;
}
}
else
{
if( subMod.ManipulationData.TryGetValue( manip, out var oldManip ) )
{
if( manip.EntryEquals( oldManip ) )
{
return;
}
subMod.ManipulationData.Remove( oldManip );
subMod.ManipulationData.Add( manip );
}
else
{
subMod.ManipulationData.Add( manip );
}
}
ModOptionChanged.Invoke( ModOptionChangeType.OptionChanged, mod, groupIdx, optionIdx );
}
public void OptionSetFile( Mod2 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 );
}
}
public void OptionSetFileSwap( Mod2 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 );
}
}
private bool VerifyFileName( Mod2 mod, IModGroup? group, string newName )
{
var path = newName.RemoveInvalidPathSymbols();
if( 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." );
return false;
}
return true;
}
private static SubMod GetSubMod( Mod2 mod, int groupIdx, int optionIdx )
{
return mod._groups[ groupIdx ] switch
{
SingleModGroup s => s.OptionData[ optionIdx ],
MultiModGroup m => m.PrioritizedOptions[ optionIdx ].Mod,
_ => throw new InvalidOperationException(),
};
}
private static bool OptionSetFile( IDictionary< Utf8GamePath, FullPath > dict, Utf8GamePath gamePath, FullPath? newPath )
{
if( dict.TryGetValue( gamePath, out var oldPath ) )
{
if( newPath == null )
{
dict.Remove( gamePath );
return true;
}
if( newPath.Value.Equals( oldPath ) )
{
return false;
}
dict[ gamePath ] = newPath.Value;
return true;
}
if( newPath == null )
{
return false;
}
dict.Add( gamePath, newPath.Value );
return true;
}
private static void OnModOptionChange( ModOptionChangeType type, Mod2 mod, int groupIdx, int _ )
{
// File deletion is handled in the actual function.
if( type != ModOptionChangeType.GroupDeleted )
{
IModGroup.SaveModGroup( mod._groups[ groupIdx ], mod.BasePath );
}
// 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,
};
}
}
}

View file

@ -0,0 +1,91 @@
using System;
using System.IO;
using Dalamud.Logging;
namespace Penumbra.Mods;
public sealed partial class Mod2
{
public sealed partial class Manager
{
public DirectoryInfo BasePath { get; private set; } = null!;
public bool Valid { get; private set; }
public event Action? ModDiscoveryStarted;
public event Action? ModDiscoveryFinished;
public void DiscoverMods( string newDir )
{
SetBaseDirectory( newDir, false );
DiscoverMods();
}
private void SetBaseDirectory( string newPath, bool firstTime )
{
if( !firstTime && string.Equals( newPath, Penumbra.Config.ModDirectory, StringComparison.InvariantCultureIgnoreCase ) )
{
return;
}
if( newPath.Length == 0 )
{
Valid = false;
BasePath = new DirectoryInfo( "." );
}
else
{
var newDir = new DirectoryInfo( newPath );
if( !newDir.Exists )
{
try
{
Directory.CreateDirectory( newDir.FullName );
newDir.Refresh();
}
catch( Exception e )
{
PluginLog.Error( $"Could not create specified mod directory {newDir.FullName}:\n{e}" );
}
}
BasePath = newDir;
Valid = true;
if( Penumbra.Config.ModDirectory != BasePath.FullName )
{
Penumbra.Config.ModDirectory = BasePath.FullName;
Penumbra.Config.Save();
}
}
}
public void DiscoverMods()
{
ModDiscoveryStarted?.Invoke();
_mods.Clear();
BasePath.Refresh();
// TODO
//StructuredMods.SubFolders.Clear();
//StructuredMods.Mods.Clear();
if( Valid && BasePath.Exists )
{
foreach( var modFolder in BasePath.EnumerateDirectories() )
{
//var mod = LoadMod( StructuredMods, modFolder );
//if( mod == null )
//{
// continue;
//}
//
//mod.Index = _mods.Count;
//_mods.Add( mod );
}
//SetModStructure();
}
ModDiscoveryFinished?.Invoke();
}
}
}

View file

@ -0,0 +1,35 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Penumbra.Mods;
public sealed partial class Mod2
{
public sealed partial class Manager : IEnumerable< Mod2 >
{
private readonly List< Mod2 > _mods = new();
public Mod2 this[ Index idx ]
=> _mods[ idx ];
public IReadOnlyList< Mod2 > Mods
=> _mods;
public int Count
=> _mods.Count;
public IEnumerator< Mod2 > GetEnumerator()
=> _mods.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
public Manager( string modDirectory )
{
SetBaseDirectory( modDirectory, true );
ModOptionChanged += OnModOptionChange;
}
}
}