Merge branch 'pr/n217_master'

This commit is contained in:
Ottermandias 2022-06-17 17:11:29 +02:00
commit 002778f4c1
6 changed files with 103 additions and 21 deletions

View file

@ -20,6 +20,7 @@ public interface IPenumbraApiBase
public delegate void ChangedItemHover( object? item ); public delegate void ChangedItemHover( object? item );
public delegate void ChangedItemClick( MouseButton button, object? item ); public delegate void ChangedItemClick( MouseButton button, object? item );
public delegate void GameObjectRedrawn( IntPtr objectPtr, int objectTableIndex );
public enum PenumbraApiEc public enum PenumbraApiEc
{ {
@ -51,6 +52,7 @@ public interface IPenumbraApi : IPenumbraApiBase
// Triggered when the user clicks a listed changed object in a mod tab. // Triggered when the user clicks a listed changed object in a mod tab.
public event ChangedItemClick? ChangedItemClicked; public event ChangedItemClick? ChangedItemClicked;
public event GameObjectRedrawn? GameObjectRedrawn;
// Queue redrawing of all actors of the given name with the given RedrawType. // Queue redrawing of all actors of the given name with the given RedrawType.
public void RedrawObject( string name, RedrawType setting ); public void RedrawObject( string name, RedrawType setting );
@ -72,6 +74,9 @@ public interface IPenumbraApi : IPenumbraApiBase
// Returns the given gamePath if penumbra would not manipulate it. // Returns the given gamePath if penumbra would not manipulate it.
public string ResolvePath( string gamePath, string characterName ); 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 IList<string> ReverseResolvePath( string moddedPath, string characterName );
// Try to load a given gamePath with the resolved path from Penumbra. // Try to load a given gamePath with the resolved path from Penumbra.
public T? GetFile< T >( string gamePath ) where T : FileResource; public T? GetFile< T >( string gamePath ) where T : FileResource;

View file

@ -20,6 +20,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
public int ApiVersion { get; } = 4; public int ApiVersion { get; } = 4;
private Penumbra? _penumbra; private Penumbra? _penumbra;
private Lumina.GameData? _lumina; private Lumina.GameData? _lumina;
public event GameObjectRedrawn? GameObjectRedrawn;
public bool Valid public bool Valid
=> _penumbra != null; => _penumbra != null;
@ -30,12 +31,14 @@ public class PenumbraApi : IDisposable, IPenumbraApi
_lumina = ( Lumina.GameData? )Dalamud.GameData.GetType() _lumina = ( Lumina.GameData? )Dalamud.GameData.GetType()
.GetField( "gameData", BindingFlags.Instance | BindingFlags.NonPublic ) .GetField( "gameData", BindingFlags.Instance | BindingFlags.NonPublic )
?.GetValue( Dalamud.GameData ); ?.GetValue( Dalamud.GameData );
_penumbra.ObjectReloader.GameObjectRedrawn += OnGameObjectRedrawn;
} }
public void Dispose() public void Dispose()
{ {
_penumbra = null; _penumbra!.ObjectReloader.GameObjectRedrawn -= OnGameObjectRedrawn;
_lumina = null; _penumbra = null;
_lumina = null;
} }
public event ChangedItemClick? ChangedItemClicked; public event ChangedItemClick? ChangedItemClicked;
@ -90,13 +93,18 @@ public class PenumbraApi : IDisposable, IPenumbraApi
_penumbra!.ObjectReloader.RedrawObject( gameObject, setting ); _penumbra!.ObjectReloader.RedrawObject( gameObject, setting );
} }
private void OnGameObjectRedrawn( IntPtr objectAddress, int objectTableIndex )
{
GameObjectRedrawn?.Invoke( objectAddress, objectTableIndex );
}
public void RedrawAll( RedrawType setting ) public void RedrawAll( RedrawType setting )
{ {
CheckInitialized(); CheckInitialized();
_penumbra!.ObjectReloader.RedrawAll( setting ); _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 ) if( !Penumbra.Config.EnableMods )
{ {
@ -121,6 +129,18 @@ public class PenumbraApi : IDisposable, IPenumbraApi
Penumbra.CollectionManager.Character( characterName ) ); Penumbra.CollectionManager.Character( characterName ) );
} }
public IList< string > ReverseResolvePath( string path, string characterName )
{
CheckInitialized();
if( !Penumbra.Config.EnableMods )
{
return new[] { path };
}
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 private T? GetFileIntern< T >( string resolvedPath ) where T : FileResource
{ {
CheckInitialized(); CheckInitialized();
@ -210,10 +230,11 @@ public class PenumbraApi : IDisposable, IPenumbraApi
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<string>, SelectType) >? GetAvailableModSettings( string modDirectory, string modName ) public IDictionary< string, (IList< string >, SelectType) >? GetAvailableModSettings( string modDirectory, string modName )
=> throw new NotImplementedException(); => throw new NotImplementedException();
public (PenumbraApiEc, (bool, int, IDictionary< string, IList<string> >, 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 ) bool allowInheritance )
=> throw new NotImplementedException(); => throw new NotImplementedException();
@ -229,7 +250,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi
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 option )
=> throw new NotImplementedException(); => throw new NotImplementedException();
public PenumbraApiEc TrySetModSetting( string collectionName, string modDirectory, string modName, string optionGroupName, IReadOnlyList<string> options ) public PenumbraApiEc TrySetModSetting( string collectionName, string modDirectory, string modName, string optionGroupName,
IReadOnlyList< string > options )
=> throw new NotImplementedException(); => throw new NotImplementedException();
public PenumbraApiEc CreateTemporaryCollection( string collectionName, string? character, bool forceOverwriteCharacter ) public PenumbraApiEc CreateTemporaryCollection( string collectionName, string? character, bool forceOverwriteCharacter )

View file

@ -111,15 +111,17 @@ public partial class PenumbraIpc
public partial class PenumbraIpc public partial class PenumbraIpc
{ {
public const string LabelProviderRedrawName = "Penumbra.RedrawObjectByName"; public const string LabelProviderRedrawName = "Penumbra.RedrawObjectByName";
public const string LabelProviderRedrawIndex = "Penumbra.RedrawObjectByIndex"; public const string LabelProviderRedrawIndex = "Penumbra.RedrawObjectByIndex";
public const string LabelProviderRedrawObject = "Penumbra.RedrawObject"; public const string LabelProviderRedrawObject = "Penumbra.RedrawObject";
public const string LabelProviderRedrawAll = "Penumbra.RedrawAll"; public const string LabelProviderRedrawAll = "Penumbra.RedrawAll";
public const string LabelProviderGameObjectRedrawn = "Penumbra.GameObjectRedrawn";
internal ICallGateProvider< string, int, object >? ProviderRedrawName; internal ICallGateProvider< string, int, object >? ProviderRedrawName;
internal ICallGateProvider< int, int, object >? ProviderRedrawIndex; internal ICallGateProvider< int, int, object >? ProviderRedrawIndex;
internal ICallGateProvider< GameObject, int, object >? ProviderRedrawObject; internal ICallGateProvider< GameObject, int, object >? ProviderRedrawObject;
internal ICallGateProvider< int, object >? ProviderRedrawAll; internal ICallGateProvider< int, object >? ProviderRedrawAll;
internal ICallGateProvider< IntPtr, int, object? >? ProviderGameObjectRedrawn;
private static RedrawType CheckRedrawType( int value ) private static RedrawType CheckRedrawType( int value )
{ {
@ -146,7 +148,7 @@ public partial class PenumbraIpc
try try
{ {
ProviderRedrawIndex = pi.GetIpcProvider<int, int, object>( LabelProviderRedrawIndex ); ProviderRedrawIndex = pi.GetIpcProvider< int, int, object >( LabelProviderRedrawIndex );
ProviderRedrawIndex.RegisterAction( ( idx, i ) => Api.RedrawObject( idx, CheckRedrawType( i ) ) ); ProviderRedrawIndex.RegisterAction( ( idx, i ) => Api.RedrawObject( idx, CheckRedrawType( i ) ) );
} }
catch( Exception e ) catch( Exception e )
@ -173,26 +175,42 @@ public partial class PenumbraIpc
{ {
PluginLog.Error( $"Error registering IPC provider for {LabelProviderRedrawAll}:\n{e}" ); PluginLog.Error( $"Error registering IPC provider for {LabelProviderRedrawAll}:\n{e}" );
} }
try
{
ProviderGameObjectRedrawn = pi.GetIpcProvider< IntPtr, int, object? >( LabelProviderGameObjectRedrawn );
Api.GameObjectRedrawn += OnGameObjectRedrawn;
}
catch( Exception e )
{
PluginLog.Error( $"Error registering IPC provider for {LabelProviderGameObjectRedrawn}:\n{e}" );
}
} }
private void OnGameObjectRedrawn( IntPtr objectAddress, int objectTableIndex )
=> ProviderGameObjectRedrawn?.SendMessage( objectAddress, objectTableIndex );
private void DisposeRedrawProviders() private void DisposeRedrawProviders()
{ {
ProviderRedrawName?.UnregisterAction(); ProviderRedrawName?.UnregisterAction();
ProviderRedrawIndex?.UnregisterAction(); ProviderRedrawIndex?.UnregisterAction();
ProviderRedrawObject?.UnregisterAction(); ProviderRedrawObject?.UnregisterAction();
ProviderRedrawAll?.UnregisterAction(); ProviderRedrawAll?.UnregisterAction();
Api.GameObjectRedrawn -= OnGameObjectRedrawn;
} }
} }
public partial class PenumbraIpc public partial class PenumbraIpc
{ {
public const string LabelProviderResolveDefault = "Penumbra.ResolveDefaultPath"; public const string LabelProviderResolveDefault = "Penumbra.ResolveDefaultPath";
public const string LabelProviderResolveCharacter = "Penumbra.ResolveCharacterPath"; public const string LabelProviderResolveCharacter = "Penumbra.ResolveCharacterPath";
public const string LabelProviderGetDrawObjectInfo = "Penumbra.GetDrawObjectInfo"; public const string LabelProviderGetDrawObjectInfo = "Penumbra.GetDrawObjectInfo";
public const string LabelProviderReverseResolvePath = "Penumbra.ReverseResolvePath";
internal ICallGateProvider< string, string >? ProviderResolveDefault; internal ICallGateProvider< string, string >? ProviderResolveDefault;
internal ICallGateProvider< string, string, string >? ProviderResolveCharacter; internal ICallGateProvider< string, string, string >? ProviderResolveCharacter;
internal ICallGateProvider< IntPtr, (IntPtr, string) >? ProviderGetDrawObjectInfo; internal ICallGateProvider< IntPtr, (IntPtr, string) >? ProviderGetDrawObjectInfo;
internal ICallGateProvider< string, string, IList< string > >? ProviderReverseResolvePath;
private void InitializeResolveProviders( DalamudPluginInterface pi ) private void InitializeResolveProviders( DalamudPluginInterface pi )
{ {
@ -225,6 +243,16 @@ public partial class PenumbraIpc
{ {
PluginLog.Error( $"Error registering IPC provider for {LabelProviderGetDrawObjectInfo}:\n{e}" ); PluginLog.Error( $"Error registering IPC provider for {LabelProviderGetDrawObjectInfo}:\n{e}" );
} }
try
{
ProviderReverseResolvePath = pi.GetIpcProvider< string, string, IList< string > >( LabelProviderReverseResolvePath );
ProviderReverseResolvePath.RegisterFunc( Api.ReverseResolvePath );
}
catch( Exception e )
{
PluginLog.Error( $"Error registering IPC provider for {LabelProviderGetDrawObjectInfo}:\n{e}" );
}
} }
private void DisposeResolveProviders() private void DisposeResolveProviders()
@ -232,6 +260,7 @@ public partial class PenumbraIpc
ProviderGetDrawObjectInfo?.UnregisterFunc(); ProviderGetDrawObjectInfo?.UnregisterFunc();
ProviderResolveDefault?.UnregisterFunc(); ProviderResolveDefault?.UnregisterFunc();
ProviderResolveCharacter?.UnregisterFunc(); ProviderResolveCharacter?.UnregisterFunc();
ProviderReverseResolvePath?.UnregisterFunc();
} }
} }
@ -356,7 +385,7 @@ public partial class PenumbraIpc
try try
{ {
ProviderCharacterCollectionName = pi.GetIpcProvider< string, ( string, bool) >( LabelProviderCharacterCollectionName ); ProviderCharacterCollectionName = pi.GetIpcProvider< string, (string, bool) >( LabelProviderCharacterCollectionName );
ProviderCharacterCollectionName.RegisterFunc( Api.GetCharacterCollection ); ProviderCharacterCollectionName.RegisterFunc( Api.GetCharacterCollection );
} }
catch( Exception e ) catch( Exception e )

