mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
Add date sort methods.
This commit is contained in:
parent
c975336e65
commit
ec91755065
9 changed files with 185 additions and 22 deletions
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
|||
Subproject commit 03934d3a19cb610898412045ad5ea7dad9766a59
|
||||
Subproject commit 8053b24bb6b77a13853455c08a89df4894b3f2ee
|
||||
|
|
@ -27,6 +27,7 @@ public partial class Configuration
|
|||
public Dictionary< string, string > ModSortOrder = new();
|
||||
public bool InvertModListOrder;
|
||||
public bool SortFoldersFirst;
|
||||
public SortModeV3 SortMode = SortModeV3.FoldersFirst;
|
||||
|
||||
public static void Migrate( Configuration config )
|
||||
{
|
||||
|
|
@ -45,6 +46,31 @@ public partial class Configuration
|
|||
m.Version0To1();
|
||||
m.Version1To2();
|
||||
m.Version2To3();
|
||||
m.Version3To4();
|
||||
}
|
||||
|
||||
// SortMode was changed from an enum to a type.
|
||||
private void Version3To4()
|
||||
{
|
||||
if( _config.Version != 3 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SortMode = _data[ nameof( SortMode ) ]?.ToObject< SortModeV3 >() ?? SortMode;
|
||||
_config.SortMode = SortMode switch
|
||||
{
|
||||
SortModeV3.FoldersFirst => ISortMode< Mod >.FoldersFirst,
|
||||
SortModeV3.Lexicographical => ISortMode< Mod >.Lexicographical,
|
||||
SortModeV3.InverseFoldersFirst => ISortMode< Mod >.InverseFoldersFirst,
|
||||
SortModeV3.InverseLexicographical => ISortMode< Mod >.InverseLexicographical,
|
||||
SortModeV3.FoldersLast => ISortMode< Mod >.FoldersLast,
|
||||
SortModeV3.InverseFoldersLast => ISortMode< Mod >.InverseFoldersLast,
|
||||
SortModeV3.InternalOrder => ISortMode< Mod >.InternalOrder,
|
||||
SortModeV3.InternalOrderInverse => ISortMode< Mod >.InverseInternalOrder,
|
||||
_ => ISortMode< Mod >.FoldersFirst,
|
||||
};
|
||||
_config.Version = 4;
|
||||
}
|
||||
|
||||
// SortFoldersFirst was changed from a bool to the enum SortMode.
|
||||
|
|
@ -56,7 +82,7 @@ public partial class Configuration
|
|||
}
|
||||
|
||||
SortFoldersFirst = _data[ nameof( SortFoldersFirst ) ]?.ToObject< bool >() ?? false;
|
||||
_config.SortMode = SortFoldersFirst ? SortMode.FoldersFirst : SortMode.Lexicographical;
|
||||
SortMode = SortFoldersFirst ? SortModeV3.FoldersFirst : SortModeV3.Lexicographical;
|
||||
_config.Version = 3;
|
||||
}
|
||||
|
||||
|
|
@ -242,5 +268,17 @@ public partial class Configuration
|
|||
PluginLog.Error( $"Could not create backup copy of config at {bakName}:\n{e}" );
|
||||
}
|
||||
}
|
||||
|
||||
public enum SortModeV3 : byte
|
||||
{
|
||||
FoldersFirst = 0x00,
|
||||
Lexicographical = 0x01,
|
||||
InverseFoldersFirst = 0x02,
|
||||
InverseLexicographical = 0x03,
|
||||
FoldersLast = 0x04,
|
||||
InverseFoldersLast = 0x05,
|
||||
InternalOrder = 0x06,
|
||||
InternalOrderInverse = 0x07,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Dalamud.Configuration;
|
||||
using Dalamud.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Import;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.UI.Classes;
|
||||
using Penumbra.Util;
|
||||
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
||||
|
||||
namespace Penumbra;
|
||||
|
||||
|
|
@ -40,8 +45,10 @@ public partial class Configuration : IPluginConfiguration
|
|||
public bool EnableResourceLogging { get; set; } = false;
|
||||
public string ResourceLoggingFilter { get; set; } = string.Empty;
|
||||
|
||||
[JsonConverter( typeof( SortModeConverter ) )]
|
||||
[JsonProperty( Order = int.MaxValue )]
|
||||
public ISortMode< Mod > SortMode = ISortMode< Mod >.FoldersFirst;
|
||||
|
||||
public SortMode SortMode { get; set; } = SortMode.FoldersFirst;
|
||||
public bool ScaleModSelector { get; set; } = false;
|
||||
public float ModSelectorAbsoluteSize { get; set; } = Constants.DefaultAbsoluteSize;
|
||||
public int ModSelectorScaledSize { get; set; } = Constants.DefaultScaledSize;
|
||||
|
|
@ -65,9 +72,25 @@ public partial class Configuration : IPluginConfiguration
|
|||
// Includes adding new colors and migrating from old versions.
|
||||
public static Configuration Load()
|
||||
{
|
||||
var iConfiguration = Dalamud.PluginInterface.GetPluginConfig();
|
||||
var configuration = iConfiguration as Configuration ?? new Configuration();
|
||||
if( iConfiguration is { Version: Constants.CurrentVersion } )
|
||||
void HandleDeserializationError( object? sender, ErrorEventArgs errorArgs )
|
||||
{
|
||||
PluginLog.Error(
|
||||
$"Error parsing Configuration at {errorArgs.ErrorContext.Path}, using default or migrating:\n{errorArgs.ErrorContext.Error}" );
|
||||
errorArgs.ErrorContext.Handled = true;
|
||||
}
|
||||
|
||||
Configuration? configuration = null;
|
||||
if( File.Exists( Dalamud.PluginInterface.ConfigFile.FullName ) )
|
||||
{
|
||||
var text = File.ReadAllText( Dalamud.PluginInterface.ConfigFile.FullName );
|
||||
configuration = JsonConvert.DeserializeObject< Configuration >( text, new JsonSerializerSettings
|
||||
{
|
||||
Error = HandleDeserializationError,
|
||||
} );
|
||||
}
|
||||
|
||||
configuration ??= new Configuration();
|
||||
if( configuration.Version == Constants.CurrentVersion )
|
||||
{
|
||||
configuration.AddColors( false );
|
||||
return configuration;
|
||||
|
|
@ -84,7 +107,8 @@ public partial class Configuration : IPluginConfiguration
|
|||
{
|
||||
try
|
||||
{
|
||||
Dalamud.PluginInterface.SavePluginConfig( this );
|
||||
var text = JsonConvert.SerializeObject( this, Formatting.Indented );
|
||||
File.WriteAllText( Dalamud.PluginInterface.ConfigFile.FullName, text );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
|
|
@ -113,12 +137,48 @@ public partial class Configuration : IPluginConfiguration
|
|||
// Contains some default values or boundaries for config values.
|
||||
public static class Constants
|
||||
{
|
||||
public const int CurrentVersion = 3;
|
||||
public const int CurrentVersion = 4;
|
||||
public const float MaxAbsoluteSize = 600;
|
||||
public const int DefaultAbsoluteSize = 250;
|
||||
public const float MinAbsoluteSize = 50;
|
||||
public const int MaxScaledSize = 80;
|
||||
public const int DefaultScaledSize = 20;
|
||||
public const int MinScaledSize = 5;
|
||||
|
||||
public static readonly ISortMode< Mod >[] ValidSortModes =
|
||||
{
|
||||
ISortMode< Mod >.FoldersFirst,
|
||||
ISortMode< Mod >.Lexicographical,
|
||||
new ModFileSystem.ImportDate(),
|
||||
new ModFileSystem.InverseImportDate(),
|
||||
ISortMode< Mod >.InverseFoldersFirst,
|
||||
ISortMode< Mod >.InverseLexicographical,
|
||||
ISortMode< Mod >.FoldersLast,
|
||||
ISortMode< Mod >.InverseFoldersLast,
|
||||
ISortMode< Mod >.InternalOrder,
|
||||
ISortMode< Mod >.InverseInternalOrder,
|
||||
};
|
||||
}
|
||||
|
||||
private class SortModeConverter : JsonConverter< ISortMode< Mod > >
|
||||
{
|
||||
public override void WriteJson( JsonWriter writer, ISortMode< Mod >? value, JsonSerializer serializer )
|
||||
{
|
||||
value ??= ISortMode< Mod >.FoldersFirst;
|
||||
serializer.Serialize( writer, value.GetType().Name );
|
||||
}
|
||||
|
||||
public override ISortMode< Mod > ReadJson( JsonReader reader, Type objectType, ISortMode< Mod >? existingValue,
|
||||
bool hasExistingValue,
|
||||
JsonSerializer serializer )
|
||||
{
|
||||
var name = serializer.Deserialize< string >( reader );
|
||||
if( name == null || !Constants.ValidSortModes.FindFirst( s => s.GetType().Name == name, out var mode ) )
|
||||
{
|
||||
return existingValue ?? ISortMode< Mod >.FoldersFirst;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
using System;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Penumbra.Collections;
|
||||
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
|
||||
|
||||
namespace Penumbra.Interop.Resolver;
|
||||
|
||||
|
|
@ -92,6 +95,7 @@ public unsafe partial class PathResolver
|
|||
_animationLoadCollection = IdentifyCollection( ( GameObject* )( Dalamud.Objects[ actorIdx ]?.Address ?? IntPtr.Zero ) );
|
||||
}
|
||||
}
|
||||
|
||||
LoadSomePapHook!.Original( a1, a2, a3, a4 );
|
||||
_animationLoadCollection = last;
|
||||
}
|
||||
|
|
@ -107,4 +111,28 @@ public unsafe partial class PathResolver
|
|||
SomeActionLoadHook!.Original( gameObject );
|
||||
_animationLoadCollection = last;
|
||||
}
|
||||
|
||||
[Signature( "E8 ?? ?? ?? ?? 44 84 BB", DetourName = nameof( SomeOtherAvfxDetour ) )]
|
||||
public Hook< CharacterBaseDestructorDelegate >? SomeOtherAvfxHook;
|
||||
|
||||
private void SomeOtherAvfxDetour( IntPtr unk )
|
||||
{
|
||||
var last = _animationLoadCollection;
|
||||
var gameObject = ( GameObject* )( unk - 0x8B0 );
|
||||
_animationLoadCollection = IdentifyCollection( gameObject );
|
||||
SomeOtherAvfxHook!.Original( unk );
|
||||
_animationLoadCollection = last;
|
||||
}
|
||||
|
||||
public delegate IntPtr SomeAtexDelegate( IntPtr a1, IntPtr a2, IntPtr a3, IntPtr a4, uint a5, IntPtr a6 );
|
||||
|
||||
[Signature( "E8 ?? ?? ?? ?? 84 C0 75 ?? 48 8B CE 41 B6" )]
|
||||
public Hook< SomeAtexDelegate >? SomeAtexHook;
|
||||
|
||||
public IntPtr SomeAtexDetour( IntPtr a1, IntPtr a2, IntPtr a3, IntPtr a4, uint a5, IntPtr a6 )
|
||||
{
|
||||
var ret = SomeAtexHook!.Original( a1, a2, a3, a4, a5, a6 );
|
||||
PluginLog.Information( $"{a1:X} {a2:X} {a3:X} {a4:X} {a5:X} {a6:X} {ret}" );
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
@ -97,6 +97,8 @@ public unsafe partial class PathResolver
|
|||
LoadSomeAvfxHook?.Enable();
|
||||
LoadSomePapHook?.Enable();
|
||||
SomeActionLoadHook?.Enable();
|
||||
SomeOtherAvfxHook?.Enable();
|
||||
SomeAtexHook?.Enable();
|
||||
}
|
||||
|
||||
private void DisableDataHooks()
|
||||
|
|
@ -111,6 +113,8 @@ public unsafe partial class PathResolver
|
|||
LoadSomeAvfxHook?.Disable();
|
||||
LoadSomePapHook?.Disable();
|
||||
SomeActionLoadHook?.Disable();
|
||||
SomeOtherAvfxHook?.Disable();
|
||||
SomeAtexHook?.Disable();
|
||||
}
|
||||
|
||||
private void DisposeDataHooks()
|
||||
|
|
@ -124,6 +128,8 @@ public unsafe partial class PathResolver
|
|||
LoadSomeAvfxHook?.Dispose();
|
||||
LoadSomePapHook?.Dispose();
|
||||
SomeActionLoadHook?.Dispose();
|
||||
SomeOtherAvfxHook?.Dispose();
|
||||
SomeAtexHook?.Dispose();
|
||||
}
|
||||
|
||||
// This map links DrawObjects directly to Actors (by ObjectTable index) and their collections.
|
||||
|
|
|
|||
|
|
@ -76,6 +76,13 @@ public partial class PathResolver : IDisposable
|
|||
|
||||
private bool HandleAnimationFile( ResourceType type, Utf8GamePath _, [NotNullWhen(true)] out ModCollection? collection )
|
||||
{
|
||||
if( type == ResourceType.Atex )
|
||||
if (_animationLoadCollection == null)
|
||||
PluginLog.Information( $"ATEX {_} Default" );
|
||||
else
|
||||
{
|
||||
PluginLog.Information( $"ATEX {_} {_animationLoadCollection?.Name}" );
|
||||
}
|
||||
if( _animationLoadCollection != null )
|
||||
{
|
||||
switch( type )
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
|
@ -45,6 +46,30 @@ public sealed class ModFileSystem : FileSystem< Mod >, IDisposable
|
|||
Penumbra.ModManager.ModMetaChanged -= OnMetaChange;
|
||||
}
|
||||
|
||||
public struct ImportDate : ISortMode< Mod >
|
||||
{
|
||||
public string Name
|
||||
=> "Import Date (Older First)";
|
||||
|
||||
public string Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their import date.";
|
||||
|
||||
public IEnumerable< IPath > GetChildren( Folder f )
|
||||
=> f.GetSubFolders().Cast< IPath >().Concat( f.GetLeaves().OrderBy( l => l.Value.ImportDate ) );
|
||||
}
|
||||
|
||||
public struct InverseImportDate : ISortMode< Mod >
|
||||
{
|
||||
public string Name
|
||||
=> "Import Date (Newer First)";
|
||||
|
||||
public string Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their inverse import date.";
|
||||
|
||||
public IEnumerable< IPath > GetChildren( Folder f )
|
||||
=> f.GetSubFolders().Cast< IPath >().Concat( f.GetLeaves().OrderByDescending( l => l.Value.ImportDate ) );
|
||||
}
|
||||
|
||||
// Reload the whole filesystem from currently loaded mods and the current sort order file.
|
||||
// Used on construction and on mod rediscoveries.
|
||||
private void Reload()
|
||||
|
|
@ -72,7 +97,7 @@ public sealed class ModFileSystem : FileSystem< Mod >, IDisposable
|
|||
if( type.HasFlag( MetaChangeType.Name ) && oldName != null )
|
||||
{
|
||||
var old = oldName.FixName();
|
||||
if( Find( old, out var child ) && child is not Folder)
|
||||
if( Find( old, out var child ) && child is not Folder )
|
||||
{
|
||||
Rename( child, mod.Name.Text );
|
||||
}
|
||||
|
|
@ -97,7 +122,7 @@ public sealed class ModFileSystem : FileSystem< Mod >, IDisposable
|
|||
CreateLeaf( Root, name, mod );
|
||||
break;
|
||||
case ModPathChangeType.Deleted:
|
||||
var leaf = Root.GetAllDescendants( SortMode.Lexicographical ).OfType< Leaf >().FirstOrDefault( l => l.Value == mod );
|
||||
var leaf = Root.GetAllDescendants( ISortMode< Mod >.Lexicographical ).OfType< Leaf >().FirstOrDefault( l => l.Value == mod );
|
||||
if( leaf != null )
|
||||
{
|
||||
Delete( leaf );
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ using System.Collections.Concurrent;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.UI.Classes;
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector< Mod, Mod
|
|||
=> base.SelectedLeaf;
|
||||
|
||||
// Customization points.
|
||||
public override SortMode SortMode
|
||||
public override ISortMode< Mod > SortMode
|
||||
=> Penumbra.Config.SortMode;
|
||||
|
||||
protected override uint ExpandedFolderColor
|
||||
|
|
@ -315,7 +315,7 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector< Mod, Mod
|
|||
// Helpers.
|
||||
private static void SetDescendants( ModFileSystem.Folder folder, bool enabled, bool inherit = false )
|
||||
{
|
||||
var mods = folder.GetAllDescendants( SortMode.Lexicographical ).OfType< ModFileSystem.Leaf >().Select( l => l.Value );
|
||||
var mods = folder.GetAllDescendants( ISortMode< Mod >.Lexicographical ).OfType< ModFileSystem.Leaf >().Select( l => l.Value );
|
||||
if( inherit )
|
||||
{
|
||||
Penumbra.CollectionManager.Current.SetMultipleModInheritances( mods, enabled );
|
||||
|
|
@ -404,7 +404,7 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector< Mod, Mod
|
|||
{
|
||||
if( _lastSelectedDirectory.Length > 0 )
|
||||
{
|
||||
base.SelectedLeaf = ( ModFileSystem.Leaf? )FileSystem.Root.GetAllDescendants( SortMode.Lexicographical )
|
||||
base.SelectedLeaf = ( ModFileSystem.Leaf? )FileSystem.Root.GetAllDescendants( ISortMode< Mod >.Lexicographical )
|
||||
.FirstOrDefault( l => l is ModFileSystem.Leaf m && m.Value.ModPath.FullName == _lastSelectedDirectory );
|
||||
OnSelectionChange( null, base.SelectedLeaf?.Value, default );
|
||||
_lastSelectedDirectory = string.Empty;
|
||||
|
|
@ -422,7 +422,7 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector< Mod, Mod
|
|||
|
||||
try
|
||||
{
|
||||
var leaf = FileSystem.Root.GetChildren( SortMode.Lexicographical )
|
||||
var leaf = FileSystem.Root.GetChildren( ISortMode< Mod >.Lexicographical )
|
||||
.FirstOrDefault( f => f is FileSystem< Mod >.Leaf l && l.Value == mod );
|
||||
if( leaf == null )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ using System.Numerics;
|
|||
using Dalamud.Interface;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Filesystem;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.UI;
|
||||
|
||||
|
|
@ -119,20 +119,19 @@ public partial class ConfigWindow
|
|||
{
|
||||
var sortMode = Penumbra.Config.SortMode;
|
||||
ImGui.SetNextItemWidth( _window._inputTextWidth.X );
|
||||
using var combo = ImRaii.Combo( "##sortMode", sortMode.Data().Name );
|
||||
using var combo = ImRaii.Combo( "##sortMode", sortMode.Name );
|
||||
if( combo )
|
||||
{
|
||||
foreach( var val in Enum.GetValues< SortMode >() )
|
||||
foreach( var val in Configuration.Constants.ValidSortModes )
|
||||
{
|
||||
var (name, desc) = val.Data();
|
||||
if( ImGui.Selectable( name, val == sortMode ) && val != sortMode )
|
||||
if( ImGui.Selectable( val.Name, val.GetType() == sortMode.GetType() ) && val.GetType() != sortMode.GetType() )
|
||||
{
|
||||
Penumbra.Config.SortMode = val;
|
||||
_window._selector.SetFilterDirty();
|
||||
Penumbra.Config.Save();
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip( desc );
|
||||
ImGuiUtil.HoverTooltip( val.Description );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue