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 Penumbra.Api.Api;
using Penumbra.Api.Helpers;
using Penumbra.Communication;
using CharacterUtility = Penumbra.Interop.Services.CharacterUtility;
namespace Penumbra.Api;
@ -9,11 +11,13 @@ public sealed class IpcProviders : IDisposable, IApiService
{
private readonly List<IDisposable> _providers;
private readonly EventProvider _disposedProvider;
private readonly EventProvider _initializedProvider;
private readonly EventProvider _disposedProvider;
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);
_initializedProvider = IpcSubscribers.Initialized.Provider(pi);
_providers =
@ -115,11 +119,21 @@ public sealed class IpcProviders : IDisposable, IApiService
IpcSubscribers.OpenMainWindow.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();
_characterUtility.LoadingFinished.Unsubscribe(OnCharacterUtilityReady);
}
public void Dispose()
{
_characterUtility.LoadingFinished.Unsubscribe(OnCharacterUtilityReady);
foreach (var provider in _providers)
provider.Dispose();
_providers.Clear();

View file

@ -71,7 +71,7 @@ public class CollectionCacheManager : IDisposable, IService
_communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.CollectionCacheManager);
if (!MetaFileManager.CharacterUtility.Ready)
MetaFileManager.CharacterUtility.LoadingFinished += IncrementCounters;
MetaFileManager.CharacterUtility.LoadingFinished.Subscribe(IncrementCounters, CharacterUtilityFinished.Priority.CollectionCacheManager);
}
public void Dispose()
@ -83,7 +83,7 @@ public class CollectionCacheManager : IDisposable, IService
_communicator.ModOptionChanged.Unsubscribe(OnModOptionChange);
_communicator.ModSettingChanged.Unsubscribe(OnModSettingChange);
_communicator.CollectionInheritanceChanged.Unsubscribe(OnCollectionInheritanceChange);
MetaFileManager.CharacterUtility.LoadingFinished -= IncrementCounters;
MetaFileManager.CharacterUtility.LoadingFinished.Unsubscribe(IncrementCounters);
foreach (var collection in _storage)
{
@ -298,7 +298,7 @@ public class CollectionCacheManager : IDisposable, IService
{
foreach (var collection in _storage.Where(c => c.HasCache))
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 _)

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.Utility.Signatures;
using OtterGui.Services;
using Penumbra.Communication;
using Penumbra.GameData;
using Penumbra.Interop.Structs;
@ -26,14 +27,16 @@ public unsafe class CharacterUtility : IDisposable, IRequiredService
public CharacterUtilityData* Address
=> *_characterUtilityAddress;
public bool Ready { get; private set; }
public event Action LoadingFinished;
public nint DefaultHumanPbdResource { get; private set; }
public nint DefaultTransparentResource { get; private set; }
public nint DefaultDecalResource { get; private set; }
public nint DefaultSkinShpkResource { get; private set; }
public nint DefaultCharacterStockingsShpkResource { get; private set; }
public nint DefaultCharacterLegacyShpkResource { get; private set; }
public bool Ready { get; private set; }
public readonly CharacterUtilityFinished LoadingFinished = new();
public nint DefaultHumanPbdResource { get; private set; }
public nint DefaultTransparentResource { get; private set; }
public nint DefaultDecalResource { get; private set; }
public nint DefaultSkinShpkResource { get; private set; }
public nint DefaultCharacterStockingsShpkResource { get; private set; }
public nint DefaultCharacterLegacyShpkResource { get; private set; }
/// <summary>
/// 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)))
.ToArray();
_framework = framework;
LoadingFinished += () => Penumbra.Log.Debug("Loading of CharacterUtility finished.");
LoadingFinished.Subscribe(() => Penumbra.Log.Debug("Loading of CharacterUtility finished."), CharacterUtilityFinished.Priority.OnFinishedLoading);
LoadDefaultResources(null!);
if (!Ready)
_framework.Update += LoadDefaultResources;

View file

@ -70,6 +70,11 @@ public class ModMetaEditor(
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();
dict.ClearForDefault();