View file

@ -44,6 +44,8 @@ public partial class ModCollection
PluginLog.Verbose( "Cleared cache of collection {Name:l}.", Name ); PluginLog.Verbose( "Cleared cache of collection {Name:l}.", Name );
} }
public IEnumerable< Utf8GamePath > ReverseResolvePath( FullPath path )
=> _cache?.ReverseResolvePath( path ) ?? Array.Empty< Utf8GamePath >();
public FullPath? ResolvePath( Utf8GamePath path ) public FullPath? ResolvePath( Utf8GamePath path )
=> _cache?.ResolvePath( path ); => _cache?.ResolvePath( path );

View file

@ -79,6 +79,28 @@ public partial class ModCollection
return candidate.Path; return candidate.Path;
} }
// For a given full path, find all game paths that currently use this file.
public IEnumerable< Utf8GamePath > ReverseResolvePath( FullPath localFilePath )
{
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 _ ) private void OnModSettingChange( ModSettingChange type, int modIdx, int oldValue, int groupIdx, bool _ )
{ {
switch( type ) switch( type )

View file

@ -25,7 +25,6 @@ public unsafe partial class ObjectReloader
private static void EnableDraw( GameObject actor ) private static void EnableDraw( GameObject actor )
=> ( ( delegate* unmanaged< IntPtr, void >** )actor.Address )[ 0 ][ 16 ]( actor.Address ); => ( ( delegate* unmanaged< IntPtr, void >** )actor.Address )[ 0 ][ 16 ]( actor.Address );
// Check whether we currently are in GPose. // Check whether we currently are in GPose.
// Also clear the name list. // Also clear the name list.
private void SetGPose() private void SetGPose()
@ -106,6 +105,8 @@ public sealed unsafe partial class ObjectReloader : IDisposable
private readonly List< int > _afterGPoseQueue = new(GPoseSlots); private readonly List< int > _afterGPoseQueue = new(GPoseSlots);
private int _target = -1; private int _target = -1;
public event Action< IntPtr, int >? GameObjectRedrawn;
public ObjectReloader() public ObjectReloader()
=> Dalamud.Framework.Update += OnUpdateEvent; => Dalamud.Framework.Update += OnUpdateEvent;
@ -133,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 ) ) if( BadRedrawIndices( actor, out var tableIndex ) )
{ {
@ -141,11 +142,12 @@ public sealed unsafe partial class ObjectReloader : IDisposable
} }
*ActorDrawState( actor! ) &= ~DrawState.Invisibility; *ActorDrawState( actor! ) &= ~DrawState.Invisibility;
if( IsGPoseActor( tableIndex ) ) if( IsGPoseActor( tableIndex ) )
{ {
EnableDraw( actor! ); EnableDraw( actor! );
} }
GameObjectRedrawn?.Invoke( actor!.Address, tableIndex );
} }
private void ReloadActor( GameObject? actor ) private void ReloadActor( GameObject? actor )