mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-02-21 07:17:53 +01:00
Tmp for Mod2
This commit is contained in:
parent
069ae772a5
commit
48e442a9fd
30 changed files with 697 additions and 252 deletions
77
Penumbra/Mods/Manager/Mod2.Manager.BasePath.cs
Normal file
77
Penumbra/Mods/Manager/Mod2.Manager.BasePath.cs
Normal 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Penumbra/Mods/Manager/Mod2.Manager.FileSystem.cs
Normal file
12
Penumbra/Mods/Manager/Mod2.Manager.FileSystem.cs
Normal 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" );
|
||||
}
|
||||
}
|
||||
67
Penumbra/Mods/Manager/Mod2.Manager.Meta.cs
Normal file
67
Penumbra/Mods/Manager/Mod2.Manager.Meta.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
299
Penumbra/Mods/Manager/Mod2.Manager.Options.cs
Normal file
299
Penumbra/Mods/Manager/Mod2.Manager.Options.cs
Normal 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,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
91
Penumbra/Mods/Manager/Mod2.Manager.Root.cs
Normal file
91
Penumbra/Mods/Manager/Mod2.Manager.Root.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
35
Penumbra/Mods/Manager/Mod2.Manager.cs
Normal file
35
Penumbra/Mods/Manager/Mod2.Manager.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue