From 74ed6edd6fae4abb3027bf8fba553f4945d77474 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Mon, 21 Nov 2022 16:57:17 +0100 Subject: [PATCH] Update IPC to use better mechanisms for temporary collections without breaking backwards compatibility. --- Penumbra.Api | 2 +- Penumbra/Api/IpcTester.cs | 21 +++++++++ Penumbra/Api/PenumbraApi.cs | 68 +++++++++++++++++++++++---- Penumbra/Api/PenumbraIpcProviders.cs | 21 ++++++--- Penumbra/Api/TempModManager.cs | 9 +++- Penumbra/Collections/ModCollection.cs | 4 +- 6 files changed, 106 insertions(+), 19 deletions(-) diff --git a/Penumbra.Api b/Penumbra.Api index 27e8873e..15f782dd 160000 --- a/Penumbra.Api +++ b/Penumbra.Api @@ -1 +1 @@ -Subproject commit 27e8873e9f4633421e736757574b502a8d65e79d +Subproject commit 15f782dd7d3b823db5203769578b9edd7b92e309 diff --git a/Penumbra/Api/IpcTester.cs b/Penumbra/Api/IpcTester.cs index 6c48fd2a..ac532c1b 100644 --- a/Penumbra/Api/IpcTester.cs +++ b/Penumbra/Api/IpcTester.cs @@ -1087,6 +1087,7 @@ public class IpcTester : IDisposable private string _tempFilePath = "test/success.mtrl"; private string _tempManipulation = string.Empty; private PenumbraApiEc _lastTempError; + private int _tempActorIndex = 0; private bool _forceOverwrite; public void Draw() @@ -1099,6 +1100,7 @@ public class IpcTester : IDisposable ImGui.InputTextWithHint( "##tempCollection", "Collection Name...", ref _tempCollectionName, 128 ); ImGui.InputTextWithHint( "##tempCollectionChar", "Collection Character...", ref _tempCharacterName, 32 ); + ImGui.InputInt( "##tempActorIndex", ref _tempActorIndex, 0, 0 ); ImGui.InputTextWithHint( "##tempMod", "Temporary Mod Name...", ref _tempModName, 32 ); ImGui.InputTextWithHint( "##tempGame", "Game Path...", ref _tempGamePath, 256 ); ImGui.InputTextWithHint( "##tempFile", "File Path...", ref _tempFilePath, 256 ); @@ -1115,16 +1117,35 @@ public class IpcTester : IDisposable DrawIntro( "Last Error", _lastTempError.ToString() ); DrawIntro( "Last Created Collection", LastCreatedCollectionName ); DrawIntro( Ipc.CreateTemporaryCollection.Label, "Create Temporary Collection" ); +#pragma warning disable 0612 if( ImGui.Button( "Create##Collection" ) ) { ( _lastTempError, LastCreatedCollectionName ) = Ipc.CreateTemporaryCollection.Subscriber( _pi ).Invoke( _tempCollectionName, _tempCharacterName, _forceOverwrite ); } + DrawIntro( Ipc.CreateNamedTemporaryCollection.Label, "Create Named Temporary Collection" ); + if( ImGui.Button( "Create##NamedCollection" ) ) + { + _lastTempError = Ipc.CreateNamedTemporaryCollection.Subscriber( _pi ).Invoke( _tempCollectionName ); + } + DrawIntro( Ipc.RemoveTemporaryCollection.Label, "Remove Temporary Collection from Character" ); if( ImGui.Button( "Delete##Collection" ) ) { _lastTempError = Ipc.RemoveTemporaryCollection.Subscriber( _pi ).Invoke( _tempCharacterName ); } +#pragma warning restore 0612 + DrawIntro( Ipc.RemoveTemporaryCollectionByName.Label, "Remove Temporary Collection" ); + if( ImGui.Button( "Delete##NamedCollection" ) ) + { + _lastTempError = Ipc.RemoveTemporaryCollectionByName.Subscriber( _pi ).Invoke( _tempCollectionName ); + } + + DrawIntro( Ipc.AssignTemporaryCollection.Label, "Assign Temporary Collection" ); + if( ImGui.Button( "Assign##NamedCollection" ) ) + { + _lastTempError = Ipc.AssignTemporaryCollection.Subscriber( _pi ).Invoke( _tempCollectionName, _tempActorIndex, _forceOverwrite ); + } DrawIntro( Ipc.AddTemporaryMod.Label, "Add Temporary Mod to specific Collection" ); if( ImGui.Button( "Add##Mod" ) ) diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index 94e921de..7266c884 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -23,7 +23,7 @@ namespace Penumbra.Api; public class PenumbraApi : IDisposable, IPenumbraApi { public (int, int) ApiVersion - => ( 4, 15 ); + => ( 4, 16 ); private Penumbra? _penumbra; private Lumina.GameData? _lumina; @@ -575,10 +575,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi return collection.SetModSetting( mod.Index, groupIdx, setting ) ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged; } - public (PenumbraApiEc, string) CreateTemporaryCollection( string tag, string character, bool forceOverwriteCharacter ) - => CreateTemporaryCollection( tag, character, forceOverwriteCharacter, ushort.MaxValue ); - public (PenumbraApiEc, string) CreateTemporaryCollection( string tag, string character, bool forceOverwriteCharacter, ushort worldId ) + public (PenumbraApiEc, string) CreateTemporaryCollection( string tag, string character, bool forceOverwriteCharacter ) { CheckInitialized(); @@ -587,7 +585,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi return ( PenumbraApiEc.InvalidArgument, string.Empty ); } - var identifier = NameToIdentifier( character, worldId ); + var identifier = NameToIdentifier( character, ushort.MaxValue ); if( !identifier.IsValid ) { return ( PenumbraApiEc.InvalidArgument, string.Empty ); @@ -599,10 +597,11 @@ public class PenumbraApi : IDisposable, IPenumbraApi return ( PenumbraApiEc.CharacterCollectionExists, string.Empty ); } - var name = Penumbra.TempMods.CreateTemporaryCollection( tag, character ); - if( name.Length == 0 ) + var name = $"{tag}_{character}"; + var ret = CreateNamedTemporaryCollection( name ); + if( ret != PenumbraApiEc.Success ) { - return ( PenumbraApiEc.CharacterCollectionExists, string.Empty ); + return ( ret, name ); } if( Penumbra.TempMods.AddIdentifier( name, identifier ) ) @@ -614,6 +613,51 @@ public class PenumbraApi : IDisposable, IPenumbraApi return ( PenumbraApiEc.UnknownError, string.Empty ); } + public PenumbraApiEc CreateNamedTemporaryCollection( string name ) + { + CheckInitialized(); + if( name.Length == 0 || Mod.ReplaceBadXivSymbols( name ) != name ) + { + return PenumbraApiEc.InvalidArgument; + } + + return Penumbra.TempMods.CreateTemporaryCollection( name ).Length > 0 + ? PenumbraApiEc.Success + : PenumbraApiEc.CollectionExists; + } + + public PenumbraApiEc AssignTemporaryCollection( string collectionName, int actorIndex, bool forceAssignment ) + { + CheckInitialized(); + + if( actorIndex < 0 || actorIndex >= Dalamud.Objects.Length ) + { + return PenumbraApiEc.InvalidArgument; + } + + var identifier = Penumbra.Actors.FromObject( Dalamud.Objects[ actorIndex ] ); + if( !identifier.IsValid ) + { + return PenumbraApiEc.InvalidArgument; + } + + if( !Penumbra.TempMods.CollectionByName( collectionName, out var collection ) ) + { + return PenumbraApiEc.CollectionMissing; + } + + if( !forceAssignment + && ( Penumbra.TempMods.Collections.Individuals.ContainsKey( identifier ) || Penumbra.CollectionManager.Individuals.Individuals.ContainsKey( identifier ) ) ) + { + return PenumbraApiEc.CharacterCollectionExists; + } + + var group = Penumbra.TempMods.Collections.GetGroup( identifier ); + return Penumbra.TempMods.AddIdentifier( collection, group ) + ? PenumbraApiEc.Success + : PenumbraApiEc.UnknownError; + } + public PenumbraApiEc RemoveTemporaryCollection( string character ) { CheckInitialized(); @@ -622,6 +666,14 @@ public class PenumbraApi : IDisposable, IPenumbraApi : PenumbraApiEc.NothingChanged; } + public PenumbraApiEc RemoveTemporaryCollectionByName( string name ) + { + CheckInitialized(); + return Penumbra.TempMods.RemoveTemporaryCollection( name ) + ? PenumbraApiEc.Success + : PenumbraApiEc.NothingChanged; + } + public PenumbraApiEc AddTemporaryModAll( string tag, Dictionary< string, string > paths, string manipString, int priority ) { CheckInitialized(); diff --git a/Penumbra/Api/PenumbraIpcProviders.cs b/Penumbra/Api/PenumbraIpcProviders.cs index 0db02dbd..518d3638 100644 --- a/Penumbra/Api/PenumbraIpcProviders.cs +++ b/Penumbra/Api/PenumbraIpcProviders.cs @@ -89,6 +89,9 @@ public class PenumbraIpcProviders : IDisposable // Temporary internal readonly FuncProvider< string, string, bool, (PenumbraApiEc, string) > CreateTemporaryCollection; internal readonly FuncProvider< string, PenumbraApiEc > RemoveTemporaryCollection; + internal readonly FuncProvider< string, PenumbraApiEc > CreateNamedTemporaryCollection; + internal readonly FuncProvider< string, PenumbraApiEc > RemoveTemporaryCollectionByName; + internal readonly FuncProvider< string, int, bool, PenumbraApiEc > AssignTemporaryCollection; internal readonly FuncProvider< string, Dictionary< string, string >, string, int, PenumbraApiEc > AddTemporaryModAll; internal readonly FuncProvider< string, string, Dictionary< string, string >, string, int, PenumbraApiEc > AddTemporaryMod; internal readonly FuncProvider< string, int, PenumbraApiEc > RemoveTemporaryModAll; @@ -178,12 +181,15 @@ public class PenumbraIpcProviders : IDisposable () => Api.ModSettingChanged -= ModSettingChangedEvent ); // Temporary - CreateTemporaryCollection = Ipc.CreateTemporaryCollection.Provider( pi, Api.CreateTemporaryCollection ); - RemoveTemporaryCollection = Ipc.RemoveTemporaryCollection.Provider( pi, Api.RemoveTemporaryCollection ); - AddTemporaryModAll = Ipc.AddTemporaryModAll.Provider( pi, Api.AddTemporaryModAll ); - AddTemporaryMod = Ipc.AddTemporaryMod.Provider( pi, Api.AddTemporaryMod ); - RemoveTemporaryModAll = Ipc.RemoveTemporaryModAll.Provider( pi, Api.RemoveTemporaryModAll ); - RemoveTemporaryMod = Ipc.RemoveTemporaryMod.Provider( pi, Api.RemoveTemporaryMod ); + CreateTemporaryCollection = Ipc.CreateTemporaryCollection.Provider( pi, Api.CreateTemporaryCollection ); + RemoveTemporaryCollection = Ipc.RemoveTemporaryCollection.Provider( pi, Api.RemoveTemporaryCollection ); + CreateNamedTemporaryCollection = Ipc.CreateNamedTemporaryCollection.Provider( pi, Api.CreateNamedTemporaryCollection ); + RemoveTemporaryCollectionByName = Ipc.RemoveTemporaryCollectionByName.Provider( pi, Api.RemoveTemporaryCollectionByName ); + AssignTemporaryCollection = Ipc.AssignTemporaryCollection.Provider( pi, Api.AssignTemporaryCollection ); + AddTemporaryModAll = Ipc.AddTemporaryModAll.Provider( pi, Api.AddTemporaryModAll ); + AddTemporaryMod = Ipc.AddTemporaryMod.Provider( pi, Api.AddTemporaryMod ); + RemoveTemporaryModAll = Ipc.RemoveTemporaryModAll.Provider( pi, Api.RemoveTemporaryModAll ); + RemoveTemporaryMod = Ipc.RemoveTemporaryMod.Provider( pi, Api.RemoveTemporaryMod ); Tester = new IpcTester( pi, this ); @@ -267,6 +273,9 @@ public class PenumbraIpcProviders : IDisposable // Temporary CreateTemporaryCollection.Dispose(); RemoveTemporaryCollection.Dispose(); + CreateNamedTemporaryCollection.Dispose(); + RemoveTemporaryCollectionByName.Dispose(); + AssignTemporaryCollection.Dispose(); AddTemporaryModAll.Dispose(); AddTemporaryMod.Dispose(); RemoveTemporaryModAll.Dispose(); diff --git a/Penumbra/Api/TempModManager.cs b/Penumbra/Api/TempModManager.cs index 650b476e..511cb861 100644 --- a/Penumbra/Api/TempModManager.cs +++ b/Penumbra/Api/TempModManager.cs @@ -151,9 +151,14 @@ public class TempModManager return RedirectResult.Success; } - public string CreateTemporaryCollection( string tag, string customName ) + public string CreateTemporaryCollection( string name ) { - var collection = ModCollection.CreateNewTemporary( tag, customName ); + if( Penumbra.CollectionManager.ByName( name, out _ ) ) + { + return string.Empty; + } + + var collection = ModCollection.CreateNewTemporary( name ); if( _customCollections.TryAdd( collection.Name.ToLowerInvariant(), collection ) ) { return collection.Name; diff --git a/Penumbra/Collections/ModCollection.cs b/Penumbra/Collections/ModCollection.cs index e6a71fdf..0b165b1f 100644 --- a/Penumbra/Collections/ModCollection.cs +++ b/Penumbra/Collections/ModCollection.cs @@ -84,9 +84,9 @@ public partial class ModCollection => new(name, CurrentVersion, new Dictionary< string, ModSettings.SavedSettings >()); // Create a new temporary collection that does not save and has a negative index. - public static ModCollection CreateNewTemporary( string tag, string characterName ) + public static ModCollection CreateNewTemporary( string name ) { - var collection = new ModCollection( $"{tag}_{characterName}", Empty ); + var collection = new ModCollection( name, Empty ); collection.ModSettingChanged -= collection.SaveOnChange; collection.InheritanceChanged -= collection.SaveOnChange; collection.Index = ~Penumbra.TempMods.Collections.Count;