using System.Diagnostics.CodeAnalysis;
using ADOFAIRenderer.Core;
using HarmonyLib;
namespace ADOFAIRenderer.Patch.Game;
///
/// Suppresses the end-screen lanterns (level complete / accuracy / speed trial lamps) shown after a clear.
///
/// Patched members: EndscreenLanterns.Show(scrPlayer, float, int, bool), which activates the lantern set, sets the
/// lantern texts and starts DOTween sequences (chainSequence for the chain drop, lampSequences[3] for the lamp
/// effects), returning the number of lanterns shown; and EndscreenLanterns.Hide(), which deactivates the GameObject.
///
///
/// Active while (stage >= OnScene), so the lanterns and their tweens do not appear in
/// the rendered video during the delay after the level end. See also .
///
///
[HarmonyPatch(typeof(EndscreenLanterns))]
// ReSharper disable once InconsistentNaming
public static class EndscreenLanternsPatch
{
///
/// Prefix of EndscreenLanterns.Show. While rendering, hides the lantern set (which also runs
/// ) and reports zero lanterns shown.
///
/// The lantern set being shown.
/// Return value of Show: number of lanterns shown; set to 0 when the original is skipped.
/// True to run the original method (not rendering); false to skip it (rendering).
[HarmonyPrefix]
[HarmonyPatch("Show")]
[SuppressMessage("ReSharper", "InconsistentNaming")]
public static bool ForceHide(EndscreenLanterns __instance, ref int __result)
{
if (!RenderManager.IsActive) return true;
if (__instance != null)
{
__instance.Hide();
}
__result = 0; // Return 0 lanterns shown
return false; // Skip original Show method
}
///
/// Prefix of EndscreenLanterns.Hide. While rendering, releases the lantern tweens started by an earlier Show
/// before the original deactivates the GameObject.
///
/// The private fields lampSequences (DOTween Sequence[]) and chainSequence (Sequence) are read
/// through Harmony . For each sequence, a public instance method Kill(bool) is looked up on the
/// object's runtime type by reflection and invoked with false when found; then the field slot is set to null.
/// In the game's DOTween.dll, Kill(this Tween, bool complete = false) is an extension method of
/// DG.Tweening.TweenExtensions, so the lookup on Sequence returns null and no Kill is invoked; the effect is
/// that the fields stop referencing the sequences, while the sequences themselves keep running in DOTween.
/// Reflection failures on a single sequence (including a null array element) are ignored. The original Hide always runs
/// afterwards.
///
///
/// The lantern set being hidden.
[HarmonyPrefix]
[HarmonyPatch("Hide")]
[SuppressMessage("ReSharper", "InconsistentNaming")]
public static void PrefixHide(EndscreenLanterns __instance)
{
if (__instance == null) return;
if (!RenderManager.IsActive) return;
var traverse = Traverse.Create(__instance);
// Kill lampSequences (private Sequence[] lampSequences) via reflection
var lampSequencesField = traverse.Field("lampSequences");
var lampSequencesObj = lampSequencesField.GetValue();
if (lampSequencesObj is System.Array lampSequencesArray)
{
for (var i = 0; i < lampSequencesArray.Length; i++)
{
var item = lampSequencesArray.GetValue(i);
try
{
var killMethod = item.GetType().GetMethod("Kill", new[] { typeof(bool) });
killMethod?.Invoke(item, new object[] { false });
}
catch
{
// Ignore reflection errors
}
lampSequencesArray.SetValue(null, i);
}
}
// Kill chainSequence (private Sequence chainSequence) via reflection
var chainSequenceField = traverse.Field("chainSequence");
var chainSequenceObj = chainSequenceField.GetValue();
if (chainSequenceObj == null) return;
try
{
var killMethod = chainSequenceObj.GetType().GetMethod("Kill", new[] { typeof(bool) });
killMethod?.Invoke(chainSequenceObj, new object[] { false });
}
catch
{
// Ignore reflection errors
}
chainSequenceField.SetValue(null);
}
}