Fix issue with IPC adding mods before character utility is ready in rare cases.

This commit is contained in:
Ottermandias 2025-01-22 23:14:09 +01:00
parent dcab443b2f
commit 40168d7daf
5 changed files with 60 additions and 15 deletions

View file

@ -2,6 +2,8 @@ using Dalamud.Plugin;
using OtterGui.Services; using OtterGui.Services;
using Penumbra.Api.Api; using Penumbra.Api.Api;
using Penumbra.Api.Helpers; using Penumbra.Api.Helpers;
using Penumbra.Communication;
using CharacterUtility = Penumbra.Interop.Services.CharacterUtility;
namespace Penumbra.Api; namespace Penumbra.Api;
@ -9,11 +11,13 @@ public sealed class IpcProviders : IDisposable, IApiService
{ {
private readonly List<IDisposable> _providers; private readonly List<IDisposable> _providers;
private readonly EventProvider _disposedProvider; private readonly EventProvider _disposedProvider;
private readonly EventProvider _initializedProvider; private readonly EventProvider _initializedProvider;
private readonly CharacterUtility _characterUtility;
public IpcProviders(IDalamudPluginInterface pi, IPenumbraApi api) public IpcProviders(IDalamudPluginInterface pi, IPenumbraApi api, CharacterUtility characterUtility)
{ {
_characterUtility = characterUtility;
_disposedProvider = IpcSubscribers.Disposed.Provider(pi); _disposedProvider = IpcSubscribers.Disposed.Provider(pi);
_initializedProvider = IpcSubscribers.Initialized.Provider(pi); _initializedProvider = IpcSubscribers.Initialized.Provider(pi);
_providers = _providers =
@ -115,11 +119,21 @@ public sealed class IpcProviders : IDisposable, IApiService
IpcSubscribers.OpenMainWindow.Provider(pi, api.Ui), IpcSubscribers.OpenMainWindow.Provider(pi, api.Ui),
IpcSubscribers.CloseMainWindow.Provider(pi, api.Ui), IpcSubscribers.CloseMainWindow.Provider(pi, api.Ui),
]; ];
if (_characterUtility.Ready)
_initializedProvider.Invoke();
else
_characterUtility.LoadingFinished.Subscribe(OnCharacterUtilityReady, CharacterUtilityFinished.Priority.IpcProvider);
}
private void OnCharacterUtilityReady()
{
_initializedProvider.Invoke(); _initializedProvider.Invoke();
_characterUtility.LoadingFinished.Unsubscribe(OnCharacterUtilityReady);
} }
public void Dispose() public void Dispose()
{ {
_characterUtility.LoadingFinished.Unsubscribe(OnCharacterUtilityReady);
foreach (var provider in _providers) foreach (var provider in _providers)
provider.Dispose(); provider.Dispose();
_providers.Clear(); _providers.Clear();

View file

@ -71,7 +71,7 @@ public class CollectionCacheManager : IDisposable, IService
_communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.CollectionCacheManager); _communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.CollectionCacheManager);
if (!MetaFileManager.CharacterUtility.Ready) if (!MetaFileManager.CharacterUtility.Ready)
MetaFileManager.CharacterUtility.LoadingFinished += IncrementCounters; MetaFileManager.CharacterUtility.LoadingFinished.Subscribe(IncrementCounters, CharacterUtilityFinished.Priority.CollectionCacheManager);
} }
public void Dispose() public void Dispose()
@ -83,7 +83,7 @@ public class CollectionCacheManager : IDisposable, IService
_communicator.ModOptionChanged.Unsubscribe(OnModOptionChange); _communicator.ModOptionChanged.Unsubscribe(OnModOptionChange);
_communicator.ModSettingChanged.Unsubscribe(OnModSettingChange); _communicator.ModSettingChanged.Unsubscribe(OnModSettingChange);
_communicator.CollectionInheritanceChanged.Unsubscribe(OnCollectionInheritanceChange); _communicator.CollectionInheritanceChanged.Unsubscribe(OnCollectionInheritanceChange);
MetaFileManager.CharacterUtility.LoadingFinished -= IncrementCounters; MetaFileManager.CharacterUtility.LoadingFinished.Unsubscribe(IncrementCounters);
foreach (var collection in _storage) foreach (var collection in _storage)
{ {
@ -298,7 +298,7 @@ public class CollectionCacheManager : IDisposable, IService
{ {
foreach (var collection in _storage.Where(c => c.HasCache)) foreach (var collection in _storage.Where(c => c.HasCache))
collection.Counters.IncrementChange(); collection.Counters.IncrementChange();
MetaFileManager.CharacterUtility.LoadingFinished -= IncrementCounters; MetaFileManager.CharacterUtility.LoadingFinished.Unsubscribe(IncrementCounters);
} }
private void OnModSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, Setting oldValue, int groupIdx, bool _) private void OnModSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, Setting oldValue, int groupIdx, bool _)

View file

@ -0,0 +1,23 @@
using OtterGui.Classes;
using Penumbra.Api;
using Penumbra.Interop.Services;
namespace Penumbra.Communication;
/// <summary>
/// Triggered when the Character Utility becomes ready.
/// </summary>
public sealed class CharacterUtilityFinished() : EventWrapper<CharacterUtilityFinished.Priority>(nameof(CharacterUtilityFinished))
{
public enum Priority
{
/// <seealso cref="CharacterUtility"/>
OnFinishedLoading = int.MaxValue,
/// <seealso cref="IpcProviders.OnCharacterUtilityReady"/>
IpcProvider = int.MinValue,
/// <seealso cref="Collections.Cache.CollectionCacheManager"/>
CollectionCacheManager = 0,
}
}

View file

@ -1,6 +1,7 @@
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures; using Dalamud.Utility.Signatures;
using OtterGui.Services; using OtterGui.Services;
using Penumbra.Communication;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.Interop.Structs; using Penumbra.Interop.Structs;
@ -26,14 +27,16 @@ public unsafe class CharacterUtility : IDisposable, IRequiredService
public CharacterUtilityData* Address public CharacterUtilityData* Address
=> *_characterUtilityAddress; => *_characterUtilityAddress;
public bool Ready { get; private set; } public bool Ready { get; private set; }
public event Action LoadingFinished;
public nint DefaultHumanPbdResource { get; private set; } public readonly CharacterUtilityFinished LoadingFinished = new();
public nint DefaultTransparentResource { get; private set; }
public nint DefaultDecalResource { get; private set; } public nint DefaultHumanPbdResource { get; private set; }
public nint DefaultSkinShpkResource { get; private set; } public nint DefaultTransparentResource { get; private set; }
public nint DefaultCharacterStockingsShpkResource { get; private set; } public nint DefaultDecalResource { get; private set; }
public nint DefaultCharacterLegacyShpkResource { get; private set; } public nint DefaultSkinShpkResource { get; private set; }
public nint DefaultCharacterStockingsShpkResource { get; private set; }
public nint DefaultCharacterLegacyShpkResource { get; private set; }
/// <summary> /// <summary>
/// The relevant indices depend on which meta manipulations we allow for. /// The relevant indices depend on which meta manipulations we allow for.
@ -61,7 +64,7 @@ public unsafe class CharacterUtility : IDisposable, IRequiredService
.Select(idx => new MetaList(new InternalIndex(idx))) .Select(idx => new MetaList(new InternalIndex(idx)))
.ToArray(); .ToArray();
_framework = framework; _framework = framework;
LoadingFinished += () => Penumbra.Log.Debug("Loading of CharacterUtility finished."); LoadingFinished.Subscribe(() => Penumbra.Log.Debug("Loading of CharacterUtility finished."), CharacterUtilityFinished.Priority.OnFinishedLoading);
LoadDefaultResources(null!); LoadDefaultResources(null!);
if (!Ready) if (!Ready)
_framework.Update += LoadDefaultResources; _framework.Update += LoadDefaultResources;

View file

@ -70,6 +70,11 @@ public class ModMetaEditor(
public static bool DeleteDefaultValues(MetaFileManager metaFileManager, MetaDictionary dict) public static bool DeleteDefaultValues(MetaFileManager metaFileManager, MetaDictionary dict)
{ {
if (!metaFileManager.CharacterUtility.Ready)
{
Penumbra.Log.Warning("Trying to delete default meta values before CharacterUtility was ready, skipped.");
return false;
}
var clone = dict.Clone(); var clone = dict.Clone();
dict.ClearForDefault(); dict.ClearForDefault();