using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace HawChow.SentryAmmoGuard;
[BepInPlugin("HawChow.SentryAmmoGuard", "SentryAmmoGuard", "1.0.0")]
public sealed class Plugin : BasePlugin
{
internal static ManualLogSource Logger;
public override void Load()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Expected O, but got Unknown
Logger = ((BasePlugin)this).Log;
new Harmony("HawChow.SentryAmmoGuard").PatchAll();
ManualLogSource logger = Logger;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(86, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("SentryAmmoGuard");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.0.0");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded; SentryGunSemi targeting is gated by live sentry ammo and valid target state.");
}
logger.LogInfo(val);
}
}
internal static class PluginInfo
{
internal const string Guid = "HawChow.SentryAmmoGuard";
internal const string Name = "SentryAmmoGuard";
internal const string Version = "1.0.0";
}
internal readonly struct DetectionDecision
{
internal bool RunVanillaDetection { get; }
internal bool ClearCachedTarget { get; }
internal DetectionDecision(bool runVanillaDetection, bool clearCachedTarget)
{
RunVanillaDetection = runVanillaDetection;
ClearCachedTarget = clearCachedTarget;
}
}
internal static class SentryAmmoPolicy
{
internal static DetectionDecision ForDetection(bool isSniperSentry, float ammo)
{
bool flag = isSniperSentry && !HasUsableAmmo(ammo);
return new DetectionDecision(!flag, flag);
}
internal static bool ShouldAllowFire(bool isSniperSentry, float ammo, bool hasValidTarget)
{
if (isSniperSentry)
{
return HasUsableAmmo(ammo) && hasValidTarget;
}
return true;
}
internal static bool HasUsableAmmo(float ammo)
{
if (float.IsFinite(ammo))
{
return ammo > 0f;
}
return false;
}
internal static bool ShouldRunDetectionAfterStateReadError(bool isSniperSentry)
{
return !isSniperSentry;
}
internal static bool ShouldAllowFireAfterStateReadError(bool isSniperSentry)
{
return !isSniperSentry;
}
}
internal static class SentryTargetingAccess
{
internal static bool IsSniper(SentryGunInstance sentry)
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Invalid comparison between Unknown and I4
if ((Object)(object)sentry == (Object)null || sentry.m_firing == null)
{
return false;
}
SentryGunInstance_Firing_Bullets val = ((Il2CppObjectBase)sentry.m_firing).TryCast<SentryGunInstance_Firing_Bullets>();
if ((Object)(object)val != (Object)null)
{
return (int)val.m_fireMode == 10;
}
return false;
}
internal static bool ClearCachedTarget(SentryGunInstance_Detection detection)
{
if ((Object)(object)detection == (Object)null)
{
return false;
}
if (!detection.HasTarget && !((Object)(object)detection.Target != (Object)null) && !((Object)(object)detection.TargetAimTrans != (Object)null) && !detection.TargetIsTagged)
{
return false;
}
detection.Target = null;
detection.HasTarget = false;
detection.TargetIsTagged = false;
detection.TargetAimTrans = null;
return true;
}
internal static bool HasValidTarget(SentryGunInstance sentry)
{
if ((Object)(object)sentry == (Object)null || sentry.m_detection == null)
{
return false;
}
SentryGunInstance_Detection val = ((Il2CppObjectBase)sentry.m_detection).TryCast<SentryGunInstance_Detection>();
if ((Object)(object)val != (Object)null && val.HasTarget)
{
return (Object)(object)val.Target != (Object)null;
}
return false;
}
}
[HarmonyPatch(typeof(SentryGunInstance_Detection), "UpdateDetection")]
internal static class SniperSentryDetectionPatch
{
private static bool _reportedError;
[HarmonyPrefix]
private static bool Prefix(SentryGunInstance_Detection __instance)
{
bool flag = false;
try
{
object obj;
if (__instance == null)
{
obj = null;
}
else
{
iSentrygunInstanceCore core = __instance.m_core;
obj = ((core != null) ? ((Il2CppObjectBase)core).TryCast<SentryGunInstance>() : null);
}
SentryGunInstance val = (SentryGunInstance)obj;
flag = SentryTargetingAccess.IsSniper(val);
DetectionDecision detectionDecision = SentryAmmoPolicy.ForDetection(flag, ((Object)(object)val == (Object)null) ? float.NaN : val.Ammo);
if (detectionDecision.ClearCachedTarget && SentryTargetingAccess.ClearCachedTarget(__instance))
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogInfo((object)"[SentryAmmoGuard] Sniper Sentry target cleared at zero ammo; detection is paused until ammo is restored.");
}
}
return detectionDecision.RunVanillaDetection;
}
catch (Exception error)
{
ReportError(error);
if (flag)
{
try
{
SentryTargetingAccess.ClearCachedTarget(__instance);
}
catch
{
}
}
return SentryAmmoPolicy.ShouldRunDetectionAfterStateReadError(flag);
}
}
internal static void ReportError(Exception error)
{
if (!_reportedError)
{
_reportedError = true;
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogError((object)("Sentry guard could not read current game state; a classified sniper uses the fail-closed path. " + error));
}
}
}
}
[HarmonyPatch(typeof(SentryGunInstance), "WantToFire")]
internal static class SniperSentryFireGuardPatch
{
[HarmonyPostfix]
private static void Postfix(SentryGunInstance __instance, ref bool __result)
{
if (!__result)
{
return;
}
bool flag = false;
try
{
flag = SentryTargetingAccess.IsSniper(__instance);
if (flag)
{
__result = SentryAmmoPolicy.ShouldAllowFire(flag, __instance.Ammo, SentryTargetingAccess.HasValidTarget(__instance));
}
}
catch (Exception error)
{
SniperSentryDetectionPatch.ReportError(error);
__result = SentryAmmoPolicy.ShouldAllowFireAfterStateReadError(flag) & __result;
}
}
}