From abd1fd14f55ddd0994b32e9da451a8436cf36c6f Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 17 Jun 2022 16:18:08 +0200 Subject: [PATCH 01/11] Add config to use default or owner collection for housing retainers. --- Penumbra/Configuration.cs | 1 + Penumbra/Interop/Resolver/PathResolver.Data.cs | 4 ++++ Penumbra/UI/ConfigWindow.SettingsTab.General.cs | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/Penumbra/Configuration.cs b/Penumbra/Configuration.cs index 8cb3e746..dfa22fd2 100644 --- a/Penumbra/Configuration.cs +++ b/Penumbra/Configuration.cs @@ -27,6 +27,7 @@ public partial class Configuration : IPluginConfiguration public bool UseCharacterCollectionInTryOn { get; set; } = true; public bool UseOwnerNameForCharacterCollection { get; set; } = true; public bool PreferNamedCollectionsOverOwners { get; set; } = true; + public bool UseDefaultCollectionForRetainers { get; set; } = false; #if DEBUG public bool DebugMode { get; set; } = true; diff --git a/Penumbra/Interop/Resolver/PathResolver.Data.cs b/Penumbra/Interop/Resolver/PathResolver.Data.cs index 00b92905..71cda6c5 100644 --- a/Penumbra/Interop/Resolver/PathResolver.Data.cs +++ b/Penumbra/Interop/Resolver/PathResolver.Data.cs @@ -271,6 +271,10 @@ public unsafe partial class PathResolver return Penumbra.CollectionManager.Default; } + // Housing Retainers + if( Penumbra.Config.UseDefaultCollectionForRetainers && gameObject->ObjectKind == (byte) ObjectKind.EventNpc && gameObject->DataID == 1011832 ) + return Penumbra.CollectionManager.Default; + string? actorName = null; if( Penumbra.Config.PreferNamedCollectionsOverOwners ) { diff --git a/Penumbra/UI/ConfigWindow.SettingsTab.General.cs b/Penumbra/UI/ConfigWindow.SettingsTab.General.cs index e69fa219..b545b1eb 100644 --- a/Penumbra/UI/ConfigWindow.SettingsTab.General.cs +++ b/Penumbra/UI/ConfigWindow.SettingsTab.General.cs @@ -75,6 +75,10 @@ public partial class ConfigWindow "If you have a character collection set to a specific name for a companion or combat pet, prefer this collection over the owner's collection.\n" + "That is, if you have a 'Topaz Carbuncle' collection, it will use this one instead of the one for its owner.", Penumbra.Config.PreferNamedCollectionsOverOwners, v => Penumbra.Config.PreferNamedCollectionsOverOwners = v ); + Checkbox( "Use Default Collection for Housing Retainers", + "Housing Retainers use the name of their owner instead of their own, you can decide to let them use their owners character collection or the default collection.\n" + + "It is not possible to make them have their own collection, since they have no connection to their actual name.", + Penumbra.Config.UseDefaultCollectionForRetainers, v => Penumbra.Config.UseDefaultCollectionForRetainers = v ); ImGui.Dummy( _window._defaultSpace ); DrawFolderSortType(); DrawAbsoluteSizeSelector(); From 61680f0afbac35d8e0144a5a4d028a7cb4685a28 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 17 Jun 2022 16:18:56 +0200 Subject: [PATCH 02/11] Add warning if the currently edited collection is not in use anywhere. --- .../Collections/CollectionManager.Active.cs | 5 +++++ Penumbra/UI/ConfigWindow.Misc.cs | 18 ++++++++---------- Penumbra/UI/ConfigWindow.ModPanel.Header.cs | 7 +------ Penumbra/UI/ConfigWindow.ModsTab.cs | 11 ++++++++++- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/Penumbra/Collections/CollectionManager.Active.cs b/Penumbra/Collections/CollectionManager.Active.cs index d21ad8f9..f06a574f 100644 --- a/Penumbra/Collections/CollectionManager.Active.cs +++ b/Penumbra/Collections/CollectionManager.Active.cs @@ -20,6 +20,9 @@ public partial class ModCollection // The collection currently selected for changing settings. public ModCollection Current { get; private set; } = Empty; + // The collection currently selected is in use either as an active collection or through inheritance. + public bool CurrentCollectionInUse { get; private set; } + // The collection used for general file redirections and all characters not specifically named. public ModCollection Default { get; private set; } = Empty; @@ -78,6 +81,8 @@ public partial class ModCollection break; } + CurrentCollectionInUse = Characters.Values.Prepend( Default ).SelectMany( c => c.GetFlattenedInheritance() ).Contains( Current ); + CollectionChanged.Invoke( type, this[ oldCollectionIdx ], newCollection, characterName ); } diff --git a/Penumbra/UI/ConfigWindow.Misc.cs b/Penumbra/UI/ConfigWindow.Misc.cs index 17cc424d..7d8969ee 100644 --- a/Penumbra/UI/ConfigWindow.Misc.cs +++ b/Penumbra/UI/ConfigWindow.Misc.cs @@ -101,18 +101,16 @@ public partial class ConfigWindow _ => throw new ArgumentOutOfRangeException( nameof( type ), type, null ), }; - using var combo = ImRaii.Combo( label, current.Name ); - if( !combo ) + using var combo = ImRaii.Combo( label, current.Name ); + if( combo ) { - return; - } - - foreach( var collection in Penumbra.CollectionManager.GetEnumeratorWithEmpty().Skip( withEmpty ? 0 : 1 ).OrderBy( c => c.Name ) ) - { - using var id = ImRaii.PushId( collection.Index ); - if( ImGui.Selectable( collection.Name, collection == current ) ) + foreach( var collection in Penumbra.CollectionManager.GetEnumeratorWithEmpty().Skip( withEmpty ? 0 : 1 ).OrderBy( c => c.Name ) ) { - Penumbra.CollectionManager.SetCollection( collection, type, characterName ); + using var id = ImRaii.PushId( collection.Index ); + if( ImGui.Selectable( collection.Name, collection == current ) ) + { + Penumbra.CollectionManager.SetCollection( collection, type, characterName ); + } } } } diff --git a/Penumbra/UI/ConfigWindow.ModPanel.Header.cs b/Penumbra/UI/ConfigWindow.ModPanel.Header.cs index 6830884e..4893c6da 100644 --- a/Penumbra/UI/ConfigWindow.ModPanel.Header.cs +++ b/Penumbra/UI/ConfigWindow.ModPanel.Header.cs @@ -12,17 +12,12 @@ namespace Penumbra.UI; public partial class ConfigWindow { - private partial class ModPanel : IDisposable + private partial class ModPanel { // We use a big, nice game font for the title. private readonly GameFontHandle _nameFont = Dalamud.PluginInterface.UiBuilder.GetGameFontHandle( new GameFontStyle( GameFontFamilyAndSize.Jupiter23 ) ); - public void Dispose() - { - _nameFont.Dispose(); - } - // Header data. private string _modName = string.Empty; private string _modAuthor = string.Empty; diff --git a/Penumbra/UI/ConfigWindow.ModsTab.cs b/Penumbra/UI/ConfigWindow.ModsTab.cs index f09f1423..d85ff38a 100644 --- a/Penumbra/UI/ConfigWindow.ModsTab.cs +++ b/Penumbra/UI/ConfigWindow.ModsTab.cs @@ -63,6 +63,10 @@ public partial class ConfigWindow DrawInheritedCollectionButton( 3 * buttonSize ); ImGui.SameLine(); DrawCollectionSelector( "##collectionSelector", 2 * buttonSize.X, ModCollection.Type.Current, false, null ); + if( !Penumbra.CollectionManager.CurrentCollectionInUse ) + { + ImGuiUtil.DrawTextButton( "The currently selected collection is not used in any way.", -Vector2.UnitX, Colors.PressEnterWarningBg ); + } } private static void DrawDefaultCollectionButton( Vector2 width ) @@ -112,7 +116,7 @@ public partial class ConfigWindow // The basic setup for the mod panel. // Details are in other files. - private partial class ModPanel + private partial class ModPanel : IDisposable { private readonly ConfigWindow _window; @@ -123,6 +127,11 @@ public partial class ConfigWindow public ModPanel( ConfigWindow window ) => _window = window; + public void Dispose() + { + _nameFont.Dispose(); + } + public void Draw( ModFileSystemSelector selector ) { Init( selector ); From f579933dd7c35d3f0b43501f548931389d8cf145 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 17 Jun 2022 16:30:02 +0200 Subject: [PATCH 03/11] Change planned API to use interfaces. --- Penumbra/Api/IPenumbraApi.cs | 6 +++--- Penumbra/Api/PenumbraApi.cs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Penumbra/Api/IPenumbraApi.cs b/Penumbra/Api/IPenumbraApi.cs index 37265ce9..dd4b1562 100644 --- a/Penumbra/Api/IPenumbraApi.cs +++ b/Penumbra/Api/IPenumbraApi.cs @@ -104,12 +104,12 @@ public interface IPenumbraApi : IPenumbraApiBase // Obtain the potential settings of a mod specified by its directory name first or mod name second. // Returns null if the mod could not be found. - public Dictionary< string, (string[], SelectType) >? GetAvailableModSettings( string modDirectory, string modName ); + public IDictionary< string, (IList, SelectType) >? GetAvailableModSettings( string modDirectory, string modName ); // Obtain the enabled state, the priority, the settings of a mod specified by its directory name first or mod name second, // and whether these settings are inherited, or null if the collection does not set them at all. // If allowInheritance is false, only the collection itself will be checked. - public (PenumbraApiEc, (bool, int, Dictionary< string, string[] >, bool)?) GetCurrentModSettings( string collectionName, + public (PenumbraApiEc, (bool, int, IDictionary< string, IList >, bool)?) GetCurrentModSettings( string collectionName, string modDirectory, string modName, bool allowInheritance ); // Try to set the inheritance state in the given collection of a mod specified by its directory name first or mod name second. @@ -131,7 +131,7 @@ public interface IPenumbraApi : IPenumbraApiBase public PenumbraApiEc TrySetModSetting( string collectionName, string modDirectory, string modName, string optionGroupName, string option ); public PenumbraApiEc TrySetModSetting( string collectionName, string modDirectory, string modName, string optionGroupName, - string[] options ); + IReadOnlyList options ); // Create a temporary collection without actual settings but with a cache. diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index a81ab204..4cce0f2c 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -210,10 +210,10 @@ public class PenumbraApi : IDisposable, IPenumbraApi return Penumbra.ModManager.Select( m => ( m.ModPath.Name, m.Name.Text ) ).ToArray(); } - public Dictionary< string, (string[], SelectType) >? GetAvailableModSettings( string modDirectory, string modName ) + public IDictionary< string, (IList, SelectType) >? GetAvailableModSettings( string modDirectory, string modName ) => throw new NotImplementedException(); - public (PenumbraApiEc, (bool, int, Dictionary< string, string[] >, bool)?) GetCurrentModSettings( string collectionName, string modDirectory, string modName, + public (PenumbraApiEc, (bool, int, IDictionary< string, IList >, bool)?) GetCurrentModSettings( string collectionName, string modDirectory, string modName, bool allowInheritance ) => throw new NotImplementedException(); @@ -229,7 +229,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi public PenumbraApiEc TrySetModSetting( string collectionName, string modDirectory, string modName, string optionGroupName, string option ) => throw new NotImplementedException(); - public PenumbraApiEc TrySetModSetting( string collectionName, string modDirectory, string modName, string optionGroupName, string[] options ) + public PenumbraApiEc TrySetModSetting( string collectionName, string modDirectory, string modName, string optionGroupName, IReadOnlyList options ) => throw new NotImplementedException(); public PenumbraApiEc CreateTemporaryCollection( string collectionName, string? character, bool forceOverwriteCharacter ) From 1c7037416c29dbdf2a77bd730fa30cfdce746672 Mon Sep 17 00:00:00 2001 From: Stanley Dimant Date: Thu, 16 Jun 2022 23:33:30 +0200 Subject: [PATCH 04/11] add Penumbra.ObjectIsRedrawn and Penumbra.ReverseResolvePath to API --- Penumbra/Api/IPenumbraApi.cs | 4 + Penumbra/Api/PenumbraApi.cs | 60 +++++--- Penumbra/Api/PenumbraIpc.cs | 142 +++++++++++------- .../Collections/ModCollection.Cache.Access.cs | 1 + Penumbra/Collections/ModCollection.Cache.cs | 107 +++++++------ Penumbra/Interop/ObjectReloader.cs | 3 + 6 files changed, 192 insertions(+), 125 deletions(-) diff --git a/Penumbra/Api/IPenumbraApi.cs b/Penumbra/Api/IPenumbraApi.cs index dd4b1562..b50a98ba 100644 --- a/Penumbra/Api/IPenumbraApi.cs +++ b/Penumbra/Api/IPenumbraApi.cs @@ -51,6 +51,7 @@ public interface IPenumbraApi : IPenumbraApiBase // Triggered when the user clicks a listed changed object in a mod tab. public event ChangedItemClick? ChangedItemClicked; + event EventHandler? ObjectIsRedrawn; // Queue redrawing of all actors of the given name with the given RedrawType. public void RedrawObject( string name, RedrawType setting ); @@ -72,6 +73,9 @@ public interface IPenumbraApi : IPenumbraApiBase // Returns the given gamePath if penumbra would not manipulate it. public string ResolvePath( string gamePath, string characterName ); + // Reverse resolves a given modded local path into its replacement in form of all applicable game path for given character + public string[] ReverseResolvePath( string moddedPath, string characterName ); + // Try to load a given gamePath with the resolved path from Penumbra. public T? GetFile< T >( string gamePath ) where T : FileResource; diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index 4cce0f2c..eb8f57b2 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -18,8 +18,9 @@ namespace Penumbra.Api; public class PenumbraApi : IDisposable, IPenumbraApi { public int ApiVersion { get; } = 4; - private Penumbra? _penumbra; + private Penumbra? _penumbra; private Lumina.GameData? _lumina; + public event EventHandler? ObjectIsRedrawn; public bool Valid => _penumbra != null; @@ -30,12 +31,19 @@ public class PenumbraApi : IDisposable, IPenumbraApi _lumina = ( Lumina.GameData? )Dalamud.GameData.GetType() .GetField( "gameData", BindingFlags.Instance | BindingFlags.NonPublic ) ?.GetValue( Dalamud.GameData ); + _penumbra.ObjectReloader.ObjectIsRedrawn += ObjectReloader_ObjectIsRedrawn; + } + + private void ObjectReloader_ObjectIsRedrawn( object? sender, EventArgs e ) + { + ObjectIsRedrawn?.Invoke( sender, e ); } public void Dispose() { + _penumbra!.ObjectReloader.ObjectIsRedrawn -= ObjectReloader_ObjectIsRedrawn; _penumbra = null; - _lumina = null; + _lumina = null; } public event ChangedItemClick? ChangedItemClicked; @@ -49,7 +57,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi public IPluginConfiguration GetConfiguration() { CheckInitialized(); - return JsonConvert.DeserializeObject< Configuration >( JsonConvert.SerializeObject( Penumbra.Config ) ); + return JsonConvert.DeserializeObject( JsonConvert.SerializeObject( Penumbra.Config ) ); } public event ChangedItemHover? ChangedItemTooltip; @@ -104,7 +112,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi } var gamePath = Utf8GamePath.FromString( path, out var p, true ) ? p : Utf8GamePath.Empty; - var ret = collection.ResolvePath( gamePath ); + var ret = collection.ResolvePath( gamePath ); return ret?.ToString() ?? path; } @@ -121,17 +129,31 @@ public class PenumbraApi : IDisposable, IPenumbraApi Penumbra.CollectionManager.Character( characterName ) ); } - private T? GetFileIntern< T >( string resolvedPath ) where T : FileResource + public string[] ReverseResolvePath( string path, string characterName ) + { + CheckInitialized(); + if( !Penumbra.Config.EnableMods ) + { + return new[] { path }; + } + + var gamePath = Utf8GamePath.FromString( path, out var p, true ) ? p : Utf8GamePath.Empty; + var ret = Penumbra.CollectionManager.Character( characterName ).ResolveReversePath( new FullPath( path ) ) ?? new List(); + if( ret.Count == 0 ) ret.Add( gamePath ); + return ret.Select( r => r.ToString() ).ToArray(); + } + + private T? GetFileIntern( string resolvedPath ) where T : FileResource { CheckInitialized(); try { if( Path.IsPathRooted( resolvedPath ) ) { - return _lumina?.GetFileFromDisk< T >( resolvedPath ); + return _lumina?.GetFileFromDisk( resolvedPath ); } - return Dalamud.GameData.GetFile< T >( resolvedPath ); + return Dalamud.GameData.GetFile( resolvedPath ); } catch( Exception e ) { @@ -140,13 +162,13 @@ public class PenumbraApi : IDisposable, IPenumbraApi } } - public T? GetFile< T >( string gamePath ) where T : FileResource - => GetFileIntern< T >( ResolvePath( gamePath ) ); + public T? GetFile( string gamePath ) where T : FileResource + => GetFileIntern( ResolvePath( gamePath ) ); - public T? GetFile< T >( string gamePath, string characterName ) where T : FileResource - => GetFileIntern< T >( ResolvePath( gamePath, characterName ) ); + public T? GetFile( string gamePath, string characterName ) where T : FileResource + => GetFileIntern( ResolvePath( gamePath, characterName ) ); - public IReadOnlyDictionary< string, object? > GetChangedItemsForCollection( string collectionName ) + public IReadOnlyDictionary GetChangedItemsForCollection( string collectionName ) { CheckInitialized(); try @@ -162,7 +184,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi } PluginLog.Warning( $"Collection {collectionName} does not exist or is not loaded." ); - return new Dictionary< string, object? >(); + return new Dictionary(); } catch( Exception e ) { @@ -171,7 +193,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi } } - public IList< string > GetCollections() + public IList GetCollections() { CheckInitialized(); return Penumbra.CollectionManager.Skip( 1 ).Select( c => c.Name ).ToArray(); @@ -193,21 +215,21 @@ public class PenumbraApi : IDisposable, IPenumbraApi { CheckInitialized(); return Penumbra.CollectionManager.Characters.TryGetValue( characterName, out var collection ) - ? ( collection.Name, true ) - : ( Penumbra.CollectionManager.Default.Name, false ); + ? (collection.Name, true) + : (Penumbra.CollectionManager.Default.Name, false); } public (IntPtr, string) GetDrawObjectInfo( IntPtr drawObject ) { CheckInitialized(); var (obj, collection) = _penumbra!.PathResolver.IdentifyDrawObject( drawObject ); - return ( obj, collection.Name ); + return (obj, collection.Name); } - public IList< (string, string) > GetModList() + public IList<(string, string)> GetModList() { CheckInitialized(); - return Penumbra.ModManager.Select( m => ( m.ModPath.Name, m.Name.Text ) ).ToArray(); + return Penumbra.ModManager.Select( m => (m.ModPath.Name, m.Name.Text) ).ToArray(); } public IDictionary< string, (IList, SelectType) >? GetAvailableModSettings( string modDirectory, string modName ) diff --git a/Penumbra/Api/PenumbraIpc.cs b/Penumbra/Api/PenumbraIpc.cs index d8dc6db0..f5c59830 100644 --- a/Penumbra/Api/PenumbraIpc.cs +++ b/Penumbra/Api/PenumbraIpc.cs @@ -38,23 +38,23 @@ public partial class PenumbraIpc : IDisposable public partial class PenumbraIpc { - public const string LabelProviderInitialized = "Penumbra.Initialized"; - public const string LabelProviderDisposed = "Penumbra.Disposed"; - public const string LabelProviderApiVersion = "Penumbra.ApiVersion"; - public const string LabelProviderGetModDirectory = "Penumbra.GetModDirectory"; + public const string LabelProviderInitialized = "Penumbra.Initialized"; + public const string LabelProviderDisposed = "Penumbra.Disposed"; + public const string LabelProviderApiVersion = "Penumbra.ApiVersion"; + public const string LabelProviderGetModDirectory = "Penumbra.GetModDirectory"; public const string LabelProviderGetConfiguration = "Penumbra.GetConfiguration"; - internal ICallGateProvider< object? >? ProviderInitialized; - internal ICallGateProvider< object? >? ProviderDisposed; - internal ICallGateProvider< int >? ProviderApiVersion; - internal ICallGateProvider< string >? ProviderGetModDirectory; - internal ICallGateProvider< IPluginConfiguration >? ProviderGetConfiguration; + internal ICallGateProvider? ProviderInitialized; + internal ICallGateProvider? ProviderDisposed; + internal ICallGateProvider? ProviderApiVersion; + internal ICallGateProvider? ProviderGetModDirectory; + internal ICallGateProvider? ProviderGetConfiguration; private void InitializeGeneralProviders( DalamudPluginInterface pi ) { try { - ProviderInitialized = pi.GetIpcProvider< object? >( LabelProviderInitialized ); + ProviderInitialized = pi.GetIpcProvider( LabelProviderInitialized ); } catch( Exception e ) { @@ -63,7 +63,7 @@ public partial class PenumbraIpc try { - ProviderDisposed = pi.GetIpcProvider< object? >( LabelProviderDisposed ); + ProviderDisposed = pi.GetIpcProvider( LabelProviderDisposed ); } catch( Exception e ) { @@ -72,7 +72,7 @@ public partial class PenumbraIpc try { - ProviderApiVersion = pi.GetIpcProvider< int >( LabelProviderApiVersion ); + ProviderApiVersion = pi.GetIpcProvider( LabelProviderApiVersion ); ProviderApiVersion.RegisterFunc( () => Api.ApiVersion ); } catch( Exception e ) @@ -82,7 +82,7 @@ public partial class PenumbraIpc try { - ProviderGetModDirectory = pi.GetIpcProvider< string >( LabelProviderGetModDirectory ); + ProviderGetModDirectory = pi.GetIpcProvider( LabelProviderGetModDirectory ); ProviderGetModDirectory.RegisterFunc( Api.GetModDirectory ); } catch( Exception e ) @@ -92,7 +92,7 @@ public partial class PenumbraIpc try { - ProviderGetConfiguration = pi.GetIpcProvider< IPluginConfiguration >( LabelProviderGetConfiguration ); + ProviderGetConfiguration = pi.GetIpcProvider( LabelProviderGetConfiguration ); ProviderGetConfiguration.RegisterFunc( Api.GetConfiguration ); } catch( Exception e ) @@ -111,15 +111,17 @@ public partial class PenumbraIpc public partial class PenumbraIpc { - public const string LabelProviderRedrawName = "Penumbra.RedrawObjectByName"; - public const string LabelProviderRedrawIndex = "Penumbra.RedrawObjectByIndex"; + public const string LabelProviderRedrawName = "Penumbra.RedrawObjectByName"; + public const string LabelProviderRedrawIndex = "Penumbra.RedrawObjectByIndex"; public const string LabelProviderRedrawObject = "Penumbra.RedrawObject"; - public const string LabelProviderRedrawAll = "Penumbra.RedrawAll"; + public const string LabelProviderRedrawAll = "Penumbra.RedrawAll"; + public const string LabelProviderObjectIsRedrawn = "Penumbra.ObjectIsRedrawn"; - internal ICallGateProvider< string, int, object >? ProviderRedrawName; - internal ICallGateProvider< int, int, object >? ProviderRedrawIndex; - internal ICallGateProvider< GameObject, int, object >? ProviderRedrawObject; - internal ICallGateProvider< int, object >? ProviderRedrawAll; + internal ICallGateProvider? ProviderRedrawName; + internal ICallGateProvider? ProviderRedrawIndex; + internal ICallGateProvider? ProviderRedrawObject; + internal ICallGateProvider? ProviderRedrawAll; + internal ICallGateProvider ProviderObjectIsRedrawn; private static RedrawType CheckRedrawType( int value ) { @@ -136,7 +138,7 @@ public partial class PenumbraIpc { try { - ProviderRedrawName = pi.GetIpcProvider< string, int, object >( LabelProviderRedrawName ); + ProviderRedrawName = pi.GetIpcProvider( LabelProviderRedrawName ); ProviderRedrawName.RegisterAction( ( s, i ) => Api.RedrawObject( s, CheckRedrawType( i ) ) ); } catch( Exception e ) @@ -156,7 +158,7 @@ public partial class PenumbraIpc try { - ProviderRedrawObject = pi.GetIpcProvider< GameObject, int, object >( LabelProviderRedrawObject ); + ProviderRedrawObject = pi.GetIpcProvider( LabelProviderRedrawObject ); ProviderRedrawObject.RegisterAction( ( o, i ) => Api.RedrawObject( o, CheckRedrawType( i ) ) ); } catch( Exception e ) @@ -166,13 +168,28 @@ public partial class PenumbraIpc try { - ProviderRedrawAll = pi.GetIpcProvider< int, object >( LabelProviderRedrawAll ); + ProviderRedrawAll = pi.GetIpcProvider( LabelProviderRedrawAll ); ProviderRedrawAll.RegisterAction( i => Api.RedrawAll( CheckRedrawType( i ) ) ); } catch( Exception e ) { PluginLog.Error( $"Error registering IPC provider for {LabelProviderRedrawAll}:\n{e}" ); } + + try + { + ProviderObjectIsRedrawn = pi.GetIpcProvider( LabelProviderObjectIsRedrawn ); + Api.ObjectIsRedrawn += Api_ObjectIsRedrawn; + } + catch( Exception e ) + { + PluginLog.Error( $"Error registering IPC provider for {LabelProviderObjectIsRedrawn}:\n{e}" ); + } + } + + private void Api_ObjectIsRedrawn( object? sender, EventArgs e ) + { + ProviderObjectIsRedrawn.SendMessage( ( ( GameObject? )sender )?.Name.ToString() ?? "" ); } private void DisposeRedrawProviders() @@ -181,24 +198,27 @@ public partial class PenumbraIpc ProviderRedrawIndex?.UnregisterAction(); ProviderRedrawObject?.UnregisterAction(); ProviderRedrawAll?.UnregisterAction(); + Api.ObjectIsRedrawn -= Api_ObjectIsRedrawn; } } public partial class PenumbraIpc { - public const string LabelProviderResolveDefault = "Penumbra.ResolveDefaultPath"; - public const string LabelProviderResolveCharacter = "Penumbra.ResolveCharacterPath"; + public const string LabelProviderResolveDefault = "Penumbra.ResolveDefaultPath"; + public const string LabelProviderResolveCharacter = "Penumbra.ResolveCharacterPath"; public const string LabelProviderGetDrawObjectInfo = "Penumbra.GetDrawObjectInfo"; + public const string LabelProviderReverseResolvePath = "Penumbra.ReverseResolvePath"; - internal ICallGateProvider< string, string >? ProviderResolveDefault; - internal ICallGateProvider< string, string, string >? ProviderResolveCharacter; - internal ICallGateProvider< IntPtr, (IntPtr, string) >? ProviderGetDrawObjectInfo; + internal ICallGateProvider? ProviderResolveDefault; + internal ICallGateProvider? ProviderResolveCharacter; + internal ICallGateProvider? ProviderGetDrawObjectInfo; + internal ICallGateProvider? ProviderReverseResolvePath; private void InitializeResolveProviders( DalamudPluginInterface pi ) { try { - ProviderResolveDefault = pi.GetIpcProvider< string, string >( LabelProviderResolveDefault ); + ProviderResolveDefault = pi.GetIpcProvider( LabelProviderResolveDefault ); ProviderResolveDefault.RegisterFunc( Api.ResolvePath ); } catch( Exception e ) @@ -208,7 +228,7 @@ public partial class PenumbraIpc try { - ProviderResolveCharacter = pi.GetIpcProvider< string, string, string >( LabelProviderResolveCharacter ); + ProviderResolveCharacter = pi.GetIpcProvider( LabelProviderResolveCharacter ); ProviderResolveCharacter.RegisterFunc( Api.ResolvePath ); } catch( Exception e ) @@ -218,13 +238,23 @@ public partial class PenumbraIpc try { - ProviderGetDrawObjectInfo = pi.GetIpcProvider< IntPtr, (IntPtr, string) >( LabelProviderGetDrawObjectInfo ); + ProviderGetDrawObjectInfo = pi.GetIpcProvider( LabelProviderGetDrawObjectInfo ); ProviderGetDrawObjectInfo.RegisterFunc( Api.GetDrawObjectInfo ); } catch( Exception e ) { PluginLog.Error( $"Error registering IPC provider for {LabelProviderGetDrawObjectInfo}:\n{e}" ); } + + try + { + ProviderReverseResolvePath = pi.GetIpcProvider( LabelProviderReverseResolvePath ); + ProviderReverseResolvePath.RegisterFunc( Api.ReverseResolvePath ); + } + catch( Exception e ) + { + PluginLog.Error( $"Error registering IPC provider for {LabelProviderGetDrawObjectInfo}:\n{e}" ); + } } private void DisposeResolveProviders() @@ -238,12 +268,12 @@ public partial class PenumbraIpc public partial class PenumbraIpc { public const string LabelProviderChangedItemTooltip = "Penumbra.ChangedItemTooltip"; - public const string LabelProviderChangedItemClick = "Penumbra.ChangedItemClick"; - public const string LabelProviderGetChangedItems = "Penumbra.GetChangedItems"; + public const string LabelProviderChangedItemClick = "Penumbra.ChangedItemClick"; + public const string LabelProviderGetChangedItems = "Penumbra.GetChangedItems"; - internal ICallGateProvider< ChangedItemType, uint, object >? ProviderChangedItemTooltip; - internal ICallGateProvider< MouseButton, ChangedItemType, uint, object >? ProviderChangedItemClick; - internal ICallGateProvider< string, IReadOnlyDictionary< string, object? > >? ProviderGetChangedItems; + internal ICallGateProvider? ProviderChangedItemTooltip; + internal ICallGateProvider? ProviderChangedItemClick; + internal ICallGateProvider>? ProviderGetChangedItems; private void OnClick( MouseButton click, object? item ) { @@ -261,8 +291,8 @@ public partial class PenumbraIpc { try { - ProviderChangedItemTooltip = pi.GetIpcProvider< ChangedItemType, uint, object >( LabelProviderChangedItemTooltip ); - Api.ChangedItemTooltip += OnTooltip; + ProviderChangedItemTooltip = pi.GetIpcProvider( LabelProviderChangedItemTooltip ); + Api.ChangedItemTooltip += OnTooltip; } catch( Exception e ) { @@ -271,8 +301,8 @@ public partial class PenumbraIpc try { - ProviderChangedItemClick = pi.GetIpcProvider< MouseButton, ChangedItemType, uint, object >( LabelProviderChangedItemClick ); - Api.ChangedItemClicked += OnClick; + ProviderChangedItemClick = pi.GetIpcProvider( LabelProviderChangedItemClick ); + Api.ChangedItemClicked += OnClick; } catch( Exception e ) { @@ -281,7 +311,7 @@ public partial class PenumbraIpc try { - ProviderGetChangedItems = pi.GetIpcProvider< string, IReadOnlyDictionary< string, object? > >( LabelProviderGetChangedItems ); + ProviderGetChangedItems = pi.GetIpcProvider>( LabelProviderGetChangedItems ); ProviderGetChangedItems.RegisterFunc( Api.GetChangedItemsForCollection ); } catch( Exception e ) @@ -300,23 +330,23 @@ public partial class PenumbraIpc public partial class PenumbraIpc { - public const string LabelProviderGetMods = "Penumbra.GetMods"; - public const string LabelProviderGetCollections = "Penumbra.GetCollections"; - public const string LabelProviderCurrentCollectionName = "Penumbra.GetCurrentCollectionName"; - public const string LabelProviderDefaultCollectionName = "Penumbra.GetDefaultCollectionName"; + public const string LabelProviderGetMods = "Penumbra.GetMods"; + public const string LabelProviderGetCollections = "Penumbra.GetCollections"; + public const string LabelProviderCurrentCollectionName = "Penumbra.GetCurrentCollectionName"; + public const string LabelProviderDefaultCollectionName = "Penumbra.GetDefaultCollectionName"; public const string LabelProviderCharacterCollectionName = "Penumbra.GetCharacterCollectionName"; - internal ICallGateProvider< IList< (string, string) > >? ProviderGetMods; - internal ICallGateProvider< IList< string > >? ProviderGetCollections; - internal ICallGateProvider< string >? ProviderCurrentCollectionName; - internal ICallGateProvider< string >? ProviderDefaultCollectionName; - internal ICallGateProvider< string, (string, bool) >? ProviderCharacterCollectionName; + internal ICallGateProvider>? ProviderGetMods; + internal ICallGateProvider>? ProviderGetCollections; + internal ICallGateProvider? ProviderCurrentCollectionName; + internal ICallGateProvider? ProviderDefaultCollectionName; + internal ICallGateProvider? ProviderCharacterCollectionName; private void InitializeDataProviders( DalamudPluginInterface pi ) { try { - ProviderGetMods = pi.GetIpcProvider< IList< (string, string) > >( LabelProviderGetMods ); + ProviderGetMods = pi.GetIpcProvider>( LabelProviderGetMods ); ProviderGetMods.RegisterFunc( Api.GetModList ); } catch( Exception e ) @@ -326,7 +356,7 @@ public partial class PenumbraIpc try { - ProviderGetCollections = pi.GetIpcProvider< IList< string > >( LabelProviderGetCollections ); + ProviderGetCollections = pi.GetIpcProvider>( LabelProviderGetCollections ); ProviderGetCollections.RegisterFunc( Api.GetCollections ); } catch( Exception e ) @@ -336,7 +366,7 @@ public partial class PenumbraIpc try { - ProviderCurrentCollectionName = pi.GetIpcProvider< string >( LabelProviderCurrentCollectionName ); + ProviderCurrentCollectionName = pi.GetIpcProvider( LabelProviderCurrentCollectionName ); ProviderCurrentCollectionName.RegisterFunc( Api.GetCurrentCollection ); } catch( Exception e ) @@ -346,7 +376,7 @@ public partial class PenumbraIpc try { - ProviderDefaultCollectionName = pi.GetIpcProvider< string >( LabelProviderDefaultCollectionName ); + ProviderDefaultCollectionName = pi.GetIpcProvider( LabelProviderDefaultCollectionName ); ProviderDefaultCollectionName.RegisterFunc( Api.GetDefaultCollection ); } catch( Exception e ) @@ -356,7 +386,7 @@ public partial class PenumbraIpc try { - ProviderCharacterCollectionName = pi.GetIpcProvider< string, ( string, bool) >( LabelProviderCharacterCollectionName ); + ProviderCharacterCollectionName = pi.GetIpcProvider( LabelProviderCharacterCollectionName ); ProviderCharacterCollectionName.RegisterFunc( Api.GetCharacterCollection ); } catch( Exception e ) diff --git a/Penumbra/Collections/ModCollection.Cache.Access.cs b/Penumbra/Collections/ModCollection.Cache.Access.cs index 2e3bda92..871280a2 100644 --- a/Penumbra/Collections/ModCollection.Cache.Access.cs +++ b/Penumbra/Collections/ModCollection.Cache.Access.cs @@ -44,6 +44,7 @@ public partial class ModCollection PluginLog.Verbose( "Cleared cache of collection {Name:l}.", Name ); } + public List? ResolveReversePath( FullPath path ) => _cache?.ReverseResolvePath( path ); public FullPath? ResolvePath( Utf8GamePath path ) => _cache?.ResolvePath( path ); diff --git a/Penumbra/Collections/ModCollection.Cache.cs b/Penumbra/Collections/ModCollection.Cache.cs index 6e959e69..c1ed8f1c 100644 --- a/Penumbra/Collections/ModCollection.Cache.cs +++ b/Penumbra/Collections/ModCollection.Cache.cs @@ -12,7 +12,7 @@ using Penumbra.Util; namespace Penumbra.Collections; public record struct ModPath( Mod Mod, FullPath Path ); -public record ModConflicts( Mod Mod2, List< object > Conflicts, bool HasPriority, bool Solved ); +public record ModConflicts( Mod Mod2, List Conflicts, bool HasPriority, bool Solved ); public partial class ModCollection { @@ -20,17 +20,17 @@ public partial class ModCollection // It will only be setup if a collection gets activated in any way. private class Cache : IDisposable { - private readonly ModCollection _collection; - private readonly SortedList< string, (SingleArray< Mod >, object?) > _changedItems = new(); - public readonly Dictionary< Utf8GamePath, ModPath > ResolvedFiles = new(); - public readonly MetaManager MetaManipulations; - private readonly Dictionary< Mod, SingleArray< ModConflicts > > _conflicts = new(); + private readonly ModCollection _collection; + private readonly SortedList, object?)> _changedItems = new(); + public readonly Dictionary ResolvedFiles = new(); + public readonly MetaManager MetaManipulations; + private readonly Dictionary> _conflicts = new(); - public IEnumerable< SingleArray< ModConflicts > > AllConflicts + public IEnumerable> AllConflicts => _conflicts.Values; - public SingleArray< ModConflicts > Conflicts( Mod mod ) - => _conflicts.TryGetValue( mod, out var c ) ? c : new SingleArray< ModConflicts >(); + public SingleArray Conflicts( Mod mod ) + => _conflicts.TryGetValue( mod, out var c ) ? c : new SingleArray(); // Count the number of changes of the effective file list. // This is used for material and imc changes. @@ -38,7 +38,7 @@ public partial class ModCollection private int _changedItemsSaveCounter = -1; // Obtain currently changed items. Computes them if they haven't been computed before. - public IReadOnlyDictionary< string, (SingleArray< Mod >, object?) > ChangedItems + public IReadOnlyDictionary, object?)> ChangedItems { get { @@ -50,15 +50,15 @@ public partial class ModCollection // The cache reacts through events on its collection changing. public Cache( ModCollection collection ) { - _collection = collection; - MetaManipulations = new MetaManager( collection ); - _collection.ModSettingChanged += OnModSettingChange; + _collection = collection; + MetaManipulations = new MetaManager( collection ); + _collection.ModSettingChanged += OnModSettingChange; _collection.InheritanceChanged += OnInheritanceChange; } public void Dispose() { - _collection.ModSettingChanged -= OnModSettingChange; + _collection.ModSettingChanged -= OnModSettingChange; _collection.InheritanceChanged -= OnInheritanceChange; } @@ -79,43 +79,50 @@ public partial class ModCollection return candidate.Path; } + public List ReverseResolvePath( FullPath localFilePath ) + { + string strToSearchFor = localFilePath.FullName.Replace( '/', '\\' ).ToLower(); + return ResolvedFiles.Where( f => f.Value.Path.FullName.ToLower() == strToSearchFor ) + .Select( kvp => kvp.Key ).ToList(); + } + private void OnModSettingChange( ModSettingChange type, int modIdx, int oldValue, int groupIdx, bool _ ) { switch( type ) { case ModSettingChange.Inheritance: - ReloadMod( Penumbra.ModManager[ modIdx ], true ); + ReloadMod( Penumbra.ModManager[modIdx], true ); break; case ModSettingChange.EnableState: if( oldValue == 0 ) { - AddMod( Penumbra.ModManager[ modIdx ], true ); + AddMod( Penumbra.ModManager[modIdx], true ); } else if( oldValue == 1 ) { - RemoveMod( Penumbra.ModManager[ modIdx ], true ); + RemoveMod( Penumbra.ModManager[modIdx], true ); } - else if( _collection[ modIdx ].Settings?.Enabled == true ) + else if( _collection[modIdx].Settings?.Enabled == true ) { - ReloadMod( Penumbra.ModManager[ modIdx ], true ); + ReloadMod( Penumbra.ModManager[modIdx], true ); } else { - RemoveMod( Penumbra.ModManager[ modIdx ], true ); + RemoveMod( Penumbra.ModManager[modIdx], true ); } break; case ModSettingChange.Priority: - if( Conflicts( Penumbra.ModManager[ modIdx ] ).Count > 0 ) + if( Conflicts( Penumbra.ModManager[modIdx] ).Count > 0 ) { - ReloadMod( Penumbra.ModManager[ modIdx ], true ); + ReloadMod( Penumbra.ModManager[modIdx], true ); } break; case ModSettingChange.Setting: - if( _collection[ modIdx ].Settings?.Enabled == true ) + if( _collection[modIdx].Settings?.Enabled == true ) { - ReloadMod( Penumbra.ModManager[ modIdx ], true ); + ReloadMod( Penumbra.ModManager[modIdx], true ); } break; @@ -199,7 +206,7 @@ public partial class ModCollection var newConflicts = Conflicts( conflict.Mod2 ).Remove( c => c.Mod2 == mod ); if( newConflicts.Count > 0 ) { - _conflicts[ conflict.Mod2 ] = newConflicts; + _conflicts[conflict.Mod2] = newConflicts; } else { @@ -223,7 +230,7 @@ public partial class ModCollection // Add all files and possibly manipulations of a given mod according to its settings in this collection. public void AddMod( Mod mod, bool addMetaChanges ) { - var settings = _collection[ mod.Index ].Settings; + var settings = _collection[mod.Index].Settings; if( settings is not { Enabled: true } ) { return; @@ -236,23 +243,23 @@ public partial class ModCollection continue; } - var config = settings.Settings[ groupIndex ]; + var config = settings.Settings[groupIndex]; switch( group.Type ) { case SelectType.Single: - AddSubMod( group[ ( int )config ], mod ); + AddSubMod( group[( int )config], mod ); break; case SelectType.Multi: - { - foreach( var (option, _) in group.WithIndex() - .OrderByDescending( p => group.OptionPriority( p.Item2 ) ) - .Where( p => ( ( 1 << p.Item2 ) & config ) != 0 ) ) { - AddSubMod( option, mod ); - } + foreach( var (option, _) in group.WithIndex() + .OrderByDescending( p => group.OptionPriority( p.Item2 ) ) + .Where( p => ( ( 1 << p.Item2 ) & config ) != 0 ) ) + { + AddSubMod( option, mod ); + } - break; - } + break; + } } } @@ -305,7 +312,7 @@ public partial class ModCollection return; } - var modPath = ResolvedFiles[ path ]; + var modPath = ResolvedFiles[path]; // Lower prioritized option in the same mod. if( mod == modPath.Mod ) { @@ -314,14 +321,14 @@ public partial class ModCollection if( AddConflict( path, mod, modPath.Mod ) ) { - ResolvedFiles[ path ] = new ModPath( mod, file ); + ResolvedFiles[path] = new ModPath( mod, file ); } } // Remove all empty conflict sets for a given mod with the given conflicts. // If transitive is true, also removes the corresponding version of the other mod. - private void RemoveEmptyConflicts( Mod mod, SingleArray< ModConflicts > oldConflicts, bool transitive ) + private void RemoveEmptyConflicts( Mod mod, SingleArray oldConflicts, bool transitive ) { var changedConflicts = oldConflicts.Remove( c => { @@ -343,7 +350,7 @@ public partial class ModCollection } else { - _conflicts[ mod ] = changedConflicts; + _conflicts[mod] = changedConflicts; } } @@ -352,15 +359,15 @@ public partial class ModCollection // Returns if the added mod takes priority before the existing mod. private bool AddConflict( object data, Mod addedMod, Mod existingMod ) { - var addedPriority = addedMod.Index >= 0 ? _collection[ addedMod.Index ].Settings!.Priority : int.MaxValue; - var existingPriority = existingMod.Index >= 0 ? _collection[ existingMod.Index ].Settings!.Priority : int.MaxValue; + var addedPriority = addedMod.Index >= 0 ? _collection[addedMod.Index].Settings!.Priority : int.MaxValue; + var existingPriority = existingMod.Index >= 0 ? _collection[existingMod.Index].Settings!.Priority : int.MaxValue; if( existingPriority < addedPriority ) { var tmpConflicts = Conflicts( existingMod ); foreach( var conflict in tmpConflicts ) { - if( data is Utf8GamePath path && conflict.Conflicts.RemoveAll( p => p is Utf8GamePath x && x.Equals( path ) ) > 0 + if( data is Utf8GamePath path && conflict.Conflicts.RemoveAll( p => p is Utf8GamePath x && x.Equals( path ) ) > 0 || data is MetaManipulation meta && conflict.Conflicts.RemoveAll( m => m is MetaManipulation x && x.Equals( meta ) ) > 0 ) { AddConflict( data, addedMod, conflict.Mod2 ); @@ -370,7 +377,7 @@ public partial class ModCollection RemoveEmptyConflicts( existingMod, tmpConflicts, true ); } - var addedConflicts = Conflicts( addedMod ); + var addedConflicts = Conflicts( addedMod ); var existingConflicts = Conflicts( existingMod ); if( addedConflicts.FindFirst( c => c.Mod2 == existingMod, out var oldConflicts ) ) { @@ -380,10 +387,10 @@ public partial class ModCollection else { // Add the same conflict list to both conflict directions. - var conflictList = new List< object > { data }; - _conflicts[ addedMod ] = addedConflicts.Append( new ModConflicts( existingMod, conflictList, existingPriority < addedPriority, + var conflictList = new List { data }; + _conflicts[addedMod] = addedConflicts.Append( new ModConflicts( existingMod, conflictList, existingPriority < addedPriority, existingPriority != addedPriority ) ); - _conflicts[ existingMod ] = existingConflicts.Append( new ModConflicts( addedMod, conflictList, + _conflicts[existingMod] = existingConflicts.Append( new ModConflicts( addedMod, conflictList, existingPriority >= addedPriority, existingPriority != addedPriority ) ); } @@ -441,15 +448,15 @@ public partial class ModCollection { if( !_changedItems.TryGetValue( name, out var data ) ) { - _changedItems.Add( name, ( new SingleArray< Mod >( modPath.Mod ), obj ) ); + _changedItems.Add( name, (new SingleArray( modPath.Mod ), obj) ); } else if( !data.Item1.Contains( modPath.Mod ) ) { - _changedItems[ name ] = ( data.Item1.Append( modPath.Mod ), obj is int x && data.Item2 is int y ? x + y : obj ); + _changedItems[name] = (data.Item1.Append( modPath.Mod ), obj is int x && data.Item2 is int y ? x + y : obj); } else if( obj is int x && data.Item2 is int y ) { - _changedItems[ name ] = ( data.Item1, x + y ); + _changedItems[name] = (data.Item1, x + y); } } } diff --git a/Penumbra/Interop/ObjectReloader.cs b/Penumbra/Interop/ObjectReloader.cs index 058fc87c..d58d434c 100644 --- a/Penumbra/Interop/ObjectReloader.cs +++ b/Penumbra/Interop/ObjectReloader.cs @@ -25,6 +25,7 @@ public unsafe partial class ObjectReloader private static void EnableDraw( GameObject actor ) => ( ( delegate* unmanaged< IntPtr, void >** )actor.Address )[ 0 ][ 16 ]( actor.Address ); + public event EventHandler? ObjectIsRedrawn; // Check whether we currently are in GPose. // Also clear the name list. @@ -281,6 +282,8 @@ public sealed unsafe partial class ObjectReloader : IDisposable break; default: throw new ArgumentOutOfRangeException( nameof( settings ), settings, null ); } + + ObjectIsRedrawn?.Invoke( actor, new EventArgs() ); } private static GameObject? GetLocalPlayer() From bcd62cbe69eb2e10465f3300fda67f1ceaf6c8cc Mon Sep 17 00:00:00 2001 From: Stanley Dimant Date: Thu, 16 Jun 2022 23:51:16 +0200 Subject: [PATCH 05/11] formating fixes --- Penumbra/Api/PenumbraApi.cs | 47 +++---- Penumbra/Api/PenumbraIpc.cs | 130 ++++++++++---------- Penumbra/Collections/ModCollection.Cache.cs | 108 ++++++++-------- 3 files changed, 144 insertions(+), 141 deletions(-) diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index eb8f57b2..87904e0a 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -18,7 +18,7 @@ namespace Penumbra.Api; public class PenumbraApi : IDisposable, IPenumbraApi { public int ApiVersion { get; } = 4; - private Penumbra? _penumbra; + private Penumbra? _penumbra; private Lumina.GameData? _lumina; public event EventHandler? ObjectIsRedrawn; @@ -29,8 +29,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi { _penumbra = penumbra; _lumina = ( Lumina.GameData? )Dalamud.GameData.GetType() - .GetField( "gameData", BindingFlags.Instance | BindingFlags.NonPublic ) - ?.GetValue( Dalamud.GameData ); + .GetField( "gameData", BindingFlags.Instance | BindingFlags.NonPublic ) + ?.GetValue( Dalamud.GameData ); _penumbra.ObjectReloader.ObjectIsRedrawn += ObjectReloader_ObjectIsRedrawn; } @@ -42,8 +42,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi public void Dispose() { _penumbra!.ObjectReloader.ObjectIsRedrawn -= ObjectReloader_ObjectIsRedrawn; - _penumbra = null; - _lumina = null; + _penumbra = null; + _lumina = null; } public event ChangedItemClick? ChangedItemClicked; @@ -57,7 +57,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi public IPluginConfiguration GetConfiguration() { CheckInitialized(); - return JsonConvert.DeserializeObject( JsonConvert.SerializeObject( Penumbra.Config ) ); + return JsonConvert.DeserializeObject< Configuration >( JsonConvert.SerializeObject( Penumbra.Config ) ); } public event ChangedItemHover? ChangedItemTooltip; @@ -112,7 +112,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi } var gamePath = Utf8GamePath.FromString( path, out var p, true ) ? p : Utf8GamePath.Empty; - var ret = collection.ResolvePath( gamePath ); + var ret = collection.ResolvePath( gamePath ); return ret?.ToString() ?? path; } @@ -138,22 +138,23 @@ public class PenumbraApi : IDisposable, IPenumbraApi } var gamePath = Utf8GamePath.FromString( path, out var p, true ) ? p : Utf8GamePath.Empty; - var ret = Penumbra.CollectionManager.Character( characterName ).ResolveReversePath( new FullPath( path ) ) ?? new List(); + var ret = Penumbra.CollectionManager.Character( characterName ).ResolveReversePath( new FullPath( path ) ) ?? + new List< Utf8GamePath >(); if( ret.Count == 0 ) ret.Add( gamePath ); return ret.Select( r => r.ToString() ).ToArray(); } - private T? GetFileIntern( string resolvedPath ) where T : FileResource + private T? GetFileIntern< T >( string resolvedPath ) where T : FileResource { CheckInitialized(); try { if( Path.IsPathRooted( resolvedPath ) ) { - return _lumina?.GetFileFromDisk( resolvedPath ); + return _lumina?.GetFileFromDisk< T >( resolvedPath ); } - return Dalamud.GameData.GetFile( resolvedPath ); + return Dalamud.GameData.GetFile< T >( resolvedPath ); } catch( Exception e ) { @@ -162,13 +163,13 @@ public class PenumbraApi : IDisposable, IPenumbraApi } } - public T? GetFile( string gamePath ) where T : FileResource - => GetFileIntern( ResolvePath( gamePath ) ); + public T? GetFile< T >( string gamePath ) where T : FileResource + => GetFileIntern< T >( ResolvePath( gamePath ) ); - public T? GetFile( string gamePath, string characterName ) where T : FileResource - => GetFileIntern( ResolvePath( gamePath, characterName ) ); + public T? GetFile< T >( string gamePath, string characterName ) where T : FileResource + => GetFileIntern< T >( ResolvePath( gamePath, characterName ) ); - public IReadOnlyDictionary GetChangedItemsForCollection( string collectionName ) + public IReadOnlyDictionary< string, object? > GetChangedItemsForCollection( string collectionName ) { CheckInitialized(); try @@ -184,7 +185,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi } PluginLog.Warning( $"Collection {collectionName} does not exist or is not loaded." ); - return new Dictionary(); + return new Dictionary< string, object? >(); } catch( Exception e ) { @@ -193,7 +194,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi } } - public IList GetCollections() + public IList< string > GetCollections() { CheckInitialized(); return Penumbra.CollectionManager.Skip( 1 ).Select( c => c.Name ).ToArray(); @@ -215,21 +216,21 @@ public class PenumbraApi : IDisposable, IPenumbraApi { CheckInitialized(); return Penumbra.CollectionManager.Characters.TryGetValue( characterName, out var collection ) - ? (collection.Name, true) - : (Penumbra.CollectionManager.Default.Name, false); + ? ( collection.Name, true ) + : ( Penumbra.CollectionManager.Default.Name, false ); } public (IntPtr, string) GetDrawObjectInfo( IntPtr drawObject ) { CheckInitialized(); var (obj, collection) = _penumbra!.PathResolver.IdentifyDrawObject( drawObject ); - return (obj, collection.Name); + return ( obj, collection.Name ); } - public IList<(string, string)> GetModList() + public IList< (string, string) > GetModList() { CheckInitialized(); - return Penumbra.ModManager.Select( m => (m.ModPath.Name, m.Name.Text) ).ToArray(); + return Penumbra.ModManager.Select( m => ( m.ModPath.Name, m.Name.Text ) ).ToArray(); } public IDictionary< string, (IList, SelectType) >? GetAvailableModSettings( string modDirectory, string modName ) diff --git a/Penumbra/Api/PenumbraIpc.cs b/Penumbra/Api/PenumbraIpc.cs index f5c59830..1d197b07 100644 --- a/Penumbra/Api/PenumbraIpc.cs +++ b/Penumbra/Api/PenumbraIpc.cs @@ -38,23 +38,23 @@ public partial class PenumbraIpc : IDisposable public partial class PenumbraIpc { - public const string LabelProviderInitialized = "Penumbra.Initialized"; - public const string LabelProviderDisposed = "Penumbra.Disposed"; - public const string LabelProviderApiVersion = "Penumbra.ApiVersion"; - public const string LabelProviderGetModDirectory = "Penumbra.GetModDirectory"; + public const string LabelProviderInitialized = "Penumbra.Initialized"; + public const string LabelProviderDisposed = "Penumbra.Disposed"; + public const string LabelProviderApiVersion = "Penumbra.ApiVersion"; + public const string LabelProviderGetModDirectory = "Penumbra.GetModDirectory"; public const string LabelProviderGetConfiguration = "Penumbra.GetConfiguration"; - internal ICallGateProvider? ProviderInitialized; - internal ICallGateProvider? ProviderDisposed; - internal ICallGateProvider? ProviderApiVersion; - internal ICallGateProvider? ProviderGetModDirectory; - internal ICallGateProvider? ProviderGetConfiguration; + internal ICallGateProvider< object? >? ProviderInitialized; + internal ICallGateProvider< object? >? ProviderDisposed; + internal ICallGateProvider< int >? ProviderApiVersion; + internal ICallGateProvider< string >? ProviderGetModDirectory; + internal ICallGateProvider< IPluginConfiguration >? ProviderGetConfiguration; private void InitializeGeneralProviders( DalamudPluginInterface pi ) { try { - ProviderInitialized = pi.GetIpcProvider( LabelProviderInitialized ); + ProviderInitialized = pi.GetIpcProvider< object? >( LabelProviderInitialized ); } catch( Exception e ) { @@ -63,7 +63,7 @@ public partial class PenumbraIpc try { - ProviderDisposed = pi.GetIpcProvider( LabelProviderDisposed ); + ProviderDisposed = pi.GetIpcProvider< object? >( LabelProviderDisposed ); } catch( Exception e ) { @@ -72,7 +72,7 @@ public partial class PenumbraIpc try { - ProviderApiVersion = pi.GetIpcProvider( LabelProviderApiVersion ); + ProviderApiVersion = pi.GetIpcProvider< int >( LabelProviderApiVersion ); ProviderApiVersion.RegisterFunc( () => Api.ApiVersion ); } catch( Exception e ) @@ -82,7 +82,7 @@ public partial class PenumbraIpc try { - ProviderGetModDirectory = pi.GetIpcProvider( LabelProviderGetModDirectory ); + ProviderGetModDirectory = pi.GetIpcProvider< string >( LabelProviderGetModDirectory ); ProviderGetModDirectory.RegisterFunc( Api.GetModDirectory ); } catch( Exception e ) @@ -92,7 +92,7 @@ public partial class PenumbraIpc try { - ProviderGetConfiguration = pi.GetIpcProvider( LabelProviderGetConfiguration ); + ProviderGetConfiguration = pi.GetIpcProvider< IPluginConfiguration >( LabelProviderGetConfiguration ); ProviderGetConfiguration.RegisterFunc( Api.GetConfiguration ); } catch( Exception e ) @@ -111,17 +111,17 @@ public partial class PenumbraIpc public partial class PenumbraIpc { - public const string LabelProviderRedrawName = "Penumbra.RedrawObjectByName"; - public const string LabelProviderRedrawIndex = "Penumbra.RedrawObjectByIndex"; - public const string LabelProviderRedrawObject = "Penumbra.RedrawObject"; - public const string LabelProviderRedrawAll = "Penumbra.RedrawAll"; + public const string LabelProviderRedrawName = "Penumbra.RedrawObjectByName"; + public const string LabelProviderRedrawIndex = "Penumbra.RedrawObjectByIndex"; + public const string LabelProviderRedrawObject = "Penumbra.RedrawObject"; + public const string LabelProviderRedrawAll = "Penumbra.RedrawAll"; public const string LabelProviderObjectIsRedrawn = "Penumbra.ObjectIsRedrawn"; - internal ICallGateProvider? ProviderRedrawName; - internal ICallGateProvider? ProviderRedrawIndex; - internal ICallGateProvider? ProviderRedrawObject; - internal ICallGateProvider? ProviderRedrawAll; - internal ICallGateProvider ProviderObjectIsRedrawn; + internal ICallGateProvider< string, int, object >? ProviderRedrawName; + internal ICallGateProvider< int, int, object >? ProviderRedrawIndex; + internal ICallGateProvider< GameObject, int, object >? ProviderRedrawObject; + internal ICallGateProvider< int, object >? ProviderRedrawAll; + internal ICallGateProvider< string, string >? ProviderObjectIsRedrawn; private static RedrawType CheckRedrawType( int value ) { @@ -138,7 +138,7 @@ public partial class PenumbraIpc { try { - ProviderRedrawName = pi.GetIpcProvider( LabelProviderRedrawName ); + ProviderRedrawName = pi.GetIpcProvider< string, int, object >( LabelProviderRedrawName ); ProviderRedrawName.RegisterAction( ( s, i ) => Api.RedrawObject( s, CheckRedrawType( i ) ) ); } catch( Exception e ) @@ -148,7 +148,7 @@ public partial class PenumbraIpc try { - ProviderRedrawIndex = pi.GetIpcProvider( LabelProviderRedrawIndex ); + ProviderRedrawIndex = pi.GetIpcProvider< int, int, object >( LabelProviderRedrawIndex ); ProviderRedrawIndex.RegisterAction( ( idx, i ) => Api.RedrawObject( idx, CheckRedrawType( i ) ) ); } catch( Exception e ) @@ -158,7 +158,7 @@ public partial class PenumbraIpc try { - ProviderRedrawObject = pi.GetIpcProvider( LabelProviderRedrawObject ); + ProviderRedrawObject = pi.GetIpcProvider< GameObject, int, object >( LabelProviderRedrawObject ); ProviderRedrawObject.RegisterAction( ( o, i ) => Api.RedrawObject( o, CheckRedrawType( i ) ) ); } catch( Exception e ) @@ -168,7 +168,7 @@ public partial class PenumbraIpc try { - ProviderRedrawAll = pi.GetIpcProvider( LabelProviderRedrawAll ); + ProviderRedrawAll = pi.GetIpcProvider< int, object >( LabelProviderRedrawAll ); ProviderRedrawAll.RegisterAction( i => Api.RedrawAll( CheckRedrawType( i ) ) ); } catch( Exception e ) @@ -178,8 +178,8 @@ public partial class PenumbraIpc try { - ProviderObjectIsRedrawn = pi.GetIpcProvider( LabelProviderObjectIsRedrawn ); - Api.ObjectIsRedrawn += Api_ObjectIsRedrawn; + ProviderObjectIsRedrawn = pi.GetIpcProvider< string, string >( LabelProviderObjectIsRedrawn ); + Api.ObjectIsRedrawn += Api_ObjectIsRedrawn; } catch( Exception e ) { @@ -189,7 +189,7 @@ public partial class PenumbraIpc private void Api_ObjectIsRedrawn( object? sender, EventArgs e ) { - ProviderObjectIsRedrawn.SendMessage( ( ( GameObject? )sender )?.Name.ToString() ?? "" ); + ProviderObjectIsRedrawn?.SendMessage( ( ( GameObject? )sender )?.Name.ToString() ?? "" ); } private void DisposeRedrawProviders() @@ -204,21 +204,21 @@ public partial class PenumbraIpc public partial class PenumbraIpc { - public const string LabelProviderResolveDefault = "Penumbra.ResolveDefaultPath"; - public const string LabelProviderResolveCharacter = "Penumbra.ResolveCharacterPath"; - public const string LabelProviderGetDrawObjectInfo = "Penumbra.GetDrawObjectInfo"; + public const string LabelProviderResolveDefault = "Penumbra.ResolveDefaultPath"; + public const string LabelProviderResolveCharacter = "Penumbra.ResolveCharacterPath"; + public const string LabelProviderGetDrawObjectInfo = "Penumbra.GetDrawObjectInfo"; public const string LabelProviderReverseResolvePath = "Penumbra.ReverseResolvePath"; - internal ICallGateProvider? ProviderResolveDefault; - internal ICallGateProvider? ProviderResolveCharacter; - internal ICallGateProvider? ProviderGetDrawObjectInfo; - internal ICallGateProvider? ProviderReverseResolvePath; + internal ICallGateProvider< string, string >? ProviderResolveDefault; + internal ICallGateProvider< string, string, string >? ProviderResolveCharacter; + internal ICallGateProvider< IntPtr, (IntPtr, string) >? ProviderGetDrawObjectInfo; + internal ICallGateProvider< string, string, string[] >? ProviderReverseResolvePath; private void InitializeResolveProviders( DalamudPluginInterface pi ) { try { - ProviderResolveDefault = pi.GetIpcProvider( LabelProviderResolveDefault ); + ProviderResolveDefault = pi.GetIpcProvider< string, string >( LabelProviderResolveDefault ); ProviderResolveDefault.RegisterFunc( Api.ResolvePath ); } catch( Exception e ) @@ -228,7 +228,7 @@ public partial class PenumbraIpc try { - ProviderResolveCharacter = pi.GetIpcProvider( LabelProviderResolveCharacter ); + ProviderResolveCharacter = pi.GetIpcProvider< string, string, string >( LabelProviderResolveCharacter ); ProviderResolveCharacter.RegisterFunc( Api.ResolvePath ); } catch( Exception e ) @@ -238,7 +238,7 @@ public partial class PenumbraIpc try { - ProviderGetDrawObjectInfo = pi.GetIpcProvider( LabelProviderGetDrawObjectInfo ); + ProviderGetDrawObjectInfo = pi.GetIpcProvider< IntPtr, (IntPtr, string) >( LabelProviderGetDrawObjectInfo ); ProviderGetDrawObjectInfo.RegisterFunc( Api.GetDrawObjectInfo ); } catch( Exception e ) @@ -248,7 +248,7 @@ public partial class PenumbraIpc try { - ProviderReverseResolvePath = pi.GetIpcProvider( LabelProviderReverseResolvePath ); + ProviderReverseResolvePath = pi.GetIpcProvider< string, string, string[] >( LabelProviderReverseResolvePath ); ProviderReverseResolvePath.RegisterFunc( Api.ReverseResolvePath ); } catch( Exception e ) @@ -268,12 +268,12 @@ public partial class PenumbraIpc public partial class PenumbraIpc { public const string LabelProviderChangedItemTooltip = "Penumbra.ChangedItemTooltip"; - public const string LabelProviderChangedItemClick = "Penumbra.ChangedItemClick"; - public const string LabelProviderGetChangedItems = "Penumbra.GetChangedItems"; + public const string LabelProviderChangedItemClick = "Penumbra.ChangedItemClick"; + public const string LabelProviderGetChangedItems = "Penumbra.GetChangedItems"; - internal ICallGateProvider? ProviderChangedItemTooltip; - internal ICallGateProvider? ProviderChangedItemClick; - internal ICallGateProvider>? ProviderGetChangedItems; + internal ICallGateProvider< ChangedItemType, uint, object >? ProviderChangedItemTooltip; + internal ICallGateProvider< MouseButton, ChangedItemType, uint, object >? ProviderChangedItemClick; + internal ICallGateProvider< string, IReadOnlyDictionary< string, object? > >? ProviderGetChangedItems; private void OnClick( MouseButton click, object? item ) { @@ -291,8 +291,8 @@ public partial class PenumbraIpc { try { - ProviderChangedItemTooltip = pi.GetIpcProvider( LabelProviderChangedItemTooltip ); - Api.ChangedItemTooltip += OnTooltip; + ProviderChangedItemTooltip = pi.GetIpcProvider< ChangedItemType, uint, object >( LabelProviderChangedItemTooltip ); + Api.ChangedItemTooltip += OnTooltip; } catch( Exception e ) { @@ -301,8 +301,8 @@ public partial class PenumbraIpc try { - ProviderChangedItemClick = pi.GetIpcProvider( LabelProviderChangedItemClick ); - Api.ChangedItemClicked += OnClick; + ProviderChangedItemClick = pi.GetIpcProvider< MouseButton, ChangedItemType, uint, object >( LabelProviderChangedItemClick ); + Api.ChangedItemClicked += OnClick; } catch( Exception e ) { @@ -311,7 +311,7 @@ public partial class PenumbraIpc try { - ProviderGetChangedItems = pi.GetIpcProvider>( LabelProviderGetChangedItems ); + ProviderGetChangedItems = pi.GetIpcProvider< string, IReadOnlyDictionary< string, object? > >( LabelProviderGetChangedItems ); ProviderGetChangedItems.RegisterFunc( Api.GetChangedItemsForCollection ); } catch( Exception e ) @@ -330,23 +330,23 @@ public partial class PenumbraIpc public partial class PenumbraIpc { - public const string LabelProviderGetMods = "Penumbra.GetMods"; - public const string LabelProviderGetCollections = "Penumbra.GetCollections"; - public const string LabelProviderCurrentCollectionName = "Penumbra.GetCurrentCollectionName"; - public const string LabelProviderDefaultCollectionName = "Penumbra.GetDefaultCollectionName"; + public const string LabelProviderGetMods = "Penumbra.GetMods"; + public const string LabelProviderGetCollections = "Penumbra.GetCollections"; + public const string LabelProviderCurrentCollectionName = "Penumbra.GetCurrentCollectionName"; + public const string LabelProviderDefaultCollectionName = "Penumbra.GetDefaultCollectionName"; public const string LabelProviderCharacterCollectionName = "Penumbra.GetCharacterCollectionName"; - internal ICallGateProvider>? ProviderGetMods; - internal ICallGateProvider>? ProviderGetCollections; - internal ICallGateProvider? ProviderCurrentCollectionName; - internal ICallGateProvider? ProviderDefaultCollectionName; - internal ICallGateProvider? ProviderCharacterCollectionName; + internal ICallGateProvider< IList< (string, string) > >? ProviderGetMods; + internal ICallGateProvider< IList< string > >? ProviderGetCollections; + internal ICallGateProvider< string >? ProviderCurrentCollectionName; + internal ICallGateProvider< string >? ProviderDefaultCollectionName; + internal ICallGateProvider< string, (string, bool) >? ProviderCharacterCollectionName; private void InitializeDataProviders( DalamudPluginInterface pi ) { try { - ProviderGetMods = pi.GetIpcProvider>( LabelProviderGetMods ); + ProviderGetMods = pi.GetIpcProvider< IList< (string, string) > >( LabelProviderGetMods ); ProviderGetMods.RegisterFunc( Api.GetModList ); } catch( Exception e ) @@ -356,7 +356,7 @@ public partial class PenumbraIpc try { - ProviderGetCollections = pi.GetIpcProvider>( LabelProviderGetCollections ); + ProviderGetCollections = pi.GetIpcProvider< IList< string > >( LabelProviderGetCollections ); ProviderGetCollections.RegisterFunc( Api.GetCollections ); } catch( Exception e ) @@ -366,7 +366,7 @@ public partial class PenumbraIpc try { - ProviderCurrentCollectionName = pi.GetIpcProvider( LabelProviderCurrentCollectionName ); + ProviderCurrentCollectionName = pi.GetIpcProvider< string >( LabelProviderCurrentCollectionName ); ProviderCurrentCollectionName.RegisterFunc( Api.GetCurrentCollection ); } catch( Exception e ) @@ -376,7 +376,7 @@ public partial class PenumbraIpc try { - ProviderDefaultCollectionName = pi.GetIpcProvider( LabelProviderDefaultCollectionName ); + ProviderDefaultCollectionName = pi.GetIpcProvider< string >( LabelProviderDefaultCollectionName ); ProviderDefaultCollectionName.RegisterFunc( Api.GetDefaultCollection ); } catch( Exception e ) @@ -386,7 +386,7 @@ public partial class PenumbraIpc try { - ProviderCharacterCollectionName = pi.GetIpcProvider( LabelProviderCharacterCollectionName ); + ProviderCharacterCollectionName = pi.GetIpcProvider< string, (string, bool) >( LabelProviderCharacterCollectionName ); ProviderCharacterCollectionName.RegisterFunc( Api.GetCharacterCollection ); } catch( Exception e ) diff --git a/Penumbra/Collections/ModCollection.Cache.cs b/Penumbra/Collections/ModCollection.Cache.cs index c1ed8f1c..4b280697 100644 --- a/Penumbra/Collections/ModCollection.Cache.cs +++ b/Penumbra/Collections/ModCollection.Cache.cs @@ -12,7 +12,8 @@ using Penumbra.Util; namespace Penumbra.Collections; public record struct ModPath( Mod Mod, FullPath Path ); -public record ModConflicts( Mod Mod2, List Conflicts, bool HasPriority, bool Solved ); + +public record ModConflicts( Mod Mod2, List< object > Conflicts, bool HasPriority, bool Solved ); public partial class ModCollection { @@ -20,17 +21,17 @@ public partial class ModCollection // It will only be setup if a collection gets activated in any way. private class Cache : IDisposable { - private readonly ModCollection _collection; - private readonly SortedList, object?)> _changedItems = new(); - public readonly Dictionary ResolvedFiles = new(); - public readonly MetaManager MetaManipulations; - private readonly Dictionary> _conflicts = new(); + private readonly ModCollection _collection; + private readonly SortedList< string, (SingleArray< Mod >, object?) > _changedItems = new(); + public readonly Dictionary< Utf8GamePath, ModPath > ResolvedFiles = new(); + public readonly MetaManager MetaManipulations; + private readonly Dictionary< Mod, SingleArray< ModConflicts > > _conflicts = new(); - public IEnumerable> AllConflicts + public IEnumerable< SingleArray< ModConflicts > > AllConflicts => _conflicts.Values; - public SingleArray Conflicts( Mod mod ) - => _conflicts.TryGetValue( mod, out var c ) ? c : new SingleArray(); + public SingleArray< ModConflicts > Conflicts( Mod mod ) + => _conflicts.TryGetValue( mod, out var c ) ? c : new SingleArray< ModConflicts >(); // Count the number of changes of the effective file list. // This is used for material and imc changes. @@ -38,7 +39,7 @@ public partial class ModCollection private int _changedItemsSaveCounter = -1; // Obtain currently changed items. Computes them if they haven't been computed before. - public IReadOnlyDictionary, object?)> ChangedItems + public IReadOnlyDictionary< string, (SingleArray< Mod >, object?) > ChangedItems { get { @@ -50,15 +51,15 @@ public partial class ModCollection // The cache reacts through events on its collection changing. public Cache( ModCollection collection ) { - _collection = collection; - MetaManipulations = new MetaManager( collection ); - _collection.ModSettingChanged += OnModSettingChange; + _collection = collection; + MetaManipulations = new MetaManager( collection ); + _collection.ModSettingChanged += OnModSettingChange; _collection.InheritanceChanged += OnInheritanceChange; } public void Dispose() { - _collection.ModSettingChanged -= OnModSettingChange; + _collection.ModSettingChanged -= OnModSettingChange; _collection.InheritanceChanged -= OnInheritanceChange; } @@ -71,7 +72,7 @@ public partial class ModCollection } if( candidate.Path.InternalName.Length > Utf8GamePath.MaxGamePathLength - || candidate.Path.IsRooted && !candidate.Path.Exists ) + || candidate.Path.IsRooted && !candidate.Path.Exists ) { return null; } @@ -79,10 +80,10 @@ public partial class ModCollection return candidate.Path; } - public List ReverseResolvePath( FullPath localFilePath ) + public List< Utf8GamePath > ReverseResolvePath( FullPath localFilePath ) { string strToSearchFor = localFilePath.FullName.Replace( '/', '\\' ).ToLower(); - return ResolvedFiles.Where( f => f.Value.Path.FullName.ToLower() == strToSearchFor ) + return ResolvedFiles.Where( f => f.Value.Path.FullName.ToLower() == strToSearchFor ) .Select( kvp => kvp.Key ).ToList(); } @@ -91,38 +92,38 @@ public partial class ModCollection switch( type ) { case ModSettingChange.Inheritance: - ReloadMod( Penumbra.ModManager[modIdx], true ); + ReloadMod( Penumbra.ModManager[ modIdx ], true ); break; case ModSettingChange.EnableState: if( oldValue == 0 ) { - AddMod( Penumbra.ModManager[modIdx], true ); + AddMod( Penumbra.ModManager[ modIdx ], true ); } else if( oldValue == 1 ) { - RemoveMod( Penumbra.ModManager[modIdx], true ); + RemoveMod( Penumbra.ModManager[ modIdx ], true ); } - else if( _collection[modIdx].Settings?.Enabled == true ) + else if( _collection[ modIdx ].Settings?.Enabled == true ) { - ReloadMod( Penumbra.ModManager[modIdx], true ); + ReloadMod( Penumbra.ModManager[ modIdx ], true ); } else { - RemoveMod( Penumbra.ModManager[modIdx], true ); + RemoveMod( Penumbra.ModManager[ modIdx ], true ); } break; case ModSettingChange.Priority: - if( Conflicts( Penumbra.ModManager[modIdx] ).Count > 0 ) + if( Conflicts( Penumbra.ModManager[ modIdx ] ).Count > 0 ) { - ReloadMod( Penumbra.ModManager[modIdx], true ); + ReloadMod( Penumbra.ModManager[ modIdx ], true ); } break; case ModSettingChange.Setting: - if( _collection[modIdx].Settings?.Enabled == true ) + if( _collection[ modIdx ].Settings?.Enabled == true ) { - ReloadMod( Penumbra.ModManager[modIdx], true ); + ReloadMod( Penumbra.ModManager[ modIdx ], true ); } break; @@ -206,7 +207,7 @@ public partial class ModCollection var newConflicts = Conflicts( conflict.Mod2 ).Remove( c => c.Mod2 == mod ); if( newConflicts.Count > 0 ) { - _conflicts[conflict.Mod2] = newConflicts; + _conflicts[ conflict.Mod2 ] = newConflicts; } else { @@ -230,7 +231,7 @@ public partial class ModCollection // Add all files and possibly manipulations of a given mod according to its settings in this collection. public void AddMod( Mod mod, bool addMetaChanges ) { - var settings = _collection[mod.Index].Settings; + var settings = _collection[ mod.Index ].Settings; if( settings is not { Enabled: true } ) { return; @@ -243,23 +244,23 @@ public partial class ModCollection continue; } - var config = settings.Settings[groupIndex]; + var config = settings.Settings[ groupIndex ]; switch( group.Type ) { case SelectType.Single: - AddSubMod( group[( int )config], mod ); + AddSubMod( group[ ( int )config ], mod ); break; case SelectType.Multi: + { + foreach( var (option, _) in group.WithIndex() + .OrderByDescending( p => group.OptionPriority( p.Item2 ) ) + .Where( p => ( ( 1 << p.Item2 ) & config ) != 0 ) ) { - foreach( var (option, _) in group.WithIndex() - .OrderByDescending( p => group.OptionPriority( p.Item2 ) ) - .Where( p => ( ( 1 << p.Item2 ) & config ) != 0 ) ) - { - AddSubMod( option, mod ); - } - - break; + AddSubMod( option, mod ); } + + break; + } } } @@ -312,7 +313,7 @@ public partial class ModCollection return; } - var modPath = ResolvedFiles[path]; + var modPath = ResolvedFiles[ path ]; // Lower prioritized option in the same mod. if( mod == modPath.Mod ) { @@ -321,14 +322,14 @@ public partial class ModCollection if( AddConflict( path, mod, modPath.Mod ) ) { - ResolvedFiles[path] = new ModPath( mod, file ); + ResolvedFiles[ path ] = new ModPath( mod, file ); } } // Remove all empty conflict sets for a given mod with the given conflicts. // If transitive is true, also removes the corresponding version of the other mod. - private void RemoveEmptyConflicts( Mod mod, SingleArray oldConflicts, bool transitive ) + private void RemoveEmptyConflicts( Mod mod, SingleArray< ModConflicts > oldConflicts, bool transitive ) { var changedConflicts = oldConflicts.Remove( c => { @@ -350,7 +351,7 @@ public partial class ModCollection } else { - _conflicts[mod] = changedConflicts; + _conflicts[ mod ] = changedConflicts; } } @@ -359,8 +360,8 @@ public partial class ModCollection // Returns if the added mod takes priority before the existing mod. private bool AddConflict( object data, Mod addedMod, Mod existingMod ) { - var addedPriority = addedMod.Index >= 0 ? _collection[addedMod.Index].Settings!.Priority : int.MaxValue; - var existingPriority = existingMod.Index >= 0 ? _collection[existingMod.Index].Settings!.Priority : int.MaxValue; + var addedPriority = addedMod.Index >= 0 ? _collection[ addedMod.Index ].Settings!.Priority : int.MaxValue; + var existingPriority = existingMod.Index >= 0 ? _collection[ existingMod.Index ].Settings!.Priority : int.MaxValue; if( existingPriority < addedPriority ) { @@ -368,7 +369,8 @@ public partial class ModCollection foreach( var conflict in tmpConflicts ) { if( data is Utf8GamePath path && conflict.Conflicts.RemoveAll( p => p is Utf8GamePath x && x.Equals( path ) ) > 0 - || data is MetaManipulation meta && conflict.Conflicts.RemoveAll( m => m is MetaManipulation x && x.Equals( meta ) ) > 0 ) + || data is MetaManipulation meta && + conflict.Conflicts.RemoveAll( m => m is MetaManipulation x && x.Equals( meta ) ) > 0 ) { AddConflict( data, addedMod, conflict.Mod2 ); } @@ -377,7 +379,7 @@ public partial class ModCollection RemoveEmptyConflicts( existingMod, tmpConflicts, true ); } - var addedConflicts = Conflicts( addedMod ); + var addedConflicts = Conflicts( addedMod ); var existingConflicts = Conflicts( existingMod ); if( addedConflicts.FindFirst( c => c.Mod2 == existingMod, out var oldConflicts ) ) { @@ -387,10 +389,10 @@ public partial class ModCollection else { // Add the same conflict list to both conflict directions. - var conflictList = new List { data }; - _conflicts[addedMod] = addedConflicts.Append( new ModConflicts( existingMod, conflictList, existingPriority < addedPriority, + var conflictList = new List< object > { data }; + _conflicts[ addedMod ] = addedConflicts.Append( new ModConflicts( existingMod, conflictList, existingPriority < addedPriority, existingPriority != addedPriority ) ); - _conflicts[existingMod] = existingConflicts.Append( new ModConflicts( addedMod, conflictList, + _conflicts[ existingMod ] = existingConflicts.Append( new ModConflicts( addedMod, conflictList, existingPriority >= addedPriority, existingPriority != addedPriority ) ); } @@ -448,15 +450,15 @@ public partial class ModCollection { if( !_changedItems.TryGetValue( name, out var data ) ) { - _changedItems.Add( name, (new SingleArray( modPath.Mod ), obj) ); + _changedItems.Add( name, ( new SingleArray< Mod >( modPath.Mod ), obj ) ); } else if( !data.Item1.Contains( modPath.Mod ) ) { - _changedItems[name] = (data.Item1.Append( modPath.Mod ), obj is int x && data.Item2 is int y ? x + y : obj); + _changedItems[ name ] = ( data.Item1.Append( modPath.Mod ), obj is int x && data.Item2 is int y ? x + y : obj ); } else if( obj is int x && data.Item2 is int y ) { - _changedItems[name] = (data.Item1, x + y); + _changedItems[ name ] = ( data.Item1, x + y ); } } } From 3c5cff141848a41d86cedd75f5d906cd71d51973 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 17 Jun 2022 17:10:48 +0200 Subject: [PATCH 06/11] Some cleanup, slight changes. --- Penumbra/Api/IPenumbraApi.cs | 5 ++- Penumbra/Api/PenumbraApi.cs | 43 +++++++++---------- Penumbra/Api/PenumbraIpc.cs | 37 ++++++++-------- .../Collections/ModCollection.Cache.Access.cs | 3 +- Penumbra/Collections/ModCollection.Cache.cs | 37 ++++++++++------ Penumbra/Interop/ObjectReloader.cs | 11 +++-- 6 files changed, 74 insertions(+), 62 deletions(-) diff --git a/Penumbra/Api/IPenumbraApi.cs b/Penumbra/Api/IPenumbraApi.cs index b50a98ba..25c828e1 100644 --- a/Penumbra/Api/IPenumbraApi.cs +++ b/Penumbra/Api/IPenumbraApi.cs @@ -20,6 +20,7 @@ public interface IPenumbraApiBase public delegate void ChangedItemHover( object? item ); public delegate void ChangedItemClick( MouseButton button, object? item ); +public delegate void GameObjectRedrawn( IntPtr objectPtr, int objectTableIndex ); public enum PenumbraApiEc { @@ -51,7 +52,7 @@ public interface IPenumbraApi : IPenumbraApiBase // Triggered when the user clicks a listed changed object in a mod tab. public event ChangedItemClick? ChangedItemClicked; - event EventHandler? ObjectIsRedrawn; + public event GameObjectRedrawn? GameObjectRedrawn; // Queue redrawing of all actors of the given name with the given RedrawType. public void RedrawObject( string name, RedrawType setting ); @@ -74,7 +75,7 @@ public interface IPenumbraApi : IPenumbraApiBase public string ResolvePath( string gamePath, string characterName ); // Reverse resolves a given modded local path into its replacement in form of all applicable game path for given character - public string[] ReverseResolvePath( string moddedPath, string characterName ); + public IList ReverseResolvePath( string moddedPath, string characterName ); // Try to load a given gamePath with the resolved path from Penumbra. public T? GetFile< T >( string gamePath ) where T : FileResource; diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index 87904e0a..33b4dedf 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -20,7 +20,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi public int ApiVersion { get; } = 4; private Penumbra? _penumbra; private Lumina.GameData? _lumina; - public event EventHandler? ObjectIsRedrawn; + public event GameObjectRedrawn? GameObjectRedrawn; public bool Valid => _penumbra != null; @@ -29,21 +29,16 @@ public class PenumbraApi : IDisposable, IPenumbraApi { _penumbra = penumbra; _lumina = ( Lumina.GameData? )Dalamud.GameData.GetType() - .GetField( "gameData", BindingFlags.Instance | BindingFlags.NonPublic ) - ?.GetValue( Dalamud.GameData ); - _penumbra.ObjectReloader.ObjectIsRedrawn += ObjectReloader_ObjectIsRedrawn; - } - - private void ObjectReloader_ObjectIsRedrawn( object? sender, EventArgs e ) - { - ObjectIsRedrawn?.Invoke( sender, e ); + .GetField( "gameData", BindingFlags.Instance | BindingFlags.NonPublic ) + ?.GetValue( Dalamud.GameData ); + _penumbra.ObjectReloader.GameObjectRedrawn += OnGameObjectRedrawn; } public void Dispose() { - _penumbra!.ObjectReloader.ObjectIsRedrawn -= ObjectReloader_ObjectIsRedrawn; - _penumbra = null; - _lumina = null; + _penumbra!.ObjectReloader.GameObjectRedrawn -= OnGameObjectRedrawn; + _penumbra = null; + _lumina = null; } public event ChangedItemClick? ChangedItemClicked; @@ -98,13 +93,18 @@ public class PenumbraApi : IDisposable, IPenumbraApi _penumbra!.ObjectReloader.RedrawObject( gameObject, setting ); } + private void OnGameObjectRedrawn( IntPtr objectAddress, int objectTableIndex ) + { + GameObjectRedrawn?.Invoke( objectAddress, objectTableIndex ); + } + public void RedrawAll( RedrawType setting ) { CheckInitialized(); _penumbra!.ObjectReloader.RedrawAll( setting ); } - private static string ResolvePath( string path, Mods.Mod.Manager _, ModCollection collection ) + private static string ResolvePath( string path, Mod.Manager _, ModCollection collection ) { if( !Penumbra.Config.EnableMods ) { @@ -129,7 +129,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi Penumbra.CollectionManager.Character( characterName ) ); } - public string[] ReverseResolvePath( string path, string characterName ) + public IList< string > ReverseResolvePath( string path, string characterName ) { CheckInitialized(); if( !Penumbra.Config.EnableMods ) @@ -137,11 +137,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi return new[] { path }; } - var gamePath = Utf8GamePath.FromString( path, out var p, true ) ? p : Utf8GamePath.Empty; - var ret = Penumbra.CollectionManager.Character( characterName ).ResolveReversePath( new FullPath( path ) ) ?? - new List< Utf8GamePath >(); - if( ret.Count == 0 ) ret.Add( gamePath ); - return ret.Select( r => r.ToString() ).ToArray(); + var ret = Penumbra.CollectionManager.Character( characterName ).ReverseResolvePath( new FullPath( path ) ); + return ret.Select( r => r.ToString() ).ToList(); } private T? GetFileIntern< T >( string resolvedPath ) where T : FileResource @@ -233,10 +230,11 @@ public class PenumbraApi : IDisposable, IPenumbraApi return Penumbra.ModManager.Select( m => ( m.ModPath.Name, m.Name.Text ) ).ToArray(); } - public IDictionary< string, (IList, SelectType) >? GetAvailableModSettings( string modDirectory, string modName ) + public IDictionary< string, (IList< string >, SelectType) >? GetAvailableModSettings( string modDirectory, string modName ) => throw new NotImplementedException(); - public (PenumbraApiEc, (bool, int, IDictionary< string, IList >, bool)?) GetCurrentModSettings( string collectionName, string modDirectory, string modName, + public (PenumbraApiEc, (bool, int, IDictionary< string, IList< string > >, bool)?) GetCurrentModSettings( string collectionName, + string modDirectory, string modName, bool allowInheritance ) => throw new NotImplementedException(); @@ -252,7 +250,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi public PenumbraApiEc TrySetModSetting( string collectionName, string modDirectory, string modName, string optionGroupName, string option ) => throw new NotImplementedException(); - public PenumbraApiEc TrySetModSetting( string collectionName, string modDirectory, string modName, string optionGroupName, IReadOnlyList options ) + public PenumbraApiEc TrySetModSetting( string collectionName, string modDirectory, string modName, string optionGroupName, + IReadOnlyList< string > options ) => throw new NotImplementedException(); public PenumbraApiEc CreateTemporaryCollection( string collectionName, string? character, bool forceOverwriteCharacter ) diff --git a/Penumbra/Api/PenumbraIpc.cs b/Penumbra/Api/PenumbraIpc.cs index 1d197b07..14f3ea11 100644 --- a/Penumbra/Api/PenumbraIpc.cs +++ b/Penumbra/Api/PenumbraIpc.cs @@ -111,17 +111,17 @@ public partial class PenumbraIpc public partial class PenumbraIpc { - public const string LabelProviderRedrawName = "Penumbra.RedrawObjectByName"; - public const string LabelProviderRedrawIndex = "Penumbra.RedrawObjectByIndex"; - public const string LabelProviderRedrawObject = "Penumbra.RedrawObject"; - public const string LabelProviderRedrawAll = "Penumbra.RedrawAll"; - public const string LabelProviderObjectIsRedrawn = "Penumbra.ObjectIsRedrawn"; + public const string LabelProviderRedrawName = "Penumbra.RedrawObjectByName"; + public const string LabelProviderRedrawIndex = "Penumbra.RedrawObjectByIndex"; + public const string LabelProviderRedrawObject = "Penumbra.RedrawObject"; + public const string LabelProviderRedrawAll = "Penumbra.RedrawAll"; + public const string LabelProviderGameObjectRedrawn = "Penumbra.GameObjectRedrawn"; internal ICallGateProvider< string, int, object >? ProviderRedrawName; internal ICallGateProvider< int, int, object >? ProviderRedrawIndex; internal ICallGateProvider< GameObject, int, object >? ProviderRedrawObject; internal ICallGateProvider< int, object >? ProviderRedrawAll; - internal ICallGateProvider< string, string >? ProviderObjectIsRedrawn; + internal ICallGateProvider< IntPtr, int, object? >? ProviderGameObjectRedrawn; private static RedrawType CheckRedrawType( int value ) { @@ -178,19 +178,17 @@ public partial class PenumbraIpc try { - ProviderObjectIsRedrawn = pi.GetIpcProvider< string, string >( LabelProviderObjectIsRedrawn ); - Api.ObjectIsRedrawn += Api_ObjectIsRedrawn; + ProviderGameObjectRedrawn = pi.GetIpcProvider< IntPtr, int, object? >( LabelProviderGameObjectRedrawn ); + Api.GameObjectRedrawn += OnGameObjectRedrawn; } catch( Exception e ) { - PluginLog.Error( $"Error registering IPC provider for {LabelProviderObjectIsRedrawn}:\n{e}" ); + PluginLog.Error( $"Error registering IPC provider for {LabelProviderGameObjectRedrawn}:\n{e}" ); } } - private void Api_ObjectIsRedrawn( object? sender, EventArgs e ) - { - ProviderObjectIsRedrawn?.SendMessage( ( ( GameObject? )sender )?.Name.ToString() ?? "" ); - } + private void OnGameObjectRedrawn( IntPtr objectAddress, int objectTableIndex ) + => ProviderGameObjectRedrawn?.SendMessage( objectAddress, objectTableIndex ); private void DisposeRedrawProviders() { @@ -198,7 +196,7 @@ public partial class PenumbraIpc ProviderRedrawIndex?.UnregisterAction(); ProviderRedrawObject?.UnregisterAction(); ProviderRedrawAll?.UnregisterAction(); - Api.ObjectIsRedrawn -= Api_ObjectIsRedrawn; + Api.GameObjectRedrawn -= OnGameObjectRedrawn; } } @@ -209,10 +207,10 @@ public partial class PenumbraIpc public const string LabelProviderGetDrawObjectInfo = "Penumbra.GetDrawObjectInfo"; public const string LabelProviderReverseResolvePath = "Penumbra.ReverseResolvePath"; - internal ICallGateProvider< string, string >? ProviderResolveDefault; - internal ICallGateProvider< string, string, string >? ProviderResolveCharacter; - internal ICallGateProvider< IntPtr, (IntPtr, string) >? ProviderGetDrawObjectInfo; - internal ICallGateProvider< string, string, string[] >? ProviderReverseResolvePath; + internal ICallGateProvider< string, string >? ProviderResolveDefault; + internal ICallGateProvider< string, string, string >? ProviderResolveCharacter; + internal ICallGateProvider< IntPtr, (IntPtr, string) >? ProviderGetDrawObjectInfo; + internal ICallGateProvider< string, string, IList< string > >? ProviderReverseResolvePath; private void InitializeResolveProviders( DalamudPluginInterface pi ) { @@ -248,7 +246,7 @@ public partial class PenumbraIpc try { - ProviderReverseResolvePath = pi.GetIpcProvider< string, string, string[] >( LabelProviderReverseResolvePath ); + ProviderReverseResolvePath = pi.GetIpcProvider< string, string, IList< string > >( LabelProviderReverseResolvePath ); ProviderReverseResolvePath.RegisterFunc( Api.ReverseResolvePath ); } catch( Exception e ) @@ -262,6 +260,7 @@ public partial class PenumbraIpc ProviderGetDrawObjectInfo?.UnregisterFunc(); ProviderResolveDefault?.UnregisterFunc(); ProviderResolveCharacter?.UnregisterFunc(); + ProviderReverseResolvePath?.UnregisterFunc(); } } diff --git a/Penumbra/Collections/ModCollection.Cache.Access.cs b/Penumbra/Collections/ModCollection.Cache.Access.cs index 871280a2..5cf71fc2 100644 --- a/Penumbra/Collections/ModCollection.Cache.Access.cs +++ b/Penumbra/Collections/ModCollection.Cache.Access.cs @@ -44,7 +44,8 @@ public partial class ModCollection PluginLog.Verbose( "Cleared cache of collection {Name:l}.", Name ); } - public List? ResolveReversePath( FullPath path ) => _cache?.ReverseResolvePath( path ); + public IEnumerable< Utf8GamePath > ReverseResolvePath( FullPath path ) + => _cache?.ReverseResolvePath( path ) ?? Array.Empty< Utf8GamePath >(); public FullPath? ResolvePath( Utf8GamePath path ) => _cache?.ResolvePath( path ); diff --git a/Penumbra/Collections/ModCollection.Cache.cs b/Penumbra/Collections/ModCollection.Cache.cs index 4b280697..d4e75a2c 100644 --- a/Penumbra/Collections/ModCollection.Cache.cs +++ b/Penumbra/Collections/ModCollection.Cache.cs @@ -12,7 +12,6 @@ using Penumbra.Util; namespace Penumbra.Collections; public record struct ModPath( Mod Mod, FullPath Path ); - public record ModConflicts( Mod Mod2, List< object > Conflicts, bool HasPriority, bool Solved ); public partial class ModCollection @@ -72,7 +71,7 @@ public partial class ModCollection } if( candidate.Path.InternalName.Length > Utf8GamePath.MaxGamePathLength - || candidate.Path.IsRooted && !candidate.Path.Exists ) + || candidate.Path.IsRooted && !candidate.Path.Exists ) { return null; } @@ -80,11 +79,26 @@ public partial class ModCollection return candidate.Path; } - public List< Utf8GamePath > ReverseResolvePath( FullPath localFilePath ) + // For a given full path, find all game paths that currently use this file. + public IEnumerable< Utf8GamePath > ReverseResolvePath( FullPath localFilePath ) { - string strToSearchFor = localFilePath.FullName.Replace( '/', '\\' ).ToLower(); - return ResolvedFiles.Where( f => f.Value.Path.FullName.ToLower() == strToSearchFor ) - .Select( kvp => kvp.Key ).ToList(); + var needle = localFilePath.FullName.ToLower(); + if( localFilePath.IsRooted ) + { + needle = needle.Replace( '/', '\\' ); + } + + var iterator = ResolvedFiles + .Where( f => string.Equals( f.Value.Path.FullName, needle, StringComparison.InvariantCultureIgnoreCase ) ) + .Select( kvp => kvp.Key ); + + // For files that are not rooted, try to add themselves. + if( !localFilePath.IsRooted && Utf8GamePath.FromString( localFilePath.FullName, out var utf8 ) ) + { + iterator = iterator.Prepend( utf8 ); + } + + return iterator; } private void OnModSettingChange( ModSettingChange type, int modIdx, int oldValue, int groupIdx, bool _ ) @@ -253,8 +267,8 @@ public partial class ModCollection case SelectType.Multi: { foreach( var (option, _) in group.WithIndex() - .OrderByDescending( p => group.OptionPriority( p.Item2 ) ) - .Where( p => ( ( 1 << p.Item2 ) & config ) != 0 ) ) + .OrderByDescending( p => group.OptionPriority( p.Item2 ) ) + .Where( p => ( ( 1 << p.Item2 ) & config ) != 0 ) ) { AddSubMod( option, mod ); } @@ -360,7 +374,7 @@ public partial class ModCollection // Returns if the added mod takes priority before the existing mod. private bool AddConflict( object data, Mod addedMod, Mod existingMod ) { - var addedPriority = addedMod.Index >= 0 ? _collection[ addedMod.Index ].Settings!.Priority : int.MaxValue; + var addedPriority = addedMod.Index >= 0 ? _collection[ addedMod.Index ].Settings!.Priority : int.MaxValue; var existingPriority = existingMod.Index >= 0 ? _collection[ existingMod.Index ].Settings!.Priority : int.MaxValue; if( existingPriority < addedPriority ) @@ -368,9 +382,8 @@ public partial class ModCollection var tmpConflicts = Conflicts( existingMod ); foreach( var conflict in tmpConflicts ) { - if( data is Utf8GamePath path && conflict.Conflicts.RemoveAll( p => p is Utf8GamePath x && x.Equals( path ) ) > 0 - || data is MetaManipulation meta && - conflict.Conflicts.RemoveAll( m => m is MetaManipulation x && x.Equals( meta ) ) > 0 ) + if( data is Utf8GamePath path && conflict.Conflicts.RemoveAll( p => p is Utf8GamePath x && x.Equals( path ) ) > 0 + || data is MetaManipulation meta && conflict.Conflicts.RemoveAll( m => m is MetaManipulation x && x.Equals( meta ) ) > 0 ) { AddConflict( data, addedMod, conflict.Mod2 ); } diff --git a/Penumbra/Interop/ObjectReloader.cs b/Penumbra/Interop/ObjectReloader.cs index d58d434c..daf4ae7f 100644 --- a/Penumbra/Interop/ObjectReloader.cs +++ b/Penumbra/Interop/ObjectReloader.cs @@ -25,8 +25,6 @@ public unsafe partial class ObjectReloader private static void EnableDraw( GameObject actor ) => ( ( delegate* unmanaged< IntPtr, void >** )actor.Address )[ 0 ][ 16 ]( actor.Address ); - public event EventHandler? ObjectIsRedrawn; - // Check whether we currently are in GPose. // Also clear the name list. private void SetGPose() @@ -107,6 +105,8 @@ public sealed unsafe partial class ObjectReloader : IDisposable private readonly List< int > _afterGPoseQueue = new(GPoseSlots); private int _target = -1; + public event Action< IntPtr, int >? GameObjectRedrawn; + public ObjectReloader() => Dalamud.Framework.Update += OnUpdateEvent; @@ -134,7 +134,7 @@ public sealed unsafe partial class ObjectReloader : IDisposable } } - private static void WriteVisible( GameObject? actor ) + private void WriteVisible( GameObject? actor ) { if( BadRedrawIndices( actor, out var tableIndex ) ) { @@ -142,11 +142,12 @@ public sealed unsafe partial class ObjectReloader : IDisposable } *ActorDrawState( actor! ) &= ~DrawState.Invisibility; - if( IsGPoseActor( tableIndex ) ) { EnableDraw( actor! ); } + + GameObjectRedrawn?.Invoke( actor!.Address, tableIndex ); } private void ReloadActor( GameObject? actor ) @@ -282,8 +283,6 @@ public sealed unsafe partial class ObjectReloader : IDisposable break; default: throw new ArgumentOutOfRangeException( nameof( settings ), settings, null ); } - - ObjectIsRedrawn?.Invoke( actor, new EventArgs() ); } private static GameObject? GetLocalPlayer() From 35e68e74f4694fd2a47ec703d630ebe17fdf4f1c Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 17 Jun 2022 17:33:22 +0200 Subject: [PATCH 07/11] File Selector improvements. --- Penumbra/UI/Classes/ModEditWindow.Textures.cs | 2 +- Penumbra/UI/Classes/ModFileSystemSelector.cs | 2 +- Penumbra/UI/ConfigWindow.Misc.cs | 31 +++++++++++++++++++ Penumbra/UI/ConfigWindow.SettingsTab.cs | 2 +- Penumbra/UI/ConfigWindow.cs | 1 - 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/Penumbra/UI/Classes/ModEditWindow.Textures.cs b/Penumbra/UI/Classes/ModEditWindow.Textures.cs index 6f0ec77f..e18ec33c 100644 --- a/Penumbra/UI/Classes/ModEditWindow.Textures.cs +++ b/Penumbra/UI/Classes/ModEditWindow.Textures.cs @@ -41,7 +41,7 @@ public partial class ModEditWindow private int _offsetX = 0; private int _offsetY = 0; - private readonly FileDialogManager _dialogManager = new(); + private readonly FileDialogManager _dialogManager = ConfigWindow.SetupFileManager(); private static bool DragFloat( string label, float width, ref float value ) { diff --git a/Penumbra/UI/Classes/ModFileSystemSelector.cs b/Penumbra/UI/Classes/ModFileSystemSelector.cs index 14dfd804..51490733 100644 --- a/Penumbra/UI/Classes/ModFileSystemSelector.cs +++ b/Penumbra/UI/Classes/ModFileSystemSelector.cs @@ -19,7 +19,7 @@ namespace Penumbra.UI.Classes; public sealed partial class ModFileSystemSelector : FileSystemSelector< Mod, ModFileSystemSelector.ModState > { - private readonly FileDialogManager _fileManager = new(); + private readonly FileDialogManager _fileManager = ConfigWindow.SetupFileManager(); private TexToolsImporter? _import; public ModSettings SelectedSettings { get; private set; } = ModSettings.Empty; public ModCollection SelectedSettingCollection { get; private set; } = ModCollection.Empty; diff --git a/Penumbra/UI/ConfigWindow.Misc.cs b/Penumbra/UI/ConfigWindow.Misc.cs index 7d8969ee..6f70126a 100644 --- a/Penumbra/UI/ConfigWindow.Misc.cs +++ b/Penumbra/UI/ConfigWindow.Misc.cs @@ -1,6 +1,8 @@ using System; using System.Linq; using System.Numerics; +using Dalamud.Interface; +using Dalamud.Interface.ImGuiFileDialog; using ImGuiNET; using Lumina.Data.Parsing; using Lumina.Excel.GeneratedSheets; @@ -11,6 +13,7 @@ using Penumbra.GameData.ByteString; using Penumbra.GameData.Enums; using Penumbra.Interop.Structs; using Penumbra.UI.Classes; +using Penumbra.Util; namespace Penumbra.UI; @@ -114,4 +117,32 @@ public partial class ConfigWindow } } } + + // Set up the file selector with the right flags and custom side bar items. + public static FileDialogManager SetupFileManager() + { + var fileManager = new FileDialogManager + { + AddedWindowFlags = ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoDocking, + }; + + if( Functions.GetDownloadsFolder( out var downloadsFolder ) ) + { + fileManager.CustomSideBarItems.Add( ("Downloads", downloadsFolder, FontAwesomeIcon.Download, -1) ); + } + + if( Functions.GetQuickAccessFolders( out var folders ) ) + { + foreach( var ((name, path), idx) in folders.WithIndex() ) + { + fileManager.CustomSideBarItems.Add( ($"{name}##{idx}", path, FontAwesomeIcon.Folder, -1) ); + } + } + + // Remove Videos and Music. + fileManager.CustomSideBarItems.Add( ("Videos", string.Empty, 0, -1) ); + fileManager.CustomSideBarItems.Add( ("Music", string.Empty, 0, -1) ); + + return fileManager; + } } \ No newline at end of file diff --git a/Penumbra/UI/ConfigWindow.SettingsTab.cs b/Penumbra/UI/ConfigWindow.SettingsTab.cs index de377896..32859822 100644 --- a/Penumbra/UI/ConfigWindow.SettingsTab.cs +++ b/Penumbra/UI/ConfigWindow.SettingsTab.cs @@ -62,7 +62,7 @@ public partial class ConfigWindow // Changing the base mod directory. private string? _newModDirectory; - private readonly FileDialogManager _dialogManager = new(); + private readonly FileDialogManager _dialogManager = SetupFileManager(); private bool _dialogOpen; // For toggling on/off. // Do not change the directory without explicitly pressing enter or this button. diff --git a/Penumbra/UI/ConfigWindow.cs b/Penumbra/UI/ConfigWindow.cs index ff7fa751..ccfac393 100644 --- a/Penumbra/UI/ConfigWindow.cs +++ b/Penumbra/UI/ConfigWindow.cs @@ -33,7 +33,6 @@ public sealed partial class ConfigWindow : Window, IDisposable _effectiveTab = new EffectiveTab(); _debugTab = new DebugTab( this ); _resourceTab = new ResourceTab( this ); - Flags |= ImGuiWindowFlags.NoDocking; if( Penumbra.Config.FixMainWindow ) { Flags |= ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove; From 1fb2ddaa5e1865a57af55468132584edb7523358 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 18 Jun 2022 10:21:49 +0200 Subject: [PATCH 08/11] Fix advanced editing always showing. --- Penumbra/UI/ConfigWindow.ModPanel.Tabs.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Penumbra/UI/ConfigWindow.ModPanel.Tabs.cs b/Penumbra/UI/ConfigWindow.ModPanel.Tabs.cs index d0ad872d..d1c4a838 100644 --- a/Penumbra/UI/ConfigWindow.ModPanel.Tabs.cs +++ b/Penumbra/UI/ConfigWindow.ModPanel.Tabs.cs @@ -56,7 +56,7 @@ public partial class ConfigWindow DrawChangedItemsTab(); DrawConflictsTab(); DrawEditModTab(); - if( ImGui.TabItemButton( "Advanced Editing", ImGuiTabItemFlags.Trailing | ImGuiTabItemFlags.NoTooltip ) ) + if( Penumbra.Config.ShowAdvanced && ImGui.TabItemButton( "Advanced Editing", ImGuiTabItemFlags.Trailing | ImGuiTabItemFlags.NoTooltip ) ) { _window.ModEditPopup.ChangeMod( _mod ); _window.ModEditPopup.ChangeOption( -1, 0 ); From 1ee4cb99d02a7d16b487584824ab6952167e36da Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 18 Jun 2022 11:10:51 +0200 Subject: [PATCH 09/11] Add demihuman hooks for resolving. --- .../Resolver/PathResolver.Demihuman.cs | 88 +++++++++++++++++++ .../Interop/Resolver/PathResolver.Human.cs | 6 -- .../Interop/Resolver/PathResolver.Resolve.cs | 37 ++++++++ Penumbra/Interop/Resolver/PathResolver.cs | 4 + 4 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 Penumbra/Interop/Resolver/PathResolver.Demihuman.cs diff --git a/Penumbra/Interop/Resolver/PathResolver.Demihuman.cs b/Penumbra/Interop/Resolver/PathResolver.Demihuman.cs new file mode 100644 index 00000000..c938bb72 --- /dev/null +++ b/Penumbra/Interop/Resolver/PathResolver.Demihuman.cs @@ -0,0 +1,88 @@ +using System; +using Dalamud.Hooking; +using Dalamud.Utility.Signatures; + +namespace Penumbra.Interop.Resolver; + +public unsafe partial class PathResolver +{ + [Signature( "48 8D 05 ?? ?? ?? ?? 45 33 C0 48 89 03 BA", ScanType = ScanType.StaticAddress )] + public IntPtr* DrawObjectDemiVTable; + + public Hook< GeneralResolveDelegate >? ResolveDemiDecalPathHook; + public Hook< EidResolveDelegate >? ResolveDemiEidPathHook; + public Hook< GeneralResolveDelegate >? ResolveDemiImcPathHook; + public Hook< MPapResolveDelegate >? ResolveDemiMPapPathHook; + public Hook< GeneralResolveDelegate >? ResolveDemiMdlPathHook; + public Hook< MaterialResolveDetour >? ResolveDemiMtrlPathHook; + public Hook< MaterialResolveDetour >? ResolveDemiPapPathHook; + public Hook< GeneralResolveDelegate >? ResolveDemiPhybPathHook; + public Hook< GeneralResolveDelegate >? ResolveDemiSklbPathHook; + public Hook< GeneralResolveDelegate >? ResolveDemiSkpPathHook; + public Hook< EidResolveDelegate >? ResolveDemiTmbPathHook; + public Hook< MaterialResolveDetour >? ResolveDemiVfxPathHook; + + private void SetupDemiHooks() + { + ResolveDemiDecalPathHook = new Hook< GeneralResolveDelegate >( DrawObjectDemiVTable[ ResolveDecalIdx ], ResolveDemiDecalDetour ); + ResolveDemiEidPathHook = new Hook< EidResolveDelegate >( DrawObjectDemiVTable[ ResolveEidIdx ], ResolveDemiEidDetour ); + ResolveDemiImcPathHook = new Hook< GeneralResolveDelegate >( DrawObjectDemiVTable[ ResolveImcIdx ], ResolveDemiImcDetour ); + ResolveDemiMPapPathHook = new Hook< MPapResolveDelegate >( DrawObjectDemiVTable[ ResolveMPapIdx ], ResolveDemiMPapDetour ); + ResolveDemiMdlPathHook = new Hook< GeneralResolveDelegate >( DrawObjectDemiVTable[ ResolveMdlIdx ], ResolveDemiMdlDetour ); + ResolveDemiMtrlPathHook = new Hook< MaterialResolveDetour >( DrawObjectDemiVTable[ ResolveMtrlIdx ], ResolveDemiMtrlDetour ); + ResolveDemiPapPathHook = new Hook< MaterialResolveDetour >( DrawObjectDemiVTable[ ResolvePapIdx ], ResolveDemiPapDetour ); + ResolveDemiPhybPathHook = new Hook< GeneralResolveDelegate >( DrawObjectDemiVTable[ ResolvePhybIdx ], ResolveDemiPhybDetour ); + ResolveDemiSklbPathHook = new Hook< GeneralResolveDelegate >( DrawObjectDemiVTable[ ResolveSklbIdx ], ResolveDemiSklbDetour ); + ResolveDemiSkpPathHook = new Hook< GeneralResolveDelegate >( DrawObjectDemiVTable[ ResolveSkpIdx ], ResolveDemiSkpDetour ); + ResolveDemiTmbPathHook = new Hook< EidResolveDelegate >( DrawObjectDemiVTable[ ResolveTmbIdx ], ResolveDemiTmbDetour ); + ResolveDemiVfxPathHook = new Hook< MaterialResolveDetour >( DrawObjectDemiVTable[ ResolveVfxIdx ], ResolveDemiVfxDetour ); + } + + private void EnableDemiHooks() + { + ResolveDemiDecalPathHook?.Enable(); + ResolveDemiEidPathHook?.Enable(); + ResolveDemiImcPathHook?.Enable(); + ResolveDemiMPapPathHook?.Enable(); + ResolveDemiMdlPathHook?.Enable(); + ResolveDemiMtrlPathHook?.Enable(); + ResolveDemiPapPathHook?.Enable(); + ResolveDemiPhybPathHook?.Enable(); + ResolveDemiSklbPathHook?.Enable(); + ResolveDemiSkpPathHook?.Enable(); + ResolveDemiTmbPathHook?.Enable(); + ResolveDemiVfxPathHook?.Enable(); + } + + private void DisableDemiHooks() + { + ResolveDemiDecalPathHook?.Disable(); + ResolveDemiEidPathHook?.Disable(); + ResolveDemiImcPathHook?.Disable(); + ResolveDemiMPapPathHook?.Disable(); + ResolveDemiMdlPathHook?.Disable(); + ResolveDemiMtrlPathHook?.Disable(); + ResolveDemiPapPathHook?.Disable(); + ResolveDemiPhybPathHook?.Disable(); + ResolveDemiSklbPathHook?.Disable(); + ResolveDemiSkpPathHook?.Disable(); + ResolveDemiTmbPathHook?.Disable(); + ResolveDemiVfxPathHook?.Disable(); + } + + private void DisposeDemiHooks() + { + ResolveDemiDecalPathHook?.Dispose(); + ResolveDemiEidPathHook?.Dispose(); + ResolveDemiImcPathHook?.Dispose(); + ResolveDemiMPapPathHook?.Dispose(); + ResolveDemiMdlPathHook?.Dispose(); + ResolveDemiMtrlPathHook?.Dispose(); + ResolveDemiPapPathHook?.Dispose(); + ResolveDemiPhybPathHook?.Dispose(); + ResolveDemiSklbPathHook?.Dispose(); + ResolveDemiSkpPathHook?.Dispose(); + ResolveDemiTmbPathHook?.Dispose(); + ResolveDemiVfxPathHook?.Dispose(); + } +} \ No newline at end of file diff --git a/Penumbra/Interop/Resolver/PathResolver.Human.cs b/Penumbra/Interop/Resolver/PathResolver.Human.cs index 1ce81342..b4bb8fcd 100644 --- a/Penumbra/Interop/Resolver/PathResolver.Human.cs +++ b/Penumbra/Interop/Resolver/PathResolver.Human.cs @@ -14,12 +14,6 @@ public unsafe partial class PathResolver // [Signature( "48 8D 1D ?? ?? ?? ?? 48 C7 41", ScanType = ScanType.StaticAddress )] // public IntPtr* DrawObjectVTable; // - // [Signature( "48 8D 05 ?? ?? ?? ?? 45 33 C0 48 89 03 BA", ScanType = ScanType.StaticAddress )] - // public IntPtr* DrawObjectDemihumanVTable; - // - // [Signature( "48 8D 05 ?? ?? ?? ?? 48 89 03 33 C0 48 89 83 ?? ?? ?? ?? 48 89 83 ?? ?? ?? ?? C7 83", ScanType = ScanType.StaticAddress )] - // public IntPtr* DrawObjectMonsterVTable; - // // public const int ResolveRootIdx = 71; public const int ResolveSklbIdx = 72; diff --git a/Penumbra/Interop/Resolver/PathResolver.Resolve.cs b/Penumbra/Interop/Resolver/PathResolver.Resolve.cs index a6124a93..3892fcbd 100644 --- a/Penumbra/Interop/Resolver/PathResolver.Resolve.cs +++ b/Penumbra/Interop/Resolver/PathResolver.Resolve.cs @@ -136,6 +136,43 @@ public unsafe partial class PathResolver private IntPtr ResolveMonsterVfxDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4, ulong unk5 ) => ResolvePathDetour( drawObject, ResolveMonsterVfxPathHook!.Original( drawObject, path, unk3, unk4, unk5 ) ); + // Demihumans + private IntPtr ResolveDemiDecalDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4 ) + => ResolvePathDetour( drawObject, ResolveDemiDecalPathHook!.Original( drawObject, path, unk3, unk4 ) ); + + private IntPtr ResolveDemiEidDetour( IntPtr drawObject, IntPtr path, IntPtr unk3 ) + => ResolvePathDetour( drawObject, ResolveDemiEidPathHook!.Original( drawObject, path, unk3 ) ); + + private IntPtr ResolveDemiImcDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4 ) + => ResolvePathDetour( drawObject, ResolveDemiImcPathHook!.Original( drawObject, path, unk3, unk4 ) ); + + private IntPtr ResolveDemiMPapDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4, uint unk5 ) + => ResolvePathDetour( drawObject, ResolveDemiMPapPathHook!.Original( drawObject, path, unk3, unk4, unk5 ) ); + + private IntPtr ResolveDemiMdlDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint modelType ) + => ResolvePathDetour( drawObject, ResolveDemiMdlPathHook!.Original( drawObject, path, unk3, modelType ) ); + + private IntPtr ResolveDemiMtrlDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4, ulong unk5 ) + => ResolvePathDetour( drawObject, ResolveDemiMtrlPathHook!.Original( drawObject, path, unk3, unk4, unk5 ) ); + + private IntPtr ResolveDemiPapDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4, ulong unk5 ) + => ResolvePathDetour( drawObject, ResolveDemiPapPathHook!.Original( drawObject, path, unk3, unk4, unk5 ) ); + + private IntPtr ResolveDemiPhybDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4 ) + => ResolvePathDetour( drawObject, ResolveDemiPhybPathHook!.Original( drawObject, path, unk3, unk4 ) ); + + private IntPtr ResolveDemiSklbDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4 ) + => ResolvePathDetour( drawObject, ResolveDemiSklbPathHook!.Original( drawObject, path, unk3, unk4 ) ); + + private IntPtr ResolveDemiSkpDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4 ) + => ResolvePathDetour( drawObject, ResolveDemiSkpPathHook!.Original( drawObject, path, unk3, unk4 ) ); + + private IntPtr ResolveDemiTmbDetour( IntPtr drawObject, IntPtr path, IntPtr unk3 ) + => ResolvePathDetour( drawObject, ResolveDemiTmbPathHook!.Original( drawObject, path, unk3 ) ); + + private IntPtr ResolveDemiVfxDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4, ulong unk5 ) + => ResolvePathDetour( drawObject, ResolveDemiVfxPathHook!.Original( drawObject, path, unk3, unk4, unk5 ) ); + // Implementation [MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )] diff --git a/Penumbra/Interop/Resolver/PathResolver.cs b/Penumbra/Interop/Resolver/PathResolver.cs index c634755a..d12e6d00 100644 --- a/Penumbra/Interop/Resolver/PathResolver.cs +++ b/Penumbra/Interop/Resolver/PathResolver.cs @@ -27,6 +27,7 @@ public partial class PathResolver : IDisposable SetupHumanHooks(); SetupWeaponHooks(); SetupMonsterHooks(); + SetupDemiHooks(); SetupMetaHooks(); } @@ -105,6 +106,7 @@ public partial class PathResolver : IDisposable EnableHumanHooks(); EnableWeaponHooks(); EnableMonsterHooks(); + EnableDemiHooks(); EnableMtrlHooks(); EnableDataHooks(); EnableMetaHooks(); @@ -124,6 +126,7 @@ public partial class PathResolver : IDisposable DisableHumanHooks(); DisableWeaponHooks(); DisableMonsterHooks(); + DisableDemiHooks(); DisableMtrlHooks(); DisableDataHooks(); DisableMetaHooks(); @@ -141,6 +144,7 @@ public partial class PathResolver : IDisposable DisposeHumanHooks(); DisposeWeaponHooks(); DisposeMonsterHooks(); + DisposeDemiHooks(); DisposeMtrlHooks(); DisposeDataHooks(); DisposeMetaHooks(); From 018be13216c1a363b7cf4d309b4f2cd4d56ac0ec Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 18 Jun 2022 11:11:13 +0200 Subject: [PATCH 10/11] Use Current collection instead of Default for Effective Files and Changed Items. --- Penumbra/UI/ConfigWindow.ChangedItemsTab.cs | 2 +- Penumbra/UI/ConfigWindow.EffectiveTab.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Penumbra/UI/ConfigWindow.ChangedItemsTab.cs b/Penumbra/UI/ConfigWindow.ChangedItemsTab.cs index 596a48f0..6eb6c5ca 100644 --- a/Penumbra/UI/ConfigWindow.ChangedItemsTab.cs +++ b/Penumbra/UI/ConfigWindow.ChangedItemsTab.cs @@ -87,7 +87,7 @@ public partial class ConfigWindow ImGui.TableSetupColumn( "mods", flags, varWidth - 100 * ImGuiHelpers.GlobalScale ); ImGui.TableSetupColumn( "id", flags, 100 * ImGuiHelpers.GlobalScale ); - var items = Penumbra.CollectionManager.Default.ChangedItems; + var items = Penumbra.CollectionManager.Current.ChangedItems; var rest = _changedItemFilter.IsEmpty && _changedItemModFilter.IsEmpty ? ImGuiClip.ClippedDraw( items, skips, DrawChangedItemColumn, items.Count ) : ImGuiClip.FilteredClippedDraw( items, skips, FilterChangedItem, DrawChangedItemColumn ); diff --git a/Penumbra/UI/ConfigWindow.EffectiveTab.cs b/Penumbra/UI/ConfigWindow.EffectiveTab.cs index 4d96423c..38c37485 100644 --- a/Penumbra/UI/ConfigWindow.EffectiveTab.cs +++ b/Penumbra/UI/ConfigWindow.EffectiveTab.cs @@ -50,7 +50,7 @@ public partial class ConfigWindow ImGui.TableSetupColumn( string.Empty, ImGuiTableColumnFlags.WidthFixed, _effectiveArrowLength ); ImGui.TableSetupColumn( "##file", ImGuiTableColumnFlags.WidthFixed, _effectiveRightTextLength ); - DrawEffectiveRows( Penumbra.CollectionManager.Default, skips, height, + DrawEffectiveRows( Penumbra.CollectionManager.Current, skips, height, _effectiveFilePathFilter.Length > 0 || _effectiveGamePathFilter.Length > 0 ); } From c097b634abcd2bd325146b90cbf8e9e38237452f Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 18 Jun 2022 11:11:55 +0200 Subject: [PATCH 11/11] Print a log message when Penumbra finished loading containing version and hash. --- Penumbra/Penumbra.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index 1ae066db..e4beecf0 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -152,6 +152,10 @@ public class Penumbra : IDisposable { PluginLog.Error( $"{ImcExceptions} IMC Exceptions thrown. Please repair your game files." ); } + else + { + PluginLog.Information( $"Penumbra Version {Version}, Commit #{CommitHash} successfully Loaded." ); + } } private void SetupInterface( out ConfigWindow cfg, out LaunchButton btn, out WindowSystem system )