Add API/IPC for collection handling.

This commit is contained in:
Ottermandias 2023-01-16 17:42:26 +01:00
parent 123ed256b1
commit 80f02e5377
6 changed files with 284 additions and 87 deletions

View file

@ -9,8 +9,10 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Numerics;
using Dalamud.Utility;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
using Penumbra.Collections;
using Penumbra.String;
using Penumbra.String.Classes;
using Penumbra.Meta.Manipulations;
@ -683,10 +685,18 @@ 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 ApiCollectionType _type = ApiCollectionType.Current;
private string _characterCollectionName = string.Empty;
private IList< string > _collections = new List< string >();
private string _changedItemCollection = string.Empty;
private IReadOnlyDictionary< string, object? > _changedItems = new Dictionary< string, object? >();
private PenumbraApiEc _returnCode = PenumbraApiEc.Success;
private string? _oldCollection = null;
public Collections( DalamudPluginInterface pi )
=> _pi = pi;
@ -699,12 +709,25 @@ public class IpcTester : IDisposable
return;
}
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 );
ImGui.SameLine();
ImGui.Checkbox( "Allow Assignment Deletion", ref _allowDeletion );
using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
if( !table )
{
return;
}
DrawIntro( "Last Return Code", _returnCode.ToString() );
if( _oldCollection != null )
{
ImGui.TextUnformatted( _oldCollection.Length == 0 ? "Created" : _oldCollection );
}
DrawIntro( Ipc.GetCurrentCollectionName.Label, "Current Collection" );
ImGui.TextUnformatted( Ipc.GetCurrentCollectionName.Subscriber( _pi ).Invoke() );
DrawIntro( Ipc.GetDefaultCollectionName.Label, "Default Collection" );
@ -725,6 +748,27 @@ public class IpcTester : IDisposable
ImGui.OpenPopup( "Collections" );
}
DrawIntro( Ipc.GetCollectionForType.Label, "Get Special Collection" );
var name = Ipc.GetCollectionForType.Subscriber( _pi ).Invoke( _type );
ImGui.TextUnformatted( name.Length == 0 ? "Unassigned" : name );
DrawIntro( Ipc.SetCollectionForType.Label, "Set Special Collection" );
if( ImGui.Button( "Set##TypeCollection" ) )
{
( _returnCode, _oldCollection ) = Ipc.SetCollectionForType.Subscriber( _pi ).Invoke( _type, _collectionName, _allowCreation, _allowDeletion );
}
DrawIntro( Ipc.GetCollectionForObject.Label, "Get Object Collection" );
( var valid, var individual, name ) = Ipc.GetCollectionForObject.Subscriber( _pi ).Invoke( _objectIdx );
ImGui.TextUnformatted(
$"{( valid ? "Valid" : "Invalid" )} Object, {( name.Length == 0 ? "Unassigned" : name )}{( individual ? " (Individual Assignment)" : string.Empty )}" );
DrawIntro( Ipc.SetCollectionForObject.Label, "Set Object Collection" );
if( ImGui.Button( "Set##ObjectCollection" ) )
{
( _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 );
ImGui.InputTextWithHint( "##changedCollection", "Collection Name...", ref _changedItemCollection, 64 );
@ -1089,6 +1133,7 @@ public class IpcTester : IDisposable
{
_lastSettingsError = Ipc.CopyModSettings.Subscriber( _pi ).Invoke( _settingsCollection, _settingsModDirectory, _settingsModName );
}
ImGuiUtil.HoverTooltip( "Copy settings from Mod Directory Name to Mod Name (as directory) in collection." );
DrawIntro( Ipc.TrySetModSetting.Label, "Set Setting(s)" );

View file

@ -23,7 +23,7 @@ namespace Penumbra.Api;
public class PenumbraApi : IDisposable, IPenumbraApi
{
public (int, int) ApiVersion
=> ( 4, 17 );
=> ( 4, 18 );
private Penumbra? _penumbra;
private Lumina.GameData? _lumina;
@ -302,6 +302,132 @@ public class PenumbraApi : IDisposable, IPenumbraApi
}
}
public string GetCollectionForType( Enums.ApiCollectionType type )
{
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 )
{
CheckInitialized();
if( !Enum.IsDefined( type ) )
return ( PenumbraApiEc.InvalidArgument, string.Empty );
var oldCollection = Penumbra.CollectionManager.ByType( ( CollectionType )type )?.Name ?? string.Empty;
if( collectionName.Length == 0 )
{
if( oldCollection.Length == 0 )
{
return ( PenumbraApiEc.NothingChanged, oldCollection );
}
if( !allowDelete || type is Enums.ApiCollectionType.Current or Enums.ApiCollectionType.Default or Enums.ApiCollectionType.Interface )
{
return ( PenumbraApiEc.AssignmentDeletionDisallowed, oldCollection );
}
Penumbra.CollectionManager.RemoveSpecialCollection( (CollectionType) type );
return ( PenumbraApiEc.Success, oldCollection );
}
if( !Penumbra.CollectionManager.ByName( collectionName, out var collection ) )
{
return (PenumbraApiEc.CollectionMissing, oldCollection);
}
if( oldCollection.Length == 0 )
{
if( !allowCreateNew )
{
return ( PenumbraApiEc.AssignmentCreationDisallowed, oldCollection );
}
Penumbra.CollectionManager.CreateSpecialCollection( ( CollectionType )type );
}
else if( oldCollection == collection.Name )
{
return ( PenumbraApiEc.NothingChanged, oldCollection );
}
Penumbra.CollectionManager.SetCollection( collection, (CollectionType) type );
return ( PenumbraApiEc.Success, oldCollection );
}
public (bool ObjectValid, bool IndividualSet, string EffectiveCollection) GetCollectionForObject( int gameObjectIdx )
{
CheckInitialized();
var id = AssociatedIdentifier( gameObjectIdx );
if( !id.IsValid )
{
return ( false, false, Penumbra.CollectionManager.Default.Name );
}
if( Penumbra.CollectionManager.Individuals.Individuals.TryGetValue( id, out var collection ) )
{
return ( true, true, collection.Name );
}
AssociatedCollection( gameObjectIdx, out collection );
return ( true, false, collection.Name );
}
public (PenumbraApiEc, string OldCollection) SetCollectionForObject( int gameObjectIdx, string collectionName, bool allowCreateNew, bool allowDelete )
{
CheckInitialized();
var id = AssociatedIdentifier( gameObjectIdx );
if( !id.IsValid )
{
return ( PenumbraApiEc.InvalidIdentifier, Penumbra.CollectionManager.Default.Name );
}
var oldCollection = Penumbra.CollectionManager.Individuals.Individuals.TryGetValue( id, out var c ) ? c.Name : string.Empty;
if( collectionName.Length == 0 )
{
if( oldCollection.Length == 0 )
{
return (PenumbraApiEc.NothingChanged, oldCollection);
}
if( !allowDelete )
{
return (PenumbraApiEc.AssignmentDeletionDisallowed, oldCollection);
}
var idx = Penumbra.CollectionManager.Individuals.Index( id );
Penumbra.CollectionManager.RemoveIndividualCollection(idx );
return (PenumbraApiEc.Success, oldCollection);
}
if( !Penumbra.CollectionManager.ByName( collectionName, out var collection ) )
{
return (PenumbraApiEc.CollectionMissing, oldCollection);
}
if( oldCollection.Length == 0 )
{
if( !allowCreateNew )
{
return (PenumbraApiEc.AssignmentCreationDisallowed, oldCollection);
}
var ids = Penumbra.CollectionManager.Individuals.GetGroup( id );
Penumbra.CollectionManager.CreateIndividualCollection( ids );
}
else if( oldCollection == collection.Name )
{
return (PenumbraApiEc.NothingChanged, oldCollection);
}
Penumbra.CollectionManager.SetCollection( collection, CollectionType.Individual, Penumbra.CollectionManager.Individuals.Index( id ) );
return (PenumbraApiEc.Success, oldCollection);
}
public IList< string > GetCollections()
{
CheckInitialized();
@ -867,7 +993,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.
private unsafe bool AssociatedCollection( int gameObjectIdx, out ModCollection collection )
private static unsafe bool AssociatedCollection( int gameObjectIdx, out ModCollection collection )
{
collection = Penumbra.CollectionManager.Default;
if( gameObjectIdx < 0 || gameObjectIdx >= Dalamud.Objects.Length )
@ -885,6 +1011,16 @@ public class PenumbraApi : IDisposable, IPenumbraApi
return true;
}
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.
private static string ResolvePath( string path, Mod.Manager _, ModCollection collection )
{

View file

@ -59,12 +59,16 @@ public class PenumbraIpcProviders : IDisposable
internal readonly FuncProvider< string, string[] > ReverseResolvePlayerPath;
// 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< string, IReadOnlyDictionary< string, object? > > GetChangedItems;
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;
// Meta
internal readonly FuncProvider< string > GetPlayerMetaManipulations;
@ -163,6 +167,10 @@ public class PenumbraIpcProviders : IDisposable
GetDefaultCollectionName = Ipc.GetDefaultCollectionName.Provider( pi, Api.GetDefaultCollection );
GetInterfaceCollectionName = Ipc.GetInterfaceCollectionName.Provider( pi, Api.GetInterfaceCollection );
GetCharacterCollectionName = Ipc.GetCharacterCollectionName.Provider( pi, Api.GetCharacterCollection );
GetCollectionForType = Ipc.GetCollectionForType.Provider( pi, Api.GetCollectionForType );
SetCollectionForType = Ipc.SetCollectionForType.Provider( pi, Api.SetCollectionForType );
GetCollectionForObject = Ipc.GetCollectionForObject.Provider( pi, Api.GetCollectionForObject );
SetCollectionForObject = Ipc.SetCollectionForObject.Provider( pi, Api.SetCollectionForObject );
GetChangedItems = Ipc.GetChangedItems.Provider( pi, Api.GetChangedItemsForCollection );
// Meta
@ -189,7 +197,7 @@ public class PenumbraIpcProviders : IDisposable
TrySetModPriority = Ipc.TrySetModPriority.Provider( pi, Api.TrySetModPriority );
TrySetModSetting = Ipc.TrySetModSetting.Provider( pi, Api.TrySetModSetting );
TrySetModSettings = Ipc.TrySetModSettings.Provider( pi, Api.TrySetModSettings );
ModSettingChanged = Ipc.ModSettingChanged.Provider( pi,
ModSettingChanged = Ipc.ModSettingChanged.Provider( pi,
() => Api.ModSettingChanged += ModSettingChangedEvent,
() => Api.ModSettingChanged -= ModSettingChangedEvent );
CopyModSettings = Ipc.CopyModSettings.Provider( pi, Api.CopyModSettings );
@ -262,6 +270,10 @@ public class PenumbraIpcProviders : IDisposable
GetDefaultCollectionName.Dispose();
GetInterfaceCollectionName.Dispose();
GetCharacterCollectionName.Dispose();
GetCollectionForType.Dispose();
SetCollectionForType.Dispose();
GetCollectionForObject.Dispose();
SetCollectionForObject.Dispose();
GetChangedItems.Dispose();
// Meta