mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Add ResolvePlayerPaths.
This commit is contained in:
parent
58c74e839c
commit
fe561f39c2
6 changed files with 126 additions and 37 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit b65f0a4e2a761a3142a07587a6c0f8657f1361ee
|
||||
Subproject commit 97dc16ba32bf78c4d3a4d210a08010cd6d4eec3c
|
||||
|
|
@ -678,6 +678,32 @@ public class IpcTester : IDisposable
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
DrawIntro( Ipc.ResolvePlayerPaths.Label, "Resolved Paths (Player)" );
|
||||
if( _currentResolvePath.Length > 0 || _currentReversePath.Length > 0 )
|
||||
{
|
||||
var forwardArray = _currentResolvePath.Length > 0 ? new[] { _currentResolvePath } : Array.Empty< string >();
|
||||
var reverseArray = _currentReversePath.Length > 0 ? new[] { _currentReversePath } : Array.Empty< string >();
|
||||
var ret = Ipc.ResolvePlayerPaths.Subscriber( _pi ).Invoke( forwardArray, reverseArray );
|
||||
var text = string.Empty;
|
||||
if( ret.Item1.Length > 0 )
|
||||
{
|
||||
if( ret.Item2.Length > 0 )
|
||||
{
|
||||
text = $"Forward: {ret.Item1[ 0 ]} | Reverse: {string.Join( "; ", ret.Item2[ 0 ] )}.";
|
||||
}
|
||||
else
|
||||
{
|
||||
text = $"Forward: {ret.Item1[ 0 ]}.";
|
||||
}
|
||||
}
|
||||
else if( ret.Item2.Length > 0 )
|
||||
{
|
||||
text = $"Reverse: {string.Join( "; ", ret.Item2[ 0 ] )}.";
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted( text );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -685,10 +711,10 @@ public class IpcTester : IDisposable
|
|||
{
|
||||
private readonly DalamudPluginInterface _pi;
|
||||
|
||||
private int _objectIdx = 0;
|
||||
private string _collectionName = string.Empty;
|
||||
private bool _allowCreation = true;
|
||||
private bool _allowDeletion = true;
|
||||
private int _objectIdx = 0;
|
||||
private string _collectionName = string.Empty;
|
||||
private bool _allowCreation = true;
|
||||
private bool _allowDeletion = true;
|
||||
private ApiCollectionType _type = ApiCollectionType.Current;
|
||||
|
||||
private string _characterCollectionName = string.Empty;
|
||||
|
|
@ -709,7 +735,7 @@ public class IpcTester : IDisposable
|
|||
return;
|
||||
}
|
||||
|
||||
ImGuiUtil.GenericEnumCombo( "Collection Type", 200, _type, out _type, t => ((CollectionType)t).ToName() );
|
||||
ImGuiUtil.GenericEnumCombo( "Collection Type", 200, _type, out _type, t => ( ( CollectionType )t ).ToName() );
|
||||
ImGui.InputInt( "Object Index##Collections", ref _objectIdx, 0, 0 );
|
||||
ImGui.InputText( "Collection Name##Collections", ref _collectionName, 64 );
|
||||
ImGui.Checkbox( "Allow Assignment Creation", ref _allowCreation );
|
||||
|
|
@ -766,8 +792,11 @@ public class IpcTester : IDisposable
|
|||
{
|
||||
( _returnCode, _oldCollection ) = Ipc.SetCollectionForObject.Subscriber( _pi ).Invoke( _objectIdx, _collectionName, _allowCreation, _allowDeletion );
|
||||
}
|
||||
|
||||
if( _returnCode == PenumbraApiEc.NothingChanged && _oldCollection.IsNullOrEmpty() )
|
||||
{
|
||||
_oldCollection = null;
|
||||
}
|
||||
|
||||
DrawIntro( Ipc.GetChangedItems.Label, "Changed Item List" );
|
||||
ImGui.SetNextItemWidth( 200 * ImGuiHelpers.GlobalScale );
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.String;
|
||||
|
|
@ -23,7 +24,7 @@ namespace Penumbra.Api;
|
|||
public class PenumbraApi : IDisposable, IPenumbraApi
|
||||
{
|
||||
public (int, int) ApiVersion
|
||||
=> ( 4, 18 );
|
||||
=> ( 4, 19 );
|
||||
|
||||
private Penumbra? _penumbra;
|
||||
private Lumina.GameData? _lumina;
|
||||
|
|
@ -271,6 +272,20 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
return ret.Select( r => r.ToString() ).ToArray();
|
||||
}
|
||||
|
||||
public (string[], string[][]) ResolvePlayerPaths( string[] forward, string[] reverse )
|
||||
{
|
||||
CheckInitialized();
|
||||
if( !Penumbra.Config.EnableMods )
|
||||
{
|
||||
return ( forward, reverse.Select( p => new[] { p } ).ToArray() );
|
||||
}
|
||||
|
||||
var playerCollection = PathResolver.PlayerCollection();
|
||||
var resolved = forward.Select( p => ResolvePath( p, Penumbra.ModManager, playerCollection ) ).ToArray();
|
||||
var reverseResolved = playerCollection.ReverseResolvePaths( reverse );
|
||||
return ( resolved, reverseResolved.Select( a => a.Select( p => p.ToString() ).ToArray() ).ToArray() );
|
||||
}
|
||||
|
||||
public T? GetFile< T >( string gamePath ) where T : FileResource
|
||||
=> GetFileIntern< T >( ResolveDefaultPath( gamePath ) );
|
||||
|
||||
|
|
@ -306,17 +321,21 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
{
|
||||
CheckInitialized();
|
||||
if( !Enum.IsDefined( type ) )
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var collection = Penumbra.CollectionManager.ByType( ( CollectionType )type );
|
||||
return collection?.Name ?? string.Empty;
|
||||
}
|
||||
|
||||
public (PenumbraApiEc, string OldCollection) SetCollectionForType( Enums.ApiCollectionType type, string collectionName, bool allowCreateNew, bool allowDelete )
|
||||
public (PenumbraApiEc, string OldCollection) SetCollectionForType( ApiCollectionType type, string collectionName, bool allowCreateNew, bool allowDelete )
|
||||
{
|
||||
CheckInitialized();
|
||||
if( !Enum.IsDefined( type ) )
|
||||
{
|
||||
return ( PenumbraApiEc.InvalidArgument, string.Empty );
|
||||
}
|
||||
|
||||
var oldCollection = Penumbra.CollectionManager.ByType( ( CollectionType )type )?.Name ?? string.Empty;
|
||||
|
||||
|
|
@ -327,18 +346,18 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
return ( PenumbraApiEc.NothingChanged, oldCollection );
|
||||
}
|
||||
|
||||
if( !allowDelete || type is Enums.ApiCollectionType.Current or Enums.ApiCollectionType.Default or Enums.ApiCollectionType.Interface )
|
||||
if( !allowDelete || type is ApiCollectionType.Current or ApiCollectionType.Default or ApiCollectionType.Interface )
|
||||
{
|
||||
return ( PenumbraApiEc.AssignmentDeletionDisallowed, oldCollection );
|
||||
}
|
||||
|
||||
Penumbra.CollectionManager.RemoveSpecialCollection( (CollectionType) type );
|
||||
Penumbra.CollectionManager.RemoveSpecialCollection( ( CollectionType )type );
|
||||
return ( PenumbraApiEc.Success, oldCollection );
|
||||
}
|
||||
|
||||
if( !Penumbra.CollectionManager.ByName( collectionName, out var collection ) )
|
||||
{
|
||||
return (PenumbraApiEc.CollectionMissing, oldCollection);
|
||||
return ( PenumbraApiEc.CollectionMissing, oldCollection );
|
||||
}
|
||||
|
||||
if( oldCollection.Length == 0 )
|
||||
|
|
@ -355,7 +374,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
return ( PenumbraApiEc.NothingChanged, oldCollection );
|
||||
}
|
||||
|
||||
Penumbra.CollectionManager.SetCollection( collection, (CollectionType) type );
|
||||
Penumbra.CollectionManager.SetCollection( collection, ( CollectionType )type );
|
||||
return ( PenumbraApiEc.Success, oldCollection );
|
||||
}
|
||||
|
||||
|
|
@ -392,28 +411,29 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
{
|
||||
if( oldCollection.Length == 0 )
|
||||
{
|
||||
return (PenumbraApiEc.NothingChanged, oldCollection);
|
||||
return ( PenumbraApiEc.NothingChanged, oldCollection );
|
||||
}
|
||||
|
||||
if( !allowDelete )
|
||||
{
|
||||
return (PenumbraApiEc.AssignmentDeletionDisallowed, oldCollection);
|
||||
return ( PenumbraApiEc.AssignmentDeletionDisallowed, oldCollection );
|
||||
}
|
||||
|
||||
var idx = Penumbra.CollectionManager.Individuals.Index( id );
|
||||
Penumbra.CollectionManager.RemoveIndividualCollection(idx );
|
||||
return (PenumbraApiEc.Success, oldCollection);
|
||||
Penumbra.CollectionManager.RemoveIndividualCollection( idx );
|
||||
return ( PenumbraApiEc.Success, oldCollection );
|
||||
}
|
||||
|
||||
if( !Penumbra.CollectionManager.ByName( collectionName, out var collection ) )
|
||||
{
|
||||
return (PenumbraApiEc.CollectionMissing, oldCollection);
|
||||
return ( PenumbraApiEc.CollectionMissing, oldCollection );
|
||||
}
|
||||
|
||||
if( oldCollection.Length == 0 )
|
||||
{
|
||||
if( !allowCreateNew )
|
||||
{
|
||||
return (PenumbraApiEc.AssignmentCreationDisallowed, oldCollection);
|
||||
return ( PenumbraApiEc.AssignmentCreationDisallowed, oldCollection );
|
||||
}
|
||||
|
||||
var ids = Penumbra.CollectionManager.Individuals.GetGroup( id );
|
||||
|
|
@ -421,11 +441,11 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
}
|
||||
else if( oldCollection == collection.Name )
|
||||
{
|
||||
return (PenumbraApiEc.NothingChanged, oldCollection);
|
||||
return ( PenumbraApiEc.NothingChanged, oldCollection );
|
||||
}
|
||||
|
||||
Penumbra.CollectionManager.SetCollection( collection, CollectionType.Individual, Penumbra.CollectionManager.Individuals.Index( id ) );
|
||||
return (PenumbraApiEc.Success, oldCollection);
|
||||
return ( PenumbraApiEc.Success, oldCollection );
|
||||
}
|
||||
|
||||
public IList< string > GetCollections()
|
||||
|
|
@ -983,6 +1003,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
=> ChangedItemClicked?.Invoke( button, it );
|
||||
|
||||
|
||||
[MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )]
|
||||
private void CheckInitialized()
|
||||
{
|
||||
if( !Valid )
|
||||
|
|
@ -993,6 +1014,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
|
||||
// Return the collection associated to a current game object. If it does not exist, return the default collection.
|
||||
// If the index is invalid, returns false and the default collection.
|
||||
[MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )]
|
||||
private static unsafe bool AssociatedCollection( int gameObjectIdx, out ModCollection collection )
|
||||
{
|
||||
collection = Penumbra.CollectionManager.Default;
|
||||
|
|
@ -1011,17 +1033,20 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )]
|
||||
private static unsafe ActorIdentifier AssociatedIdentifier( int gameObjectIdx )
|
||||
{
|
||||
if( gameObjectIdx < 0 || gameObjectIdx >= Dalamud.Objects.Length )
|
||||
{
|
||||
return ActorIdentifier.Invalid;
|
||||
}
|
||||
|
||||
var ptr = ( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* )Dalamud.Objects.GetObjectAddress( gameObjectIdx );
|
||||
return Penumbra.Actors.FromObject( ptr, out _, false, true );
|
||||
}
|
||||
|
||||
// Resolve a path given by string for a specific collection.
|
||||
[MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )]
|
||||
private static string ResolvePath( string path, Mod.Manager _, ModCollection collection )
|
||||
{
|
||||
if( !Penumbra.Config.EnableMods )
|
||||
|
|
|
|||
|
|
@ -49,26 +49,27 @@ public class PenumbraIpcProviders : IDisposable
|
|||
internal readonly EventProvider< nint, string, string > GameObjectResourcePathResolved;
|
||||
|
||||
// Resolve
|
||||
internal readonly FuncProvider< string, string > ResolveDefaultPath;
|
||||
internal readonly FuncProvider< string, string > ResolveInterfacePath;
|
||||
internal readonly FuncProvider< string, string > ResolvePlayerPath;
|
||||
internal readonly FuncProvider< string, int, string > ResolveGameObjectPath;
|
||||
internal readonly FuncProvider< string, string, string > ResolveCharacterPath;
|
||||
internal readonly FuncProvider< string, string, string[] > ReverseResolvePath;
|
||||
internal readonly FuncProvider< string, int, string[] > ReverseResolveGameObjectPath;
|
||||
internal readonly FuncProvider< string, string[] > ReverseResolvePlayerPath;
|
||||
internal readonly FuncProvider< string, string > ResolveDefaultPath;
|
||||
internal readonly FuncProvider< string, string > ResolveInterfacePath;
|
||||
internal readonly FuncProvider< string, string > ResolvePlayerPath;
|
||||
internal readonly FuncProvider< string, int, string > ResolveGameObjectPath;
|
||||
internal readonly FuncProvider< string, string, string > ResolveCharacterPath;
|
||||
internal readonly FuncProvider< string, string, string[] > ReverseResolvePath;
|
||||
internal readonly FuncProvider< string, int, string[] > ReverseResolveGameObjectPath;
|
||||
internal readonly FuncProvider< string, string[] > ReverseResolvePlayerPath;
|
||||
internal readonly FuncProvider< string[], string[], (string[], string[][]) > ResolvePlayerPaths;
|
||||
|
||||
// Collections
|
||||
internal readonly FuncProvider< IList< string > > GetCollections;
|
||||
internal readonly FuncProvider< string > GetCurrentCollectionName;
|
||||
internal readonly FuncProvider< string > GetDefaultCollectionName;
|
||||
internal readonly FuncProvider< string > GetInterfaceCollectionName;
|
||||
internal readonly FuncProvider< string, (string, bool) > GetCharacterCollectionName;
|
||||
internal readonly FuncProvider< IList< string > > GetCollections;
|
||||
internal readonly FuncProvider< string > GetCurrentCollectionName;
|
||||
internal readonly FuncProvider< string > GetDefaultCollectionName;
|
||||
internal readonly FuncProvider< string > GetInterfaceCollectionName;
|
||||
internal readonly FuncProvider< string, (string, bool) > GetCharacterCollectionName;
|
||||
internal readonly FuncProvider< ApiCollectionType, string > GetCollectionForType;
|
||||
internal readonly FuncProvider< ApiCollectionType, string, bool, bool, (PenumbraApiEc, string) > SetCollectionForType;
|
||||
internal readonly FuncProvider< int, (bool, bool, string) > GetCollectionForObject;
|
||||
internal readonly FuncProvider< int, string, bool, bool, (PenumbraApiEc, string) > SetCollectionForObject;
|
||||
internal readonly FuncProvider< string, IReadOnlyDictionary< string, object? > > GetChangedItems;
|
||||
internal readonly FuncProvider< int, (bool, bool, string) > GetCollectionForObject;
|
||||
internal readonly FuncProvider< int, string, bool, bool, (PenumbraApiEc, string) > SetCollectionForObject;
|
||||
internal readonly FuncProvider< string, IReadOnlyDictionary< string, object? > > GetChangedItems;
|
||||
|
||||
// Meta
|
||||
internal readonly FuncProvider< string > GetPlayerMetaManipulations;
|
||||
|
|
@ -160,6 +161,7 @@ public class PenumbraIpcProviders : IDisposable
|
|||
ReverseResolvePath = Ipc.ReverseResolvePath.Provider( pi, Api.ReverseResolvePath );
|
||||
ReverseResolveGameObjectPath = Ipc.ReverseResolveGameObjectPath.Provider( pi, Api.ReverseResolveGameObjectPath );
|
||||
ReverseResolvePlayerPath = Ipc.ReverseResolvePlayerPath.Provider( pi, Api.ReverseResolvePlayerPath );
|
||||
ResolvePlayerPaths = Ipc.ResolvePlayerPaths.Provider( pi, Api.ResolvePlayerPaths );
|
||||
|
||||
// Collections
|
||||
GetCollections = Ipc.GetCollections.Provider( pi, Api.GetCollections );
|
||||
|
|
@ -263,6 +265,7 @@ public class PenumbraIpcProviders : IDisposable
|
|||
ReverseResolvePath.Dispose();
|
||||
ReverseResolveGameObjectPath.Dispose();
|
||||
ReverseResolvePlayerPath.Dispose();
|
||||
ResolvePlayerPaths.Dispose();
|
||||
|
||||
// Collections
|
||||
GetCollections.Dispose();
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Penumbra.Meta.Manager;
|
|||
using Penumbra.Mods;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using Penumbra.Interop;
|
||||
|
|
@ -68,6 +69,9 @@ public partial class ModCollection
|
|||
public IEnumerable< Utf8GamePath > ReverseResolvePath( FullPath path )
|
||||
=> _cache?.ReverseResolvePath( path ) ?? Array.Empty< Utf8GamePath >();
|
||||
|
||||
public HashSet< Utf8GamePath >[] ReverseResolvePaths( string[] paths )
|
||||
=> _cache?.ReverseResolvePaths( paths ) ?? paths.Select( _ => new HashSet< Utf8GamePath >() ).ToArray();
|
||||
|
||||
public FullPath? ResolvePath( Utf8GamePath path )
|
||||
=> _cache?.ResolvePath( path );
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Penumbra.Meta.Manipulations;
|
|||
using Penumbra.Mods;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.String.Classes;
|
||||
|
|
@ -104,6 +105,33 @@ public partial class ModCollection
|
|||
return iterator;
|
||||
}
|
||||
|
||||
// Reverse resolve multiple paths at once for efficiency.
|
||||
public HashSet< Utf8GamePath >[] ReverseResolvePaths( IReadOnlyCollection< string > fullPaths )
|
||||
{
|
||||
if( fullPaths.Count == 0 )
|
||||
return Array.Empty< HashSet< Utf8GamePath > >();
|
||||
|
||||
var ret = new HashSet< Utf8GamePath >[fullPaths.Count];
|
||||
var dict = new Dictionary< FullPath, int >( fullPaths.Count );
|
||||
foreach( var (path, idx) in fullPaths.WithIndex() )
|
||||
{
|
||||
dict[ new FullPath(path) ] = idx;
|
||||
ret[ idx ] = !Path.IsPathRooted( path ) && Utf8GamePath.FromString( path, out var utf8 )
|
||||
? new HashSet< Utf8GamePath > { utf8 }
|
||||
: new HashSet< Utf8GamePath >();
|
||||
}
|
||||
|
||||
foreach( var (game, full) in ResolvedFiles )
|
||||
{
|
||||
if( dict.TryGetValue( full.Path, out var idx ) )
|
||||
{
|
||||
ret[ idx ].Add( game );
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void OnModSettingChange( ModSettingChange type, int modIdx, int oldValue, int groupIdx, bool _ )
|
||||
{
|
||||
switch( type )
|
||||
|
|
@ -474,7 +502,7 @@ public partial class ModCollection
|
|||
// Skip IMCs because they would result in far too many false-positive items,
|
||||
// since they are per set instead of per item-slot/item/variant.
|
||||
var identifier = Penumbra.Identifier;
|
||||
var items = new SortedList< string, object? >(512);
|
||||
var items = new SortedList< string, object? >( 512 );
|
||||
|
||||
void AddItems( IMod mod )
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue