Use external library for API interface and IPC.

This commit is contained in:
Ottermandias 2022-10-08 02:02:33 +02:00
parent b3f048bfe6
commit 918d5db6a6
69 changed files with 4026 additions and 1873 deletions

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using OtterGui;
using OtterGui.Filesystem;
using Penumbra.Api.Enums;
using Penumbra.GameData.ByteString;
using Penumbra.Meta.Manipulations;
using Penumbra.Util;
@ -16,7 +17,7 @@ public sealed partial class Mod
public delegate void ModOptionChangeDelegate( ModOptionChangeType type, Mod mod, int groupIdx, int optionIdx, int movedToIdx );
public event ModOptionChangeDelegate ModOptionChanged;
public void ChangeModGroupType( Mod mod, int groupIdx, SelectType type )
public void ChangeModGroupType( Mod mod, int groupIdx, GroupType type )
{
var group = mod._groups[ groupIdx ];
if( group.Type == type )
@ -61,7 +62,7 @@ public sealed partial class Mod
ModOptionChanged.Invoke( ModOptionChangeType.GroupRenamed, mod, groupIdx, -1, -1 );
}
public void AddModGroup( Mod mod, SelectType type, string newName )
public void AddModGroup( Mod mod, GroupType type, string newName )
{
if( !VerifyFileName( mod, null, newName, true ) )
{
@ -70,7 +71,7 @@ public sealed partial class Mod
var maxPriority = mod._groups.Count == 0 ? 0 : mod._groups.Max( o => o.Priority ) + 1;
mod._groups.Add( type == SelectType.Multi
mod._groups.Add( type == GroupType.Multi
? new MultiModGroup { Name = newName, Priority = maxPriority }
: new SingleModGroup { Name = newName, Priority = maxPriority } );
ModOptionChanged.Invoke( ModOptionChangeType.GroupAdded, mod, mod._groups.Count - 1, -1, -1 );

View file

@ -5,6 +5,7 @@ using System.Text;
using Dalamud.Utility;
using OtterGui.Classes;
using OtterGui.Filesystem;
using Penumbra.Api.Enums;
using Penumbra.GameData.ByteString;
using Penumbra.Import;
@ -62,12 +63,12 @@ public partial class Mod
}
// Create a file for an option group from given data.
internal static void CreateOptionGroup( DirectoryInfo baseFolder, SelectType type, string name,
internal static void CreateOptionGroup( DirectoryInfo baseFolder, GroupType type, string name,
int priority, int index, uint defaultSettings, string desc, IEnumerable< ISubMod > subMods )
{
switch( type )
{
case SelectType.Multi:
case GroupType.Multi:
{
var group = new MultiModGroup()
{
@ -80,7 +81,7 @@ public partial class Mod
IModGroup.Save( group, baseFolder, index );
break;
}
case SelectType.Single:
case GroupType.Single:
{
var group = new SingleModGroup()
{

View file

@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using Newtonsoft.Json.Linq;
using OtterGui;
using Penumbra.Api.Enums;
using Penumbra.GameData.ByteString;
using Penumbra.Meta.Manipulations;
@ -79,10 +80,10 @@ public partial class Mod
try
{
var json = JObject.Parse( File.ReadAllText( file.FullName ) );
switch( json[ nameof( Type ) ]?.ToObject< SelectType >() ?? SelectType.Single )
switch( json[ nameof( Type ) ]?.ToObject< GroupType >() ?? GroupType.Single )
{
case SelectType.Multi: return MultiModGroup.Load( mod, json, groupIdx );
case SelectType.Single: return SingleModGroup.Load( mod, json, groupIdx );
case GroupType.Multi: return MultiModGroup.Load( mod, json, groupIdx );
case GroupType.Single: return SingleModGroup.Load( mod, json, groupIdx );
}
}
catch( Exception e )

View file

@ -6,6 +6,7 @@ using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OtterGui;
using Penumbra.Api.Enums;
using Penumbra.GameData.ByteString;
namespace Penumbra.Mods;
@ -128,7 +129,7 @@ public sealed partial class Mod
switch( group.SelectionType )
{
case SelectType.Multi:
case GroupType.Multi:
var optionPriority = 0;
var newMultiGroup = new MultiModGroup()
@ -144,7 +145,7 @@ public sealed partial class Mod
}
break;
case SelectType.Single:
case GroupType.Single:
if( group.Options.Count == 1 )
{
AddFilesToSubMod( mod._default, mod.ModPath, group.Options[ 0 ], seenMetaFiles );
@ -209,7 +210,7 @@ public sealed partial class Mod
public string GroupName = string.Empty;
[JsonConverter( typeof( Newtonsoft.Json.Converters.StringEnumConverter ) )]
public SelectType SelectionType = SelectType.Single;
public GroupType SelectionType = GroupType.Single;
public List< OptionV0 > Options = new();

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@ -121,8 +122,7 @@ public sealed class ModFileSystem : FileSystem< Mod >, IDisposable
CreateLeaf( Root, name, mod );
break;
case ModPathChangeType.Deleted:
var leaf = Root.GetAllDescendants( ISortMode< Mod >.Lexicographical ).OfType< Leaf >().FirstOrDefault( l => l.Value == mod );
if( leaf != null )
if( FindLeaf( mod, out var leaf ) )
{
Delete( leaf );
}
@ -137,6 +137,16 @@ public sealed class ModFileSystem : FileSystem< Mod >, IDisposable
}
}
// Search the entire filesystem for the leaf corresponding to a mod.
public bool FindLeaf( Mod mod, [NotNullWhen( true )] out Leaf? leaf )
{
leaf = Root.GetAllDescendants( ISortMode< Mod >.Lexicographical )
.OfType< Leaf >()
.FirstOrDefault( l => l.Value == mod );
return leaf != null;
}
// Used for saving and loading.
private static string ModToIdentifier( Mod mod )
=> mod.ModPath.Name;
@ -144,15 +154,16 @@ public sealed class ModFileSystem : FileSystem< Mod >, IDisposable
private static string ModToName( Mod mod )
=> mod.Name.Text.FixName();
private static (string, bool) SaveMod( Mod mod, string fullPath )
// Return whether a mod has a custom path or is just a numbered default path.
public static bool ModHasDefaultPath( Mod mod, string fullPath )
{
var regex = new Regex( $@"^{Regex.Escape( ModToName( mod ) )}( \(\d+\))?$" );
// Only save pairs with non-default paths.
if( regex.IsMatch( fullPath ) )
{
return ( string.Empty, false );
}
return ( ModToIdentifier( mod ), true );
return regex.IsMatch( fullPath );
}
private static (string, bool) SaveMod( Mod mod, string fullPath )
// Only save pairs with non-default paths.
=> ModHasDefaultPath( mod, fullPath )
? ( string.Empty, false )
: ( ModToIdentifier( mod ), true );
}

View file

@ -3,22 +3,17 @@ using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using OtterGui.Filesystem;
using Penumbra.Api.Enums;
namespace Penumbra.Mods;
public enum SelectType
{
Single,
Multi,
}
public interface IModGroup : IEnumerable< ISubMod >
{
public const int MaxMultiOptions = 32;
public string Name { get; }
public string Description { get; }
public SelectType Type { get; }
public GroupType Type { get; }
public int Priority { get; }
public uint DefaultSettings { get; set; }
@ -31,8 +26,8 @@ public interface IModGroup : IEnumerable< ISubMod >
public bool IsOption
=> Type switch
{
SelectType.Single => Count > 1,
SelectType.Multi => Count > 0,
GroupType.Single => Count > 1,
GroupType.Multi => Count > 0,
_ => false,
};
@ -90,7 +85,7 @@ public interface IModGroup : IEnumerable< ISubMod >
j.WriteStartArray();
for( var idx = 0; idx < group.Count; ++idx )
{
ISubMod.WriteSubMod( j, serializer, group[ idx ], basePath, group.Type == SelectType.Multi ? group.OptionPriority( idx ) : null );
ISubMod.WriteSubMod( j, serializer, group[ idx ], basePath, group.Type == GroupType.Multi ? group.OptionPriority( idx ) : null );
}
j.WriteEndArray();
@ -98,7 +93,7 @@ public interface IModGroup : IEnumerable< ISubMod >
Penumbra.Log.Debug( $"Saved group file {file} for group {groupIdx + 1}: {group.Name}." );
}
public IModGroup Convert( SelectType type );
public IModGroup Convert( GroupType type );
public bool MoveOption( int optionIdxFrom, int optionIdxTo );
public void UpdatePositions( int from = 0 );
}

View file

@ -7,6 +7,7 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OtterGui;
using OtterGui.Filesystem;
using Penumbra.Api.Enums;
namespace Penumbra.Mods;
@ -15,8 +16,8 @@ public partial class Mod
// Groups that allow all available options to be selected at once.
private sealed class MultiModGroup : IModGroup
{
public SelectType Type
=> SelectType.Multi;
public GroupType Type
=> GroupType.Multi;
public string Name { get; set; } = "Group";
public string Description { get; set; } = "A non-exclusive group of settings.";
@ -79,12 +80,12 @@ public partial class Mod
return ret;
}
public IModGroup Convert( SelectType type )
public IModGroup Convert( GroupType type )
{
switch( type )
{
case SelectType.Multi: return this;
case SelectType.Single:
case GroupType.Multi: return this;
case GroupType.Single:
var multi = new SingleModGroup()
{
Name = Name,

View file

@ -6,6 +6,7 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OtterGui;
using OtterGui.Filesystem;
using Penumbra.Api.Enums;
namespace Penumbra.Mods;
@ -14,8 +15,8 @@ public partial class Mod
// Groups that allow only one of their available options to be selected.
private sealed class SingleModGroup : IModGroup
{
public SelectType Type
=> SelectType.Single;
public GroupType Type
=> GroupType.Single;
public string Name { get; set; } = "Option";
public string Description { get; set; } = "A mutually exclusive group of settings.";
@ -72,12 +73,12 @@ public partial class Mod
return ret;
}
public IModGroup Convert( SelectType type )
public IModGroup Convert( GroupType type )
{
switch( type )
{
case SelectType.Single: return this;
case SelectType.Multi:
case GroupType.Single: return this;
case GroupType.Multi:
var multi = new MultiModGroup()
{
Name = Name,

View file

@ -4,6 +4,7 @@ using System.Linq;
using System.Numerics;
using OtterGui;
using OtterGui.Filesystem;
using Penumbra.Api.Enums;
namespace Penumbra.Mods;
@ -56,8 +57,8 @@ public class ModSettings
var config = Settings[ groupIdx ];
Settings[ groupIdx ] = group.Type switch
{
SelectType.Single => ( uint )Math.Max( Math.Min( group.Count - 1, BitOperations.TrailingZeroCount( config ) ), 0 ),
SelectType.Multi => 1u << ( int )config,
GroupType.Single => ( uint )Math.Max( Math.Min( group.Count - 1, BitOperations.TrailingZeroCount( config ) ), 0 ),
GroupType.Multi => 1u << ( int )config,
_ => config,
};
return config != Settings[ groupIdx ];
@ -70,8 +71,8 @@ public class ModSettings
var config = Settings[ groupIdx ];
Settings[ groupIdx ] = group.Type switch
{
SelectType.Single => config >= optionIdx ? config > 1 ? config - 1 : 0 : config,
SelectType.Multi => Functions.RemoveBit( config, optionIdx ),
GroupType.Single => config >= optionIdx ? config > 1 ? config - 1 : 0 : config,
GroupType.Multi => Functions.RemoveBit( config, optionIdx ),
_ => config,
};
return config != Settings[ groupIdx ];
@ -87,8 +88,8 @@ public class ModSettings
var config = Settings[ groupIdx ];
Settings[ groupIdx ] = group.Type switch
{
SelectType.Single => config == optionIdx ? ( uint )movedToIdx : config,
SelectType.Multi => Functions.MoveBit( config, optionIdx, movedToIdx ),
GroupType.Single => config == optionIdx ? ( uint )movedToIdx : config,
GroupType.Multi => Functions.MoveBit( config, optionIdx, movedToIdx ),
_ => config,
};
return config != Settings[ groupIdx ];
@ -101,8 +102,8 @@ public class ModSettings
private static uint FixSetting( IModGroup group, uint value )
=> group.Type switch
{
SelectType.Single => ( uint )Math.Min( value, group.Count - 1 ),
SelectType.Multi => ( uint )( value & ( ( 1ul << group.Count ) - 1 ) ),
GroupType.Single => ( uint )Math.Min( value, group.Count - 1 ),
GroupType.Multi => ( uint )( value & ( ( 1ul << group.Count ) - 1 ) ),
_ => value,
};
@ -202,7 +203,7 @@ public class ModSettings
}
var group = mod.Groups[ idx ];
if( group.Type == SelectType.Single && setting < group.Count )
if( group.Type == GroupType.Single && setting < group.Count )
{
dict.Add( group.Name, new[] { group[ ( int )setting ].Name } );
}