diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index 2d907faa..d88d069e 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -22,6 +22,7 @@ using Penumbra.String; using Penumbra.String.Classes; using Penumbra.Services; using Penumbra.Collections.Manager; +using Penumbra.Communication; using Penumbra.Interop.Services; using Penumbra.UI; @@ -34,13 +35,13 @@ public class PenumbraApi : IDisposable, IPenumbraApi public event Action? PreSettingsPanelDraw { - add => _communicator.PreSettingsPanelDraw.Subscribe(value!); + add => _communicator.PreSettingsPanelDraw.Subscribe(value!, Communication.PreSettingsPanelDraw.Priority.Default); remove => _communicator.PreSettingsPanelDraw.Unsubscribe(value!); } public event Action? PostSettingsPanelDraw { - add => _communicator.PostSettingsPanelDraw.Subscribe(value!); + add => _communicator.PostSettingsPanelDraw.Subscribe(value!, Communication.PostSettingsPanelDraw.Priority.Default); remove => _communicator.PostSettingsPanelDraw.Unsubscribe(value!); } @@ -68,7 +69,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi return; CheckInitialized(); - _communicator.CreatingCharacterBase.Subscribe(new Action(value)); + _communicator.CreatingCharacterBase.Subscribe(new Action(value), Communication.CreatingCharacterBase.Priority.Api); } remove { @@ -88,7 +89,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi return; CheckInitialized(); - _communicator.CreatedCharacterBase.Subscribe(new Action(value)); + _communicator.CreatedCharacterBase.Subscribe(new Action(value), Communication.CreatedCharacterBase.Priority.Api); } remove { @@ -147,8 +148,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi _lumina = _dalamud.GameData.GameData; _resourceLoader.ResourceLoaded += OnResourceLoaded; - _communicator.ModPathChanged.Subscribe(ModPathChangeSubscriber); - _communicator.ModSettingChanged.Subscribe(OnModSettingChange, -1000); + _communicator.ModPathChanged.Subscribe(ModPathChangeSubscriber, ModPathChanged.Priority.Api); + _communicator.ModSettingChanged.Subscribe(OnModSettingChange, Communication.ModSettingChanged.Priority.Api); } public unsafe void Dispose() @@ -180,7 +181,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi public event ChangedItemClick? ChangedItemClicked { - add => _communicator.ChangedItemClick.Subscribe(new Action(value!)); + add => _communicator.ChangedItemClick.Subscribe(new Action(value!), Communication.ChangedItemClick.Priority.Default); remove => _communicator.ChangedItemClick.Unsubscribe(new Action(value!)); } @@ -203,7 +204,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi add { CheckInitialized(); - _communicator.ModDirectoryChanged.Subscribe(value!); + _communicator.ModDirectoryChanged.Subscribe(value!, Communication.ModDirectoryChanged.Priority.Api); } remove { @@ -220,7 +221,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi add { CheckInitialized(); - _communicator.EnabledChanged.Subscribe(value!, int.MinValue); + _communicator.EnabledChanged.Subscribe(value!, EnabledChanged.Priority.Api); } remove { @@ -237,7 +238,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi public event ChangedItemHover? ChangedItemTooltip { - add => _communicator.ChangedItemHover.Subscribe(new Action(value!)); + add => _communicator.ChangedItemHover.Subscribe(new Action(value!), Communication.ChangedItemHover.Priority.Default); remove => _communicator.ChangedItemHover.Unsubscribe(new Action(value!)); } diff --git a/Penumbra/Api/TempModManager.cs b/Penumbra/Api/TempModManager.cs index c28a10f7..1dd8331f 100644 --- a/Penumbra/Api/TempModManager.cs +++ b/Penumbra/Api/TempModManager.cs @@ -5,8 +5,9 @@ using Penumbra.Mods; using System.Collections.Generic; using Penumbra.Services; using Penumbra.String.Classes; -using Penumbra.Collections.Manager; - +using Penumbra.Collections.Manager; +using Penumbra.Communication; + namespace Penumbra.Api; public enum RedirectResult @@ -27,7 +28,7 @@ public class TempModManager : IDisposable public TempModManager(CommunicatorService communicator) { _communicator = communicator; - _communicator.CollectionChange.Subscribe(OnCollectionChange); + _communicator.CollectionChange.Subscribe(OnCollectionChange, CollectionChange.Priority.TempModManager); } public void Dispose() diff --git a/Penumbra/Collections/Cache/CollectionCacheManager.cs b/Penumbra/Collections/Cache/CollectionCacheManager.cs index fc43f654..088c3a90 100644 --- a/Penumbra/Collections/Cache/CollectionCacheManager.cs +++ b/Penumbra/Collections/Cache/CollectionCacheManager.cs @@ -8,6 +8,7 @@ using OtterGui.Classes; using Penumbra.Api; using Penumbra.Api.Enums; using Penumbra.Collections.Manager; +using Penumbra.Communication; using Penumbra.Meta; using Penumbra.Mods; using Penumbra.Mods.Manager; @@ -44,15 +45,15 @@ public class CollectionCacheManager : IDisposable if (!_active.Individuals.IsLoaded) _active.Individuals.Loaded += CreateNecessaryCaches; - _communicator.CollectionChange.Subscribe(OnCollectionChange, -100); - _communicator.ModPathChanged.Subscribe(OnModChangeAddition, -100); - _communicator.ModPathChanged.Subscribe(OnModChangeRemoval, 100); - _communicator.TemporaryGlobalModChange.Subscribe(OnGlobalModChange); - _communicator.ModOptionChanged.Subscribe(OnModOptionChange, -100); - _communicator.ModSettingChanged.Subscribe(OnModSettingChange); - _communicator.CollectionInheritanceChanged.Subscribe(OnCollectionInheritanceChange); - _communicator.ModDiscoveryStarted.Subscribe(OnModDiscoveryStarted); - _communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, -100); + _communicator.CollectionChange.Subscribe(OnCollectionChange, CollectionChange.Priority.CollectionCacheManager); + _communicator.ModPathChanged.Subscribe(OnModChangeAddition, ModPathChanged.Priority.CollectionCacheManagerAddition); + _communicator.ModPathChanged.Subscribe(OnModChangeRemoval, ModPathChanged.Priority.CollectionCacheManagerRemoval); + _communicator.TemporaryGlobalModChange.Subscribe(OnGlobalModChange, TemporaryGlobalModChange.Priority.CollectionCacheManager); + _communicator.ModOptionChanged.Subscribe(OnModOptionChange, ModOptionChanged.Priority.CollectionCacheManager); + _communicator.ModSettingChanged.Subscribe(OnModSettingChange, ModSettingChanged.Priority.CollectionCacheManager); + _communicator.CollectionInheritanceChanged.Subscribe(OnCollectionInheritanceChange, CollectionInheritanceChanged.Priority.CollectionCacheManager); + _communicator.ModDiscoveryStarted.Subscribe(OnModDiscoveryStarted, ModDiscoveryStarted.Priority.CollectionCacheManager); + _communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.CollectionCacheManager); if (!MetaFileManager.CharacterUtility.Ready) MetaFileManager.CharacterUtility.LoadingFinished += IncrementCounters; diff --git a/Penumbra/Collections/Manager/ActiveCollections.cs b/Penumbra/Collections/Manager/ActiveCollections.cs index 1034227e..86d36abd 100644 --- a/Penumbra/Collections/Manager/ActiveCollections.cs +++ b/Penumbra/Collections/Manager/ActiveCollections.cs @@ -6,6 +6,7 @@ using Dalamud.Interface.Internal.Notifications; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using OtterGui; +using Penumbra.Communication; using Penumbra.GameData.Actors; using Penumbra.GameData.Enums; using Penumbra.Services; @@ -44,7 +45,7 @@ public class ActiveCollections : ISavable, IDisposable Default = storage.DefaultNamed; Interface = storage.DefaultNamed; Individuals = new IndividualCollections(actors, config, false); - _communicator.CollectionChange.Subscribe(OnCollectionChange, -100); + _communicator.CollectionChange.Subscribe(OnCollectionChange, CollectionChange.Priority.ActiveCollections); LoadCollections(); UpdateCurrentCollectionInUse(); Individuals.Loaded += UpdateCurrentCollectionInUse; diff --git a/Penumbra/Collections/Manager/CollectionStorage.cs b/Penumbra/Collections/Manager/CollectionStorage.cs index d065bbcf..4980ea71 100644 --- a/Penumbra/Collections/Manager/CollectionStorage.cs +++ b/Penumbra/Collections/Manager/CollectionStorage.cs @@ -7,6 +7,7 @@ using System.Linq; using Dalamud.Interface.Internal.Notifications; using OtterGui; using OtterGui.Filesystem; +using Penumbra.Communication; using Penumbra.Mods; using Penumbra.Mods.Manager; using Penumbra.Services; @@ -56,10 +57,10 @@ public class CollectionStorage : IReadOnlyList, IDisposable _communicator = communicator; _saveService = saveService; _modStorage = modStorage; - _communicator.ModDiscoveryStarted.Subscribe(OnModDiscoveryStarted); - _communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished); - _communicator.ModPathChanged.Subscribe(OnModPathChange, 10); - _communicator.ModOptionChanged.Subscribe(OnModOptionChange, 100); + _communicator.ModDiscoveryStarted.Subscribe(OnModDiscoveryStarted, ModDiscoveryStarted.Priority.CollectionStorage); + _communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.CollectionStorage); + _communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.CollectionStorage); + _communicator.ModOptionChanged.Subscribe(OnModOptionChange, ModOptionChanged.Priority.CollectionStorage); ReadCollections(out DefaultNamed); } diff --git a/Penumbra/Collections/Manager/InheritanceManager.cs b/Penumbra/Collections/Manager/InheritanceManager.cs index 1378ae56..93dee89f 100644 --- a/Penumbra/Collections/Manager/InheritanceManager.cs +++ b/Penumbra/Collections/Manager/InheritanceManager.cs @@ -4,6 +4,7 @@ using System.Linq; using Dalamud.Interface.Internal.Notifications; using OtterGui; using OtterGui.Filesystem; +using Penumbra.Communication; using Penumbra.Mods.Manager; using Penumbra.Services; using Penumbra.Util; @@ -47,7 +48,7 @@ public class InheritanceManager : IDisposable _modStorage = modStorage; ApplyInheritances(); - _communicator.CollectionChange.Subscribe(OnCollectionChange); + _communicator.CollectionChange.Subscribe(OnCollectionChange, CollectionChange.Priority.InheritanceManager); } public void Dispose() diff --git a/Penumbra/Collections/Manager/TempCollectionManager.cs b/Penumbra/Collections/Manager/TempCollectionManager.cs index 7f1f03b8..400bd2cf 100644 --- a/Penumbra/Collections/Manager/TempCollectionManager.cs +++ b/Penumbra/Collections/Manager/TempCollectionManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using Penumbra.Api; +using Penumbra.Communication; using Penumbra.GameData.Actors; using Penumbra.Mods; using Penumbra.Services; @@ -27,7 +28,7 @@ public class TempCollectionManager : IDisposable _storage = storage; Collections = new IndividualCollections(actors, config, true); - _communicator.TemporaryGlobalModChange.Subscribe(OnGlobalModChange); + _communicator.TemporaryGlobalModChange.Subscribe(OnGlobalModChange, TemporaryGlobalModChange.Priority.TempCollectionManager); } public void Dispose() diff --git a/Penumbra/Communication/ChangedItemClick.cs b/Penumbra/Communication/ChangedItemClick.cs new file mode 100644 index 00000000..fd879280 --- /dev/null +++ b/Penumbra/Communication/ChangedItemClick.cs @@ -0,0 +1,28 @@ +using System; +using Penumbra.Api.Enums; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered when a Changed Item in Penumbra is clicked. +/// +/// Parameter is the clicked mouse button. +/// Parameter is the clicked object data if any.. +/// +/// +public sealed class ChangedItemClick : EventWrapper, ChangedItemClick.Priority> +{ + public enum Priority + { + /// + Default = 0, + } + + public ChangedItemClick() + : base(nameof(ChangedItemClick)) + { } + + public void Invoke(MouseButton button, object? data) + => Invoke(this, button, data); +} diff --git a/Penumbra/Communication/ChangedItemHover.cs b/Penumbra/Communication/ChangedItemHover.cs new file mode 100644 index 00000000..9a658769 --- /dev/null +++ b/Penumbra/Communication/ChangedItemHover.cs @@ -0,0 +1,29 @@ +using System; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered when a Changed Item in Penumbra is hovered. +/// +/// Parameter is the hovered object data if any. +/// +/// +public sealed class ChangedItemHover : EventWrapper, ChangedItemHover.Priority> +{ + public enum Priority + { + /// + Default = 0, + } + + public ChangedItemHover() + : base(nameof(ChangedItemHover)) + { } + + public void Invoke(object? data) + => Invoke(this, data); + + public bool HasTooltip + => HasSubscribers; +} diff --git a/Penumbra/Communication/CollectionChange.cs b/Penumbra/Communication/CollectionChange.cs new file mode 100644 index 00000000..c5a0b93f --- /dev/null +++ b/Penumbra/Communication/CollectionChange.cs @@ -0,0 +1,54 @@ +using System; +using Penumbra.Collections; +using Penumbra.Collections.Manager; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered whenever collection setup is changed. +/// +/// Parameter is the type of the changed collection. (Inactive or Temporary for additions or deletions) +/// Parameter is the old collection, or null on additions. +/// Parameter is the new collection, or null on deletions. +/// Parameter is the display name for Individual collections or an empty string otherwise. +/// +public sealed class CollectionChange : EventWrapper, CollectionChange.Priority> +{ + public enum Priority + { + /// + CollectionCacheManager = -2, + + /// + ActiveCollections = -1, + + /// + TempModManager = 0, + + /// + InheritanceManager = 0, + + /// + IdentifiedCollectionCache = 0, + + /// + ItemSwapTab = 0, + + /// + CollectionSelector = 0, + + /// + IndividualAssignmentUi = 0, + + /// + ModFileSystemSelector = 0, + } + + public CollectionChange() + : base(nameof(CollectionChange)) + { } + + public void Invoke(CollectionType collectionType, ModCollection? oldCollection, ModCollection? newCollection, string displayName) + => Invoke(this, collectionType, oldCollection, newCollection, displayName); +} diff --git a/Penumbra/Communication/CollectionInheritanceChanged.cs b/Penumbra/Communication/CollectionInheritanceChanged.cs new file mode 100644 index 00000000..3562f457 --- /dev/null +++ b/Penumbra/Communication/CollectionInheritanceChanged.cs @@ -0,0 +1,34 @@ +using System; +using Penumbra.Collections; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered whenever a collections inheritances change. +/// +/// Parameter is the collection whose ancestors were changed. +/// Parameter is whether the change was itself inherited, i.e. if it happened in a direct parent (false) or a more removed ancestor (true). +/// +/// +public sealed class CollectionInheritanceChanged : EventWrapper, CollectionInheritanceChanged.Priority> +{ + public enum Priority + { + /// + CollectionCacheManager = 0, + + /// + ItemSwapTab = 0, + + /// + ModFileSystemSelector = 0, + } + + public CollectionInheritanceChanged() + : base(nameof(CollectionInheritanceChanged)) + { } + + public void Invoke(ModCollection collection, bool inherited) + => Invoke(this, collection, inherited); +} diff --git a/Penumbra/Communication/CreatedCharacterBase.cs b/Penumbra/Communication/CreatedCharacterBase.cs new file mode 100644 index 00000000..dacd51dd --- /dev/null +++ b/Penumbra/Communication/CreatedCharacterBase.cs @@ -0,0 +1,25 @@ +using System; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Parameter is the game object for which a draw object is created. +/// Parameter is the name of the applied collection. +/// Parameter is the created draw object. +/// +public sealed class CreatedCharacterBase : EventWrapper, CreatedCharacterBase.Priority> +{ + public enum Priority + { + /// + Api = 0, + } + + public CreatedCharacterBase() + : base(nameof(CreatedCharacterBase)) + { } + + public void Invoke(nint gameObject, string appliedCollectionName, nint drawObject) + => Invoke(this, gameObject, appliedCollectionName, drawObject); +} diff --git a/Penumbra/Communication/CreatingCharacterBase.cs b/Penumbra/Communication/CreatingCharacterBase.cs new file mode 100644 index 00000000..357bc066 --- /dev/null +++ b/Penumbra/Communication/CreatingCharacterBase.cs @@ -0,0 +1,29 @@ +using System; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered whenever a character base draw object is being created by the game. +/// +/// Parameter is the game object for which a draw object is created. +/// Parameter is the name of the applied collection. +/// Parameter is a pointer to the model id (an uint). +/// Parameter is a pointer to the customize array. +/// Parameter is a pointer to the equip data array. +/// +public sealed class CreatingCharacterBase : EventWrapper, CreatingCharacterBase.Priority> +{ + public enum Priority + { + /// + Api = 0, + } + + public CreatingCharacterBase() + : base(nameof(CreatingCharacterBase)) + { } + + public void Invoke(nint gameObject, string appliedCollectionName, nint modelIdAddress, nint customizeArrayAddress, nint equipDataAddress) + => Invoke(this, gameObject, appliedCollectionName, modelIdAddress, customizeArrayAddress, equipDataAddress); +} diff --git a/Penumbra/Communication/EnabledChanged.cs b/Penumbra/Communication/EnabledChanged.cs new file mode 100644 index 00000000..ec63337f --- /dev/null +++ b/Penumbra/Communication/EnabledChanged.cs @@ -0,0 +1,26 @@ +using System; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered when the general Enabled state of Penumbra is changed. +/// +/// Parameter is whether Penumbra is now Enabled (true) or Disabled (false). +/// +/// +public sealed class EnabledChanged : EventWrapper, EnabledChanged.Priority> +{ + public enum Priority + { + /// + Api = int.MinValue, + } + + public EnabledChanged() + : base(nameof(EnabledChanged)) + { } + + public void Invoke(bool enabled) + => Invoke(this, enabled); +} diff --git a/Penumbra/Communication/ModDataChanged.cs b/Penumbra/Communication/ModDataChanged.cs new file mode 100644 index 00000000..8f16dcfe --- /dev/null +++ b/Penumbra/Communication/ModDataChanged.cs @@ -0,0 +1,35 @@ +using System; +using Penumbra.Mods; +using Penumbra.Mods.Manager; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered whenever mod meta data or local data is changed. +/// +/// Parameter is the type of data change for the mod, which can be multiple flags. +/// Parameter is the changed mod. +/// Parameter is the old name of the mod in case of a name change, and null otherwise. +/// +public sealed class ModDataChanged : EventWrapper, ModDataChanged.Priority> +{ + public enum Priority + { + /// + ModFileSystemSelector = -10, + + /// + ModCacheManager = 0, + + /// + ModFileSystem = 0, + } + + public ModDataChanged() + : base(nameof(ModDataChanged)) + { } + + public void Invoke(ModDataChangeType changeType, Mod mod, string? oldName) + => Invoke(this, changeType, mod, oldName); +} diff --git a/Penumbra/Communication/ModDirectoryChanged.cs b/Penumbra/Communication/ModDirectoryChanged.cs new file mode 100644 index 00000000..102ddec4 --- /dev/null +++ b/Penumbra/Communication/ModDirectoryChanged.cs @@ -0,0 +1,30 @@ +using System; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered whenever the mod root directory changes. +/// +/// Parameter is the full path of the new directory. +/// Parameter is whether the new directory is valid. +/// +/// +public sealed class ModDirectoryChanged : EventWrapper, ModDirectoryChanged.Priority> +{ + public enum Priority + { + /// + Api = 0, + + /// + FileDialogService = 0, + } + + public ModDirectoryChanged() + : base(nameof(ModDirectoryChanged)) + { } + + public void Invoke(string newModDirectory, bool newDirectoryValid) + => Invoke(this, newModDirectory, newDirectoryValid); +} diff --git a/Penumbra/Communication/ModDiscoveryFinished.cs b/Penumbra/Communication/ModDiscoveryFinished.cs new file mode 100644 index 00000000..1471d7d7 --- /dev/null +++ b/Penumbra/Communication/ModDiscoveryFinished.cs @@ -0,0 +1,33 @@ +using System; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// Triggered whenever a new mod discovery has finished. +public sealed class ModDiscoveryFinished : EventWrapper +{ + public enum Priority + { + /// + ModFileSystemSelector = -200, + + /// + CollectionCacheManager = -100, + + /// + CollectionStorage = 0, + + /// + ModCacheManager = 0, + + /// + ModFileSystem = 0, + } + + public ModDiscoveryFinished() + : base(nameof(ModDiscoveryFinished)) + { } + + public void Invoke() + => Invoke(this); +} diff --git a/Penumbra/Communication/ModDiscoveryStarted.cs b/Penumbra/Communication/ModDiscoveryStarted.cs new file mode 100644 index 00000000..4e98a3e0 --- /dev/null +++ b/Penumbra/Communication/ModDiscoveryStarted.cs @@ -0,0 +1,26 @@ +using System; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// Triggered whenever mods are prepared to be rediscovered. +public sealed class ModDiscoveryStarted : EventWrapper +{ + public enum Priority + { + /// + CollectionCacheManager = 0, + + /// + CollectionStorage = 0, + + /// + ModFileSystemSelector = 200, + } + public ModDiscoveryStarted() + : base(nameof(ModDiscoveryStarted)) + { } + + public void Invoke() + => Invoke(this); +} diff --git a/Penumbra/Communication/ModOptionChanged.cs b/Penumbra/Communication/ModOptionChanged.cs new file mode 100644 index 00000000..cacc7a89 --- /dev/null +++ b/Penumbra/Communication/ModOptionChanged.cs @@ -0,0 +1,40 @@ +using System; +using Penumbra.Mods; +using Penumbra.Mods.Manager; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered whenever an option of a mod is changed inside the mod. +/// +/// Parameter is the type option change. +/// Parameter is the changed mod. +/// Parameter is the index of the changed group inside the mod. +/// Parameter is the index of the changed option inside the group or -1 if it does not concern a specific option. +/// Parameter is the index of the group an option was moved to. +/// +public sealed class ModOptionChanged : EventWrapper, ModOptionChanged.Priority> +{ + public enum Priority + { + /// + CollectionCacheManager = -100, + + /// + ModCacheManager = 0, + + /// + ItemSwapTab = 0, + + /// + CollectionStorage = 100, + } + + public ModOptionChanged() + : base(nameof(ModOptionChanged)) + { } + + public void Invoke(ModOptionChangeType changeType, Mod mod, int groupIndex, int optionIndex, int moveToIndex) + => Invoke(this, changeType, mod, groupIndex, optionIndex, moveToIndex); +} diff --git a/Penumbra/Communication/ModPathChanged.cs b/Penumbra/Communication/ModPathChanged.cs new file mode 100644 index 00000000..608c10eb --- /dev/null +++ b/Penumbra/Communication/ModPathChanged.cs @@ -0,0 +1,54 @@ +using System; +using System.IO; +using Penumbra.Mods; +using Penumbra.Mods.Manager; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered whenever a mod is added, deleted, moved or reloaded. +/// +/// Parameter is the type of change. +/// Parameter is the changed mod. +/// Parameter is the old directory on deletion, move or reload and null on addition. +/// Parameter is the new directory on addition, move or reload and null on deletion. +/// +/// +public sealed class ModPathChanged : EventWrapper, ModPathChanged.Priority> +{ + public enum Priority + { + /// + CollectionCacheManagerAddition = -100, + + /// + Api = 0, + + /// + ModCacheManager = 0, + + /// + ModExportManager = 0, + + /// + ModFileSystem = 0, + + /// + ModManager = 0, + + /// + CollectionStorage = 10, + + /// + CollectionCacheManagerRemoval = 100, + + + } + public ModPathChanged() + : base(nameof(ModPathChanged)) + { } + + public void Invoke(ModPathChangeType changeType, Mod mod, DirectoryInfo? oldModDirectory, DirectoryInfo? newModDirectory) + => Invoke(this, changeType, mod, oldModDirectory, newModDirectory); +} diff --git a/Penumbra/Communication/ModSettingChanged.cs b/Penumbra/Communication/ModSettingChanged.cs new file mode 100644 index 00000000..e32a84c2 --- /dev/null +++ b/Penumbra/Communication/ModSettingChanged.cs @@ -0,0 +1,43 @@ +using System; +using Penumbra.Api.Enums; +using Penumbra.Collections; +using Penumbra.Mods; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered whenever a mod setting is changed. +/// +/// Parameter is the collection in which the setting was changed. +/// Parameter is the type of change. +/// Parameter is the mod the setting was changed for, unless it was a multi-change. +/// Parameter is the old value of the setting before the change as int. +/// Parameter is the index of the changed group if the change type is Setting. +/// Parameter is whether the change was inherited from another collection. +/// +/// +public sealed class ModSettingChanged : EventWrapper, ModSettingChanged.Priority> +{ + public enum Priority + { + /// + Api = int.MinValue, + + /// + CollectionCacheManager = 0, + + /// + ItemSwapTab = 0, + + /// + ModFileSystemSelector = 0, + } + + public ModSettingChanged() + : base(nameof(ModSettingChanged)) + { } + + public void Invoke(ModCollection collection, ModSettingChange type, Mod? mod, int oldValue, int groupIdx, bool inherited) + => Invoke(this, collection, type, mod, oldValue, groupIdx, inherited); +} diff --git a/Penumbra/Communication/PostSettingsPanelDraw.cs b/Penumbra/Communication/PostSettingsPanelDraw.cs new file mode 100644 index 00000000..e460e369 --- /dev/null +++ b/Penumbra/Communication/PostSettingsPanelDraw.cs @@ -0,0 +1,26 @@ +using System; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered after the settings panel is drawn. +/// +/// Parameter is the identifier (directory name) of the currently selected mod. +/// +/// +public sealed class PostSettingsPanelDraw : EventWrapper, PostSettingsPanelDraw.Priority> +{ + public enum Priority + { + /// + Default = 0, + } + + public PostSettingsPanelDraw() + : base(nameof(PostSettingsPanelDraw)) + { } + + public void Invoke(string modDirectory) + => Invoke(this, modDirectory); +} diff --git a/Penumbra/Communication/PreSettingsPanelDraw.cs b/Penumbra/Communication/PreSettingsPanelDraw.cs new file mode 100644 index 00000000..c3e182b0 --- /dev/null +++ b/Penumbra/Communication/PreSettingsPanelDraw.cs @@ -0,0 +1,26 @@ +using System; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered before the settings panel is drawn. +/// +/// Parameter is the identifier (directory name) of the currently selected mod. +/// +/// +public sealed class PreSettingsPanelDraw : EventWrapper, PreSettingsPanelDraw.Priority> +{ + public enum Priority + { + /// + Default = 0, + } + + public PreSettingsPanelDraw() + : base(nameof(PreSettingsPanelDraw)) + { } + + public void Invoke(string modDirectory) + => Invoke(this, modDirectory); +} diff --git a/Penumbra/Communication/TemporaryGlobalModChange.cs b/Penumbra/Communication/TemporaryGlobalModChange.cs new file mode 100644 index 00000000..1f0352a2 --- /dev/null +++ b/Penumbra/Communication/TemporaryGlobalModChange.cs @@ -0,0 +1,31 @@ +using System; +using Penumbra.Mods; +using Penumbra.Util; + +namespace Penumbra.Communication; + +/// +/// Triggered whenever a temporary mod for all collections is changed. +/// +/// Parameter added, deleted or edited temporary mod. +/// Parameter is whether the mod was newly created. +/// Parameter is whether the mod was deleted. +/// +public sealed class TemporaryGlobalModChange : EventWrapper, TemporaryGlobalModChange.Priority> +{ + public enum Priority + { + /// + CollectionCacheManager = 0, + + /// + TempCollectionManager = 0, + } + + public TemporaryGlobalModChange() + : base(nameof(TemporaryGlobalModChange)) + { } + + public void Invoke(TemporaryMod temporaryMod, bool newlyCreated, bool deleted) + => Invoke(this, temporaryMod, newlyCreated, deleted); +} diff --git a/Penumbra/Interop/PathResolving/IdentifiedCollectionCache.cs b/Penumbra/Interop/PathResolving/IdentifiedCollectionCache.cs index 58ae0d92..67ab584e 100644 --- a/Penumbra/Interop/PathResolving/IdentifiedCollectionCache.cs +++ b/Penumbra/Interop/PathResolving/IdentifiedCollectionCache.cs @@ -5,7 +5,8 @@ using Dalamud.Game.ClientState; using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Object; using Penumbra.Collections; -using Penumbra.Collections.Manager; +using Penumbra.Collections.Manager; +using Penumbra.Communication; using Penumbra.GameData.Actors; using Penumbra.Interop.Services; using Penumbra.Services; @@ -26,7 +27,7 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(nint A _communicator = communicator; _events = events; - _communicator.CollectionChange.Subscribe(CollectionChangeClear); + _communicator.CollectionChange.Subscribe(CollectionChangeClear, CollectionChange.Priority.IdentifiedCollectionCache); _clientState.TerritoryChanged += TerritoryClear; _events.CharacterDestructor += OnCharacterDestruct; } diff --git a/Penumbra/Mods/Manager/ModCacheManager.cs b/Penumbra/Mods/Manager/ModCacheManager.cs index 1015e4ed..1ace9536 100644 --- a/Penumbra/Mods/Manager/ModCacheManager.cs +++ b/Penumbra/Mods/Manager/ModCacheManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using Penumbra.Communication; using Penumbra.GameData; using Penumbra.GameData.Data; using Penumbra.GameData.Enums; @@ -23,10 +24,10 @@ public class ModCacheManager : IDisposable _identifier = identifier; _modManager = modStorage; - _communicator.ModOptionChanged.Subscribe(OnModOptionChange); - _communicator.ModPathChanged.Subscribe(OnModPathChange); - _communicator.ModDataChanged.Subscribe(OnModDataChange); - _communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished); + _communicator.ModOptionChanged.Subscribe(OnModOptionChange, ModOptionChanged.Priority.ModCacheManager); + _communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModCacheManager); + _communicator.ModDataChanged.Subscribe(OnModDataChange, ModDataChanged.Priority.ModCacheManager); + _communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.ModCacheManager); if (!identifier.Valid) identifier.FinishedCreation += OnIdentifierCreation; OnModDiscoveryFinished(); diff --git a/Penumbra/Mods/Manager/ModExportManager.cs b/Penumbra/Mods/Manager/ModExportManager.cs index 6396e1f9..6bb919fc 100644 --- a/Penumbra/Mods/Manager/ModExportManager.cs +++ b/Penumbra/Mods/Manager/ModExportManager.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Penumbra.Communication; using Penumbra.Services; namespace Penumbra.Mods.Manager; @@ -21,7 +22,7 @@ public class ModExportManager : IDisposable _communicator = communicator; _modManager = modManager; UpdateExportDirectory(_config.ExportDirectory, false); - _communicator.ModPathChanged.Subscribe(OnModPathChange); + _communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModExportManager); } /// diff --git a/Penumbra/Mods/Manager/ModFileSystem.cs b/Penumbra/Mods/Manager/ModFileSystem.cs index 76f4e1d6..62daa9fb 100644 --- a/Penumbra/Mods/Manager/ModFileSystem.cs +++ b/Penumbra/Mods/Manager/ModFileSystem.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; using OtterGui.Filesystem; +using Penumbra.Communication; using Penumbra.Mods.Manager; using Penumbra.Services; using Penumbra.Util; @@ -25,9 +26,9 @@ public sealed class ModFileSystem : FileSystem, IDisposable, ISavable _saveService = saveService; Reload(); Changed += OnChange; - _communicator.ModDiscoveryFinished.Subscribe(Reload); - _communicator.ModDataChanged.Subscribe(OnDataChange); - _communicator.ModPathChanged.Subscribe(OnModPathChange); + _communicator.ModDiscoveryFinished.Subscribe(Reload, ModDiscoveryFinished.Priority.ModFileSystem); + _communicator.ModDataChanged.Subscribe(OnDataChange, ModDataChanged.Priority.ModFileSystem); + _communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModFileSystem); } public void Dispose() diff --git a/Penumbra/Mods/Manager/ModManager.cs b/Penumbra/Mods/Manager/ModManager.cs index 8b25f763..7e7599f0 100644 --- a/Penumbra/Mods/Manager/ModManager.cs +++ b/Penumbra/Mods/Manager/ModManager.cs @@ -3,6 +3,7 @@ using System.Collections.Concurrent; using System.IO; using System.Linq; using System.Threading.Tasks; +using Penumbra.Communication; using Penumbra.Services; namespace Penumbra.Mods.Manager; @@ -50,7 +51,7 @@ public sealed class ModManager : ModStorage, IDisposable OptionEditor = optionEditor; Creator = creator; SetBaseDirectory(config.ModDirectory, true); - _communicator.ModPathChanged.Subscribe(OnModPathChange); + _communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModManager); DiscoverMods(); } diff --git a/Penumbra/Services/CommunicatorService.cs b/Penumbra/Services/CommunicatorService.cs index a45548c7..371722b2 100644 --- a/Penumbra/Services/CommunicatorService.cs +++ b/Penumbra/Services/CommunicatorService.cs @@ -1,350 +1,59 @@ using System; -using System.IO; -using Penumbra.Api.Enums; -using Penumbra.Collections; -using Penumbra.Collections.Manager; -using Penumbra.Mods; -using Penumbra.Mods.Manager; -using Penumbra.Util; +using Penumbra.Communication; namespace Penumbra.Services; -/// -/// Triggered whenever collection setup is changed. -/// -/// Parameter is the type of the changed collection. (Inactive or Temporary for additions or deletions) -/// Parameter is the old collection, or null on additions. -/// Parameter is the new collection, or null on deletions. -/// Parameter is the display name for Individual collections or an empty string otherwise. -/// -public sealed class CollectionChange : EventWrapper> -{ - public CollectionChange() - : base(nameof(CollectionChange)) - { } - - public void Invoke(CollectionType collectionType, ModCollection? oldCollection, ModCollection? newCollection, string displayName) - => Invoke(this, collectionType, oldCollection, newCollection, displayName); -} - -/// -/// Triggered whenever a temporary mod for all collections is changed. -/// -/// Parameter added, deleted or edited temporary mod. -/// Parameter is whether the mod was newly created. -/// Parameter is whether the mod was deleted. -/// -public sealed class TemporaryGlobalModChange : EventWrapper> -{ - public TemporaryGlobalModChange() - : base(nameof(TemporaryGlobalModChange)) - { } - - public void Invoke(TemporaryMod temporaryMod, bool newlyCreated, bool deleted) - => Invoke(this, temporaryMod, newlyCreated, deleted); -} - -/// -/// Triggered whenever a character base draw object is being created by the game. -/// -/// Parameter is the game object for which a draw object is created. -/// Parameter is the name of the applied collection. -/// Parameter is a pointer to the model id (an uint). -/// Parameter is a pointer to the customize array. -/// Parameter is a pointer to the equip data array. -/// -public sealed class CreatingCharacterBase : EventWrapper> -{ - public CreatingCharacterBase() - : base(nameof(CreatingCharacterBase)) - { } - - public void Invoke(nint gameObject, string appliedCollectionName, nint modelIdAddress, nint customizeArrayAddress, nint equipDataAddress) - => Invoke(this, gameObject, appliedCollectionName, modelIdAddress, customizeArrayAddress, equipDataAddress); -} - -/// -/// Parameter is the game object for which a draw object is created. -/// Parameter is the name of the applied collection. -/// Parameter is the created draw object. -/// -public sealed class CreatedCharacterBase : EventWrapper> -{ - public CreatedCharacterBase() - : base(nameof(CreatedCharacterBase)) - { } - - public void Invoke(nint gameObject, string appliedCollectionName, nint drawObject) - => Invoke(this, gameObject, appliedCollectionName, drawObject); -} - -/// -/// Triggered whenever mod meta data or local data is changed. -/// -/// Parameter is the type of data change for the mod, which can be multiple flags. -/// Parameter is the changed mod. -/// Parameter is the old name of the mod in case of a name change, and null otherwise. -/// -public sealed class ModDataChanged : EventWrapper> -{ - public ModDataChanged() - : base(nameof(ModDataChanged)) - { } - - public void Invoke(ModDataChangeType changeType, Mod mod, string? oldName) - => Invoke(this, changeType, mod, oldName); -} - -/// -/// Triggered whenever an option of a mod is changed inside the mod. -/// -/// Parameter is the type option change. -/// Parameter is the changed mod. -/// Parameter is the index of the changed group inside the mod. -/// Parameter is the index of the changed option inside the group or -1 if it does not concern a specific option. -/// Parameter is the index of the group an option was moved to. -/// -public sealed class ModOptionChanged : EventWrapper> -{ - public ModOptionChanged() - : base(nameof(ModOptionChanged)) - { } - - public void Invoke(ModOptionChangeType changeType, Mod mod, int groupIndex, int optionIndex, int moveToIndex) - => Invoke(this, changeType, mod, groupIndex, optionIndex, moveToIndex); -} - -/// Triggered whenever mods are prepared to be rediscovered. -public sealed class ModDiscoveryStarted : EventWrapper -{ - public ModDiscoveryStarted() - : base(nameof(ModDiscoveryStarted)) - { } - - public void Invoke() - => EventWrapper.Invoke(this); -} - -/// Triggered whenever a new mod discovery has finished. -public sealed class ModDiscoveryFinished : EventWrapper -{ - public ModDiscoveryFinished() - : base(nameof(ModDiscoveryFinished)) - { } - - public void Invoke() - => Invoke(this); -} - -/// -/// Triggered whenever the mod root directory changes. -/// -/// Parameter is the full path of the new directory. -/// Parameter is whether the new directory is valid. -/// -/// -public sealed class ModDirectoryChanged : EventWrapper> -{ - public ModDirectoryChanged() - : base(nameof(ModDirectoryChanged)) - { } - - public void Invoke(string newModDirectory, bool newDirectoryValid) - => Invoke(this, newModDirectory, newDirectoryValid); -} - -/// -/// Triggered whenever a mod is added, deleted, moved or reloaded. -/// -/// Parameter is the type of change. -/// Parameter is the changed mod. -/// Parameter is the old directory on deletion, move or reload and null on addition. -/// Parameter is the new directory on addition, move or reload and null on deletion. -/// -/// -public sealed class ModPathChanged : EventWrapper> -{ - public ModPathChanged() - : base(nameof(ModPathChanged)) - { } - - public void Invoke(ModPathChangeType changeType, Mod mod, DirectoryInfo? oldModDirectory, DirectoryInfo? newModDirectory) - => Invoke(this, changeType, mod, oldModDirectory, newModDirectory); -} - -/// -/// Triggered whenever a mod setting is changed. -/// -/// Parameter is the collection in which the setting was changed. -/// Parameter is the type of change. -/// Parameter is the mod the setting was changed for, unless it was a multi-change. -/// Parameter is the old value of the setting before the change as int. -/// Parameter is the index of the changed group if the change type is Setting. -/// Parameter is whether the change was inherited from another collection. -/// -/// -public sealed class ModSettingChanged : EventWrapper> -{ - public ModSettingChanged() - : base(nameof(ModSettingChanged)) - { } - - public void Invoke(ModCollection collection, ModSettingChange type, Mod? mod, int oldValue, int groupIdx, bool inherited) - => Invoke(this, collection, type, mod, oldValue, groupIdx, inherited); -} - -/// -/// Triggered whenever a collections inheritances change. -/// -/// Parameter is the collection whose ancestors were changed. -/// Parameter is whether the change was itself inherited, i.e. if it happened in a direct parent (false) or a more removed ancestor (true). -/// -/// -public sealed class CollectionInheritanceChanged : EventWrapper> -{ - public CollectionInheritanceChanged() - : base(nameof(CollectionInheritanceChanged)) - { } - - public void Invoke(ModCollection collection, bool inherited) - => Invoke(this, collection, inherited); -} - -/// -/// Triggered when the general Enabled state of Penumbra is changed. -/// -/// Parameter is whether Penumbra is now Enabled (true) or Disabled (false). -/// -/// -public sealed class EnabledChanged : EventWrapper> -{ - public EnabledChanged() - : base(nameof(EnabledChanged)) - { } - - public void Invoke(bool enabled) - => Invoke(this, enabled); -} - -/// -/// Triggered before the settings panel is drawn. -/// -/// Parameter is the identifier (directory name) of the currently selected mod. -/// -/// -public sealed class PreSettingsPanelDraw : EventWrapper> -{ - public PreSettingsPanelDraw() - : base(nameof(PreSettingsPanelDraw)) - { } - - public void Invoke(string modDirectory) - => Invoke(this, modDirectory); -} - -/// -/// Triggered after the settings panel is drawn. -/// -/// Parameter is the identifier (directory name) of the currently selected mod. -/// -/// -public sealed class PostSettingsPanelDraw : EventWrapper> -{ - public PostSettingsPanelDraw() - : base(nameof(PostSettingsPanelDraw)) - { } - - public void Invoke(string modDirectory) - => Invoke(this, modDirectory); -} - -/// -/// Triggered when a Changed Item in Penumbra is hovered. -/// -/// Parameter is the hovered object data if any. -/// -/// -public sealed class ChangedItemHover : EventWrapper> -{ - public ChangedItemHover() - : base(nameof(ChangedItemHover)) - { } - - public void Invoke(object? data) - => Invoke(this, data); - - public bool HasTooltip - => HasSubscribers; -} - -/// -/// Triggered when a Changed Item in Penumbra is clicked. -/// -/// Parameter is the clicked mouse button. -/// Parameter is the clicked object data if any.. -/// -/// -public sealed class ChangedItemClick : EventWrapper> -{ - public ChangedItemClick() - : base(nameof(ChangedItemClick)) - { } - - public void Invoke(MouseButton button, object? data) - => Invoke(this, button, data); -} - public class CommunicatorService : IDisposable { - /// + /// public readonly CollectionChange CollectionChange = new(); - /// + /// public readonly TemporaryGlobalModChange TemporaryGlobalModChange = new(); - /// + /// public readonly CreatingCharacterBase CreatingCharacterBase = new(); - /// + /// public readonly CreatedCharacterBase CreatedCharacterBase = new(); - /// + /// public readonly ModDataChanged ModDataChanged = new(); - /// + /// public readonly ModOptionChanged ModOptionChanged = new(); - /// + /// public readonly ModDiscoveryStarted ModDiscoveryStarted = new(); - /// + /// public readonly ModDiscoveryFinished ModDiscoveryFinished = new(); - /// + /// public readonly ModDirectoryChanged ModDirectoryChanged = new(); - /// + /// public readonly ModPathChanged ModPathChanged = new(); - /// + /// public readonly ModSettingChanged ModSettingChanged = new(); - /// + /// public readonly CollectionInheritanceChanged CollectionInheritanceChanged = new(); - /// + /// public readonly EnabledChanged EnabledChanged = new(); - /// + /// public readonly PreSettingsPanelDraw PreSettingsPanelDraw = new(); - /// + /// public readonly PostSettingsPanelDraw PostSettingsPanelDraw = new(); - /// + /// public readonly ChangedItemHover ChangedItemHover = new(); - /// + /// public readonly ChangedItemClick ChangedItemClick = new(); public void Dispose() diff --git a/Penumbra/UI/AdvancedWindow/ItemSwapTab.cs b/Penumbra/UI/AdvancedWindow/ItemSwapTab.cs index 22bca756..4903158d 100644 --- a/Penumbra/UI/AdvancedWindow/ItemSwapTab.cs +++ b/Penumbra/UI/AdvancedWindow/ItemSwapTab.cs @@ -13,6 +13,7 @@ using OtterGui.Widgets; using Penumbra.Api.Enums; using Penumbra.Collections; using Penumbra.Collections.Manager; +using Penumbra.Communication; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; using Penumbra.Meta; @@ -57,10 +58,10 @@ public class ItemSwapTab : IDisposable, ITab // @formatter:on }; - _communicator.CollectionChange.Subscribe(OnCollectionChange); - _communicator.ModSettingChanged.Subscribe(OnSettingChange); - _communicator.CollectionInheritanceChanged.Subscribe(OnInheritanceChange); - _communicator.ModOptionChanged.Subscribe(OnModOptionChange); + _communicator.CollectionChange.Subscribe(OnCollectionChange, CollectionChange.Priority.ItemSwapTab); + _communicator.ModSettingChanged.Subscribe(OnSettingChange, ModSettingChanged.Priority.ItemSwapTab); + _communicator.CollectionInheritanceChanged.Subscribe(OnInheritanceChange, CollectionInheritanceChanged.Priority.ItemSwapTab); + _communicator.ModOptionChanged.Subscribe(OnModOptionChange, ModOptionChanged.Priority.ItemSwapTab); } /// Update the currently selected mod or its settings. diff --git a/Penumbra/UI/CollectionTab/CollectionSelector.cs b/Penumbra/UI/CollectionTab/CollectionSelector.cs index 14611d59..746c2d5f 100644 --- a/Penumbra/UI/CollectionTab/CollectionSelector.cs +++ b/Penumbra/UI/CollectionTab/CollectionSelector.cs @@ -6,6 +6,7 @@ using OtterGui; using OtterGui.Raii; using Penumbra.Collections; using Penumbra.Collections.Manager; +using Penumbra.Communication; using Penumbra.GameData.Actors; using Penumbra.Services; using Penumbra.UI.Classes; @@ -34,7 +35,7 @@ public sealed class CollectionSelector : ItemSelector, IDisposabl _active = active; _tutorial = tutorial; - _communicator.CollectionChange.Subscribe(OnCollectionChange); + _communicator.CollectionChange.Subscribe(OnCollectionChange, CollectionChange.Priority.CollectionSelector); // Set items. OnCollectionChange(CollectionType.Inactive, null, null, string.Empty); // Set selection. diff --git a/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs b/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs index 98fcc0d6..81e0a862 100644 --- a/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs +++ b/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs @@ -5,6 +5,7 @@ using ImGuiNET; using OtterGui.Raii; using Penumbra.Collections; using Penumbra.Collections.Manager; +using Penumbra.Communication; using Penumbra.GameData.Actors; using Penumbra.Services; @@ -30,7 +31,7 @@ public class IndividualAssignmentUi : IDisposable _communicator = communicator; _actorService = actors; _collectionManager = collectionManager; - _communicator.CollectionChange.Subscribe(UpdateIdentifiers); + _communicator.CollectionChange.Subscribe(UpdateIdentifiers, CollectionChange.Priority.IndividualAssignmentUi); if (_actorService.Valid) SetupCombos(); else @@ -57,7 +58,7 @@ public class IndividualAssignmentUi : IDisposable public void DrawWorldCombo(float width) { if (_ready && _worldCombo.Draw(width)) - UpdateIdentifiers(); + UpdateIdentifiersInternal(); } public void DrawObjectKindCombo(float width) @@ -76,7 +77,7 @@ public class IndividualAssignmentUi : IDisposable continue; _newKind = kind; - UpdateIdentifiers(); + UpdateIdentifiersInternal(); } } @@ -87,7 +88,7 @@ public class IndividualAssignmentUi : IDisposable ImGui.SetNextItemWidth(width); if (ImGui.InputTextWithHint("##NewCharacter", "Character Name...", ref _newCharacterName, 32)) - UpdateIdentifiers(); + UpdateIdentifiersInternal(); } public void DrawNewNpcCollection(float width) @@ -97,7 +98,7 @@ public class IndividualAssignmentUi : IDisposable var combo = GetNpcCombo(_newKind); if (combo.Draw(width)) - UpdateIdentifiers(); + UpdateIdentifiersInternal(); } public void Dispose() @@ -154,10 +155,10 @@ public class IndividualAssignmentUi : IDisposable private void UpdateIdentifiers(CollectionType type, ModCollection? _1, ModCollection? _2, string _3) { if (type == CollectionType.Individual) - UpdateIdentifiers(); + UpdateIdentifiersInternal(); } - private void UpdateIdentifiers() + private void UpdateIdentifiersInternal() { var combo = GetNpcCombo(_newKind); PlayerTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Player, _newCharacterName, diff --git a/Penumbra/UI/FileDialogService.cs b/Penumbra/UI/FileDialogService.cs index b1956796..c483c3b1 100644 --- a/Penumbra/UI/FileDialogService.cs +++ b/Penumbra/UI/FileDialogService.cs @@ -9,6 +9,7 @@ using Dalamud.Interface.ImGuiFileDialog; using Dalamud.Utility; using ImGuiNET; using OtterGui; +using Penumbra.Communication; using Penumbra.Services; namespace Penumbra.UI; @@ -22,9 +23,9 @@ public class FileDialogService : IDisposable public FileDialogService(CommunicatorService communicator, Configuration config) { - _communicator = communicator; - _manager = SetupFileManager(config.ModDirectory); - _communicator.ModDirectoryChanged.Subscribe(OnModDirectoryChange); + _communicator = communicator; + _manager = SetupFileManager(config.ModDirectory); + _communicator.ModDirectoryChanged.Subscribe(OnModDirectoryChange, ModDirectoryChanged.Priority.FileDialogService); } public void OpenFilePicker(string title, string filters, Action> callback, int selectionCountMax, string? startPath, diff --git a/Penumbra/UI/ModsTab/ModFileSystemSelector.cs b/Penumbra/UI/ModsTab/ModFileSystemSelector.cs index 758b6aad..5a53712d 100644 --- a/Penumbra/UI/ModsTab/ModFileSystemSelector.cs +++ b/Penumbra/UI/ModsTab/ModFileSystemSelector.cs @@ -14,6 +14,7 @@ using OtterGui.Raii; using Penumbra.Api.Enums; using Penumbra.Collections; using Penumbra.Collections.Manager; +using Penumbra.Communication; using Penumbra.Mods; using Penumbra.Mods.Manager; using Penumbra.Services; @@ -72,12 +73,12 @@ public sealed class ModFileSystemSelector : FileSystemSelector : IDisposable where T : Delegate +public abstract class EventWrapper : IDisposable + where T : Delegate + where TPriority : struct, Enum { - private readonly string _name; - private readonly List<(object Subscriber, int Priority)> _event = new(); + private readonly string _name; + private readonly List<(object Subscriber, TPriority Priority)> _event = new(); public bool HasSubscribers => _event.Count > 0; @@ -23,12 +25,12 @@ public abstract class EventWrapper : IDisposable where T : Delegate } } - public void Subscribe(T subscriber, int priority = 0) + public void Subscribe(T subscriber, TPriority priority) { lock (_event) { - var existingIdx = _event.FindIndex(p => (T) p.Subscriber == subscriber); - var idx = _event.FindIndex(p => p.Priority > priority); + var existingIdx = _event.FindIndex(p => (T)p.Subscriber == subscriber); + var idx = _event.FindIndex(p => p.Priority.CompareTo(priority) > 0); if (idx == existingIdx) { if (idx < 0) @@ -53,14 +55,14 @@ public abstract class EventWrapper : IDisposable where T : Delegate { lock (_event) { - var idx = _event.FindIndex(p => (T) p.Subscriber == subscriber); + var idx = _event.FindIndex(p => (T)p.Subscriber == subscriber); if (idx >= 0) _event.RemoveAt(idx); } } - protected static void Invoke(EventWrapper wrapper) + protected static void Invoke(EventWrapper wrapper) { lock (wrapper._event) { @@ -78,7 +80,7 @@ public abstract class EventWrapper : IDisposable where T : Delegate } } - protected static void Invoke(EventWrapper wrapper, T1 a) + protected static void Invoke(EventWrapper wrapper, T1 a) { lock (wrapper._event) { @@ -96,7 +98,7 @@ public abstract class EventWrapper : IDisposable where T : Delegate } } - protected static void Invoke(EventWrapper wrapper, T1 a, T2 b) + protected static void Invoke(EventWrapper wrapper, T1 a, T2 b) { lock (wrapper._event) { @@ -114,7 +116,7 @@ public abstract class EventWrapper : IDisposable where T : Delegate } } - protected static void Invoke(EventWrapper wrapper, T1 a, T2 b, T3 c) + protected static void Invoke(EventWrapper wrapper, T1 a, T2 b, T3 c) { lock (wrapper._event) { @@ -132,7 +134,7 @@ public abstract class EventWrapper : IDisposable where T : Delegate } } - protected static void Invoke(EventWrapper wrapper, T1 a, T2 b, T3 c, T4 d) + protected static void Invoke(EventWrapper wrapper, T1 a, T2 b, T3 c, T4 d) { lock (wrapper._event) { @@ -150,7 +152,7 @@ public abstract class EventWrapper : IDisposable where T : Delegate } } - protected static void Invoke(EventWrapper wrapper, T1 a, T2 b, T3 c, T4 d, T5 e) + protected static void Invoke(EventWrapper wrapper, T1 a, T2 b, T3 c, T4 d, T5 e) { lock (wrapper._event) { @@ -168,7 +170,7 @@ public abstract class EventWrapper : IDisposable where T : Delegate } } - protected static void Invoke(EventWrapper wrapper, T1 a, T2 b, T3 c, T4 d, T5 e, T6 f) + protected static void Invoke(EventWrapper wrapper, T1 a, T2 b, T3 c, T4 d, T5 e, T6 f) { lock (wrapper._event) {