mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Add ReverseResolvePlayer.
This commit is contained in:
parent
95de9ea48a
commit
9115cbaac1
5 changed files with 99 additions and 27 deletions
|
|
@ -22,7 +22,9 @@ 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 delegate void GameObjectRedrawn( IntPtr objectPtr, int objectTableIndex );
|
||||||
public delegate void ModSettingChanged( ModSettingChange type, string collectionName, string modDirectory, bool inherited );
|
public delegate void ModSettingChanged( ModSettingChange type, string collectionName, string modDirectory, bool inherited );
|
||||||
public delegate void CreatingCharacterBaseDelegate( IntPtr gameObject, ModCollection collection, IntPtr customize, IntPtr equipData );
|
|
||||||
|
public delegate void CreatingCharacterBaseDelegate( IntPtr gameObject, ModCollection collection, IntPtr modelId, IntPtr customize,
|
||||||
|
IntPtr equipData );
|
||||||
|
|
||||||
public enum PenumbraApiEc
|
public enum PenumbraApiEc
|
||||||
{
|
{
|
||||||
|
|
@ -87,8 +89,12 @@ 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
|
// Reverse resolves a given modded local path into its replacement in form of all applicable game paths for given character collection.
|
||||||
public IList< string > ReverseResolvePath( string moddedPath, string characterName );
|
public string[] ReverseResolvePath( string moddedPath, string characterName );
|
||||||
|
|
||||||
|
// Reverse resolves a given modded local path into its replacement in form of all applicable game paths
|
||||||
|
// using the collection applying to the player character.
|
||||||
|
public string[] ReverseResolvePathPlayer( string moddedPath );
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ public class IpcTester : IDisposable
|
||||||
private readonly ICallGateSubscriber< string, object? > _postSettingsDraw;
|
private readonly ICallGateSubscriber< string, object? > _postSettingsDraw;
|
||||||
private readonly ICallGateSubscriber< IntPtr, int, object? > _redrawn;
|
private readonly ICallGateSubscriber< IntPtr, int, object? > _redrawn;
|
||||||
private readonly ICallGateSubscriber< ModSettingChange, string, string, bool, object? > _settingChanged;
|
private readonly ICallGateSubscriber< ModSettingChange, string, string, bool, object? > _settingChanged;
|
||||||
private readonly ICallGateSubscriber< IntPtr, string, IntPtr, IntPtr, object? > _characterBaseCreated;
|
private readonly ICallGateSubscriber< IntPtr, string, IntPtr, IntPtr, IntPtr, object? > _characterBaseCreated;
|
||||||
|
|
||||||
private readonly List< DateTimeOffset > _initializedList = new();
|
private readonly List< DateTimeOffset > _initializedList = new();
|
||||||
private readonly List< DateTimeOffset > _disposedList = new();
|
private readonly List< DateTimeOffset > _disposedList = new();
|
||||||
|
|
@ -46,7 +46,7 @@ public class IpcTester : IDisposable
|
||||||
_postSettingsDraw = _pi.GetIpcSubscriber< string, object? >( PenumbraIpc.LabelProviderPostSettingsDraw );
|
_postSettingsDraw = _pi.GetIpcSubscriber< string, object? >( PenumbraIpc.LabelProviderPostSettingsDraw );
|
||||||
_settingChanged = _pi.GetIpcSubscriber< ModSettingChange, string, string, bool, object? >( PenumbraIpc.LabelProviderModSettingChanged );
|
_settingChanged = _pi.GetIpcSubscriber< ModSettingChange, string, string, bool, object? >( PenumbraIpc.LabelProviderModSettingChanged );
|
||||||
_characterBaseCreated =
|
_characterBaseCreated =
|
||||||
_pi.GetIpcSubscriber< IntPtr, string, IntPtr, IntPtr, object? >( PenumbraIpc.LabelProviderCreatingCharacterBase );
|
_pi.GetIpcSubscriber< IntPtr, string, IntPtr, IntPtr, IntPtr, object? >( PenumbraIpc.LabelProviderCreatingCharacterBase );
|
||||||
_initialized.Subscribe( AddInitialized );
|
_initialized.Subscribe( AddInitialized );
|
||||||
_disposed.Subscribe( AddDisposed );
|
_disposed.Subscribe( AddDisposed );
|
||||||
_redrawn.Subscribe( SetLastRedrawn );
|
_redrawn.Subscribe( SetLastRedrawn );
|
||||||
|
|
@ -204,7 +204,7 @@ public class IpcTester : IDisposable
|
||||||
private string _lastCreatedGameObjectName = string.Empty;
|
private string _lastCreatedGameObjectName = string.Empty;
|
||||||
private DateTimeOffset _lastCreatedGameObjectTime = DateTimeOffset.MaxValue;
|
private DateTimeOffset _lastCreatedGameObjectTime = DateTimeOffset.MaxValue;
|
||||||
|
|
||||||
private unsafe void UpdateLastCreated( IntPtr gameObject, string _, IntPtr _2, IntPtr _3 )
|
private unsafe void UpdateLastCreated( IntPtr gameObject, string _, IntPtr _2, IntPtr _3, IntPtr _4 )
|
||||||
{
|
{
|
||||||
var obj = ( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* )gameObject;
|
var obj = ( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* )gameObject;
|
||||||
_lastCreatedGameObjectName = new Utf8String( obj->GetName() ).ToString();
|
_lastCreatedGameObjectName = new Utf8String( obj->GetName() ).ToString();
|
||||||
|
|
@ -278,6 +278,21 @@ public class IpcTester : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DrawIntro( PenumbraIpc.LabelProviderReverseResolvePathPlayer, "Reversed Game Paths (Player)" );
|
||||||
|
if( _currentReversePath.Length > 0 )
|
||||||
|
{
|
||||||
|
var list = _pi.GetIpcSubscriber< string, string[] >( PenumbraIpc.LabelProviderReverseResolvePathPlayer )
|
||||||
|
.InvokeFunc( _currentReversePath );
|
||||||
|
if( list.Length > 0 )
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted( list[ 0 ] );
|
||||||
|
if( list.Length > 1 && ImGui.IsItemHovered() )
|
||||||
|
{
|
||||||
|
ImGui.SetTooltip( string.Join( "\n", list.Skip( 1 ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DrawIntro( PenumbraIpc.LabelProviderCreatingCharacterBase, "Last Drawobject created" );
|
DrawIntro( PenumbraIpc.LabelProviderCreatingCharacterBase, "Last Drawobject created" );
|
||||||
if( _lastCreatedGameObjectTime < DateTimeOffset.Now )
|
if( _lastCreatedGameObjectTime < DateTimeOffset.Now )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ using OtterGui;
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.GameData.ByteString;
|
using Penumbra.GameData.ByteString;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
using Penumbra.Interop.Resolver;
|
||||||
using Penumbra.Meta.Manipulations;
|
using Penumbra.Meta.Manipulations;
|
||||||
using Penumbra.Mods;
|
using Penumbra.Mods;
|
||||||
using Penumbra.Util;
|
using Penumbra.Util;
|
||||||
|
|
@ -21,7 +22,7 @@ namespace Penumbra.Api;
|
||||||
public class PenumbraApi : IDisposable, IPenumbraApi
|
public class PenumbraApi : IDisposable, IPenumbraApi
|
||||||
{
|
{
|
||||||
public (int, int) ApiVersion
|
public (int, int) ApiVersion
|
||||||
=> ( 4, 8 );
|
=> ( 4, 9 );
|
||||||
|
|
||||||
private Penumbra? _penumbra;
|
private Penumbra? _penumbra;
|
||||||
private Lumina.GameData? _lumina;
|
private Lumina.GameData? _lumina;
|
||||||
|
|
@ -129,7 +130,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
||||||
Penumbra.CollectionManager.Character( characterName ) );
|
Penumbra.CollectionManager.Character( characterName ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList< string > ReverseResolvePath( string path, string characterName )
|
public string[] ReverseResolvePath( string path, string characterName )
|
||||||
{
|
{
|
||||||
CheckInitialized();
|
CheckInitialized();
|
||||||
if( !Penumbra.Config.EnableMods )
|
if( !Penumbra.Config.EnableMods )
|
||||||
|
|
@ -138,7 +139,19 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
||||||
}
|
}
|
||||||
|
|
||||||
var ret = Penumbra.CollectionManager.Character( characterName ).ReverseResolvePath( new FullPath( path ) );
|
var ret = Penumbra.CollectionManager.Character( characterName ).ReverseResolvePath( new FullPath( path ) );
|
||||||
return ret.Select( r => r.ToString() ).ToList();
|
return ret.Select( r => r.ToString() ).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] ReverseResolvePathPlayer( string path )
|
||||||
|
{
|
||||||
|
CheckInitialized();
|
||||||
|
if( !Penumbra.Config.EnableMods )
|
||||||
|
{
|
||||||
|
return new[] { path };
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = PathResolver.PlayerCollection().ReverseResolvePath( new FullPath( path ) );
|
||||||
|
return ret.Select( r => r.ToString() ).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public T? GetFile< T >( string gamePath ) where T : FileResource
|
public T? GetFile< T >( string gamePath ) where T : FileResource
|
||||||
|
|
|
||||||
|
|
@ -257,17 +257,19 @@ public partial class PenumbraIpc
|
||||||
|
|
||||||
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";
|
public const string LabelProviderReverseResolvePath = "Penumbra.ReverseResolvePath";
|
||||||
public const string LabelProviderCreatingCharacterBase = "Penumbra.CreatingCharacterBase";
|
public const string LabelProviderReverseResolvePathPlayer = "Penumbra.ReverseResolvePathPlayer";
|
||||||
|
public const string LabelProviderCreatingCharacterBase = "Penumbra.CreatingCharacterBase";
|
||||||
|
|
||||||
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;
|
internal ICallGateProvider< string, string, string[] >? ProviderReverseResolvePath;
|
||||||
internal ICallGateProvider< IntPtr, string, IntPtr, IntPtr, object? >? ProviderCreatingCharacterBase;
|
internal ICallGateProvider< string, string[] >? ProviderReverseResolvePathPlayer;
|
||||||
|
internal ICallGateProvider< IntPtr, string, IntPtr, IntPtr, IntPtr, object? >? ProviderCreatingCharacterBase;
|
||||||
|
|
||||||
private void InitializeResolveProviders( DalamudPluginInterface pi )
|
private void InitializeResolveProviders( DalamudPluginInterface pi )
|
||||||
{
|
{
|
||||||
|
|
@ -303,18 +305,29 @@ public partial class PenumbraIpc
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ProviderReverseResolvePath = pi.GetIpcProvider< string, string, IList< string > >( LabelProviderReverseResolvePath );
|
ProviderReverseResolvePath = pi.GetIpcProvider< string, string, string[] >( LabelProviderReverseResolvePath );
|
||||||
ProviderReverseResolvePath.RegisterFunc( Api.ReverseResolvePath );
|
ProviderReverseResolvePath.RegisterFunc( Api.ReverseResolvePath );
|
||||||
}
|
}
|
||||||
catch( Exception e )
|
catch( Exception e )
|
||||||
{
|
{
|
||||||
PluginLog.Error( $"Error registering IPC provider for {LabelProviderGetDrawObjectInfo}:\n{e}" );
|
PluginLog.Error( $"Error registering IPC provider for {LabelProviderReverseResolvePath}:\n{e}" );
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ProviderCreatingCharacterBase = pi.GetIpcProvider< IntPtr, string, IntPtr, IntPtr, object? >( LabelProviderCreatingCharacterBase );
|
ProviderReverseResolvePathPlayer = pi.GetIpcProvider< string, string[] >( LabelProviderReverseResolvePathPlayer );
|
||||||
Api.CreatingCharacterBase += CreatingCharacterBaseEvent;
|
ProviderReverseResolvePathPlayer.RegisterFunc( Api.ReverseResolvePathPlayer );
|
||||||
|
}
|
||||||
|
catch( Exception e )
|
||||||
|
{
|
||||||
|
PluginLog.Error( $"Error registering IPC provider for {LabelProviderReverseResolvePathPlayer}:\n{e}" );
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ProviderCreatingCharacterBase =
|
||||||
|
pi.GetIpcProvider< IntPtr, string, IntPtr, IntPtr, IntPtr, object? >( LabelProviderCreatingCharacterBase );
|
||||||
|
Api.CreatingCharacterBase += CreatingCharacterBaseEvent;
|
||||||
}
|
}
|
||||||
catch( Exception e )
|
catch( Exception e )
|
||||||
{
|
{
|
||||||
|
|
@ -328,12 +341,13 @@ public partial class PenumbraIpc
|
||||||
ProviderResolveDefault?.UnregisterFunc();
|
ProviderResolveDefault?.UnregisterFunc();
|
||||||
ProviderResolveCharacter?.UnregisterFunc();
|
ProviderResolveCharacter?.UnregisterFunc();
|
||||||
ProviderReverseResolvePath?.UnregisterFunc();
|
ProviderReverseResolvePath?.UnregisterFunc();
|
||||||
|
ProviderReverseResolvePathPlayer?.UnregisterFunc();
|
||||||
Api.CreatingCharacterBase -= CreatingCharacterBaseEvent;
|
Api.CreatingCharacterBase -= CreatingCharacterBaseEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreatingCharacterBaseEvent( IntPtr gameObject, ModCollection collection, IntPtr customize, IntPtr equipData )
|
private void CreatingCharacterBaseEvent( IntPtr gameObject, ModCollection collection, IntPtr modelId, IntPtr customize, IntPtr equipData )
|
||||||
{
|
{
|
||||||
ProviderCreatingCharacterBase?.SendMessage( gameObject, collection.Name, customize, equipData );
|
ProviderCreatingCharacterBase?.SendMessage( gameObject, collection.Name, modelId, customize, equipData );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,14 +31,14 @@ public unsafe partial class PathResolver
|
||||||
private ModCollection? _lastCreatedCollection;
|
private ModCollection? _lastCreatedCollection;
|
||||||
public event CreatingCharacterBaseDelegate? CreatingCharacterBase;
|
public event CreatingCharacterBaseDelegate? CreatingCharacterBase;
|
||||||
|
|
||||||
|
|
||||||
private IntPtr CharacterBaseCreateDetour( uint a, IntPtr b, IntPtr c, byte d )
|
private IntPtr CharacterBaseCreateDetour( uint a, IntPtr b, IntPtr c, byte d )
|
||||||
{
|
{
|
||||||
using var cmp = MetaChanger.ChangeCmp( this, out _lastCreatedCollection );
|
using var cmp = MetaChanger.ChangeCmp( this, out _lastCreatedCollection );
|
||||||
|
|
||||||
if( LastGameObject != null )
|
if( LastGameObject != null )
|
||||||
{
|
{
|
||||||
CreatingCharacterBase?.Invoke( ( IntPtr )LastGameObject, _lastCreatedCollection!, b, c );
|
var modelPtr = &a;
|
||||||
|
CreatingCharacterBase?.Invoke( ( IntPtr )LastGameObject, _lastCreatedCollection!, ( IntPtr )modelPtr, b, c );
|
||||||
}
|
}
|
||||||
|
|
||||||
var ret = CharacterBaseCreateHook!.Original( a, b, c, d );
|
var ret = CharacterBaseCreateHook!.Original( a, b, c, d );
|
||||||
|
|
@ -341,6 +341,30 @@ public unsafe partial class PathResolver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the collection applying to the current player character
|
||||||
|
// or the default collection if no player exists.
|
||||||
|
public static ModCollection PlayerCollection()
|
||||||
|
{
|
||||||
|
var player = Dalamud.ClientState.LocalPlayer;
|
||||||
|
if( player == null )
|
||||||
|
{
|
||||||
|
return Penumbra.CollectionManager.Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
var name = player.Name.TextValue;
|
||||||
|
if( CollectionByActorName( name, out var c ) )
|
||||||
|
{
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( CollectionByActor( name, ( GameObject* )player.Address, out c ) )
|
||||||
|
{
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Penumbra.CollectionManager.Default;
|
||||||
|
}
|
||||||
|
|
||||||
// Check both temporary and permanent character collections. Temporary first.
|
// Check both temporary and permanent character collections. Temporary first.
|
||||||
private static bool CollectionByActorName( string name, [NotNullWhen( true )] out ModCollection? collection )
|
private static bool CollectionByActorName( string name, [NotNullWhen( true )] out ModCollection? collection )
|
||||||
=> Penumbra.TempMods.Collections.TryGetValue( name, out collection )
|
=> Penumbra.TempMods.Collections.TryGetValue( name, out collection )
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue