qstbak/Questionable/Questionable.Controller.GameUi/CreditsController.cs
2025-10-09 07:53:51 +10:00

187 lines
5.7 KiB
C#

using System;
using Dalamud.Game.Addon.Lifecycle;
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Component.GUI;
using Microsoft.Extensions.Logging;
namespace Questionable.Controller.GameUi;
internal sealed class CreditsController : IDisposable
{
private static CreditsController? _instance;
private static IAddonLifecycle? _registeredLifecycle;
private static readonly IAddonLifecycle.AddonEventDelegate _creditScrollHandler = delegate(AddonEvent t, AddonArgs a)
{
_instance?.CreditScrollPostSetup(t, a);
};
private static readonly IAddonLifecycle.AddonEventDelegate _creditHandler = delegate(AddonEvent t, AddonArgs a)
{
_instance?.CreditPostSetup(t, a);
};
private static readonly IAddonLifecycle.AddonEventDelegate _creditPlayerHandler = delegate(AddonEvent t, AddonArgs a)
{
_instance?.CreditPlayerPostSetup(t, a);
};
private static readonly string[] CreditScrollArray = new string[1] { "CreditScroll" };
private static readonly string[] CreditArray = new string[1] { "Credit" };
private static readonly string[] CreditPlayerArray = new string[1] { "CreditPlayer" };
private static bool _deferDisposeUntilCutsceneEnds;
private static bool _pendingDispose;
private readonly IAddonLifecycle _addonLifecycle;
private readonly ILogger<CreditsController> _logger;
private static readonly object _lock = new object();
public CreditsController(IAddonLifecycle addonLifecycle, ILogger<CreditsController> logger)
{
_addonLifecycle = addonLifecycle;
_logger = logger;
lock (_lock)
{
if (_instance == null)
{
_instance = this;
_registeredLifecycle = _addonLifecycle;
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, CreditScrollArray, _creditScrollHandler);
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, CreditArray, _creditHandler);
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, CreditPlayerArray, _creditPlayerHandler);
}
}
}
private unsafe void CreditScrollPostSetup(AddonEvent type, AddonArgs args)
{
_logger.LogInformation("Closing Credits sequence scroll post-setup");
if (args.Addon.Address == IntPtr.Zero)
{
_logger.LogInformation("CreditScrollPostSetup: Addon address is zero, skipping.");
return;
}
lock (_lock)
{
if (_registeredLifecycle != null)
{
_registeredLifecycle.UnregisterListener(AddonEvent.PostSetup, CreditPlayerArray, _creditPlayerHandler);
_registeredLifecycle.UnregisterListener(AddonEvent.PostSetup, CreditArray, _creditHandler);
_registeredLifecycle.UnregisterListener(AddonEvent.PostSetup, CreditScrollArray, _creditScrollHandler);
_registeredLifecycle = null;
_instance = null;
}
}
AtkUnitBase* address = (AtkUnitBase*)args.Addon.Address;
address->FireCallbackInt(-2);
}
private unsafe void CreditPostSetup(AddonEvent type, AddonArgs args)
{
_logger.LogInformation("Closing Credits sequence post-setup");
if (args.Addon.Address == IntPtr.Zero)
{
_logger.LogInformation("CreditPostSetup: Addon address is zero, skipping.");
return;
}
lock (_lock)
{
if (_registeredLifecycle != null)
{
_registeredLifecycle.UnregisterListener(AddonEvent.PostSetup, CreditPlayerArray, _creditPlayerHandler);
_registeredLifecycle.UnregisterListener(AddonEvent.PostSetup, CreditArray, _creditHandler);
_registeredLifecycle.UnregisterListener(AddonEvent.PostSetup, CreditScrollArray, _creditScrollHandler);
_registeredLifecycle = null;
_instance = null;
}
}
AtkUnitBase* address = (AtkUnitBase*)args.Addon.Address;
address->FireCallbackInt(-2);
}
private unsafe void CreditPlayerPostSetup(AddonEvent type, AddonArgs args)
{
_logger.LogInformation("Closing CreditPlayer");
if (args.Addon.Address == IntPtr.Zero)
{
return;
}
lock (_lock)
{
if (_registeredLifecycle != null)
{
_registeredLifecycle.UnregisterListener(AddonEvent.PostSetup, CreditPlayerArray, _creditPlayerHandler);
_registeredLifecycle.UnregisterListener(AddonEvent.PostSetup, CreditArray, _creditHandler);
_registeredLifecycle.UnregisterListener(AddonEvent.PostSetup, CreditScrollArray, _creditScrollHandler);
_registeredLifecycle = null;
_instance = null;
}
}
AtkUnitBase* address = (AtkUnitBase*)args.Addon.Address;
address->Close(fireCallback: true);
}
public static void DeferDisposeUntilCutsceneEnds()
{
lock (_lock)
{
_deferDisposeUntilCutsceneEnds = true;
if (_instance != null)
{
_instance._logger.LogDebug("CreditsController: deferring dispose until cutscene ends.");
}
}
}
public static void NotifyCutsceneEnded()
{
lock (_lock)
{
_deferDisposeUntilCutsceneEnds = false;
if (_instance != null)
{
_instance._logger.LogDebug("CreditsController: cutscene ended, processing pending dispose state.");
}
if (_pendingDispose && _instance != null)
{
_instance._logger.LogDebug("CreditsController: pending dispose detected, performing unregister now.");
_instance.Dispose();
}
}
}
public void Dispose()
{
lock (_lock)
{
if (_instance != this)
{
return;
}
if (_deferDisposeUntilCutsceneEnds)
{
_pendingDispose = true;
_logger.LogInformation("CreditsController.Dispose deferred until cutscene end.");
return;
}
if (_registeredLifecycle != null)
{
_registeredLifecycle.UnregisterListener(AddonEvent.PostSetup, CreditPlayerArray, _creditPlayerHandler);
_registeredLifecycle.UnregisterListener(AddonEvent.PostSetup, CreditArray, _creditHandler);
_registeredLifecycle.UnregisterListener(AddonEvent.PostSetup, CreditScrollArray, _creditScrollHandler);
}
_registeredLifecycle = null;
_instance = null;
_pendingDispose = false;
_logger.LogDebug("CreditsController listeners unregistered and disposed (primary instance).");
}
}
}