Decompiled source of RMBPLAYER v1.0.0

BepInEx/plugins/RMBPLAYER/RMBPLAYER.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using Agents;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Gear;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Player;
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.RMBPLAYER;

internal sealed class FireScope
{
	internal readonly FireScope Previous;

	internal long ShotId;

	internal IntPtr WeaponPointer;

	internal IntPtr ShooterPointer;

	internal ItemEquippable Weapon;

	internal PlayerAgent Shooter;

	internal WeaponSlot Slot;

	internal uint ArchetypeId;

	internal string ArchetypeName;

	internal string PublicName;

	internal bool IsLocalPlayer;

	internal bool IsWeapon;

	internal readonly ShotRewardGate RewardGate = new ShotRewardGate();

	internal FireScope(FireScope previous)
	{
		Previous = previous;
	}
}
internal sealed class DamageScope
{
	internal IntPtr EnemyPointer;

	internal IntPtr ShooterPointer;

	internal float HealthBefore;

	internal bool LocalPlayerSource;

	internal bool LimbObserved;

	internal bool Weakspot;

	internal FireScope Shot;
}
internal static class ShotRewardTracker
{
	[ThreadStatic]
	private static FireScope _activeFire;

	private static readonly HashSet<uint> ReportedWeaponIds = new HashSet<uint>();

	private static long _nextShotId;

	private static int _warningBudget = 12;

	internal static FireScope ActiveFire => _activeFire;

	internal static FireScope PushExternalFire(FireScope scope)
	{
		FireScope activeFire = _activeFire;
		_activeFire = scope;
		return activeFire;
	}

	internal static void RestoreExternalFire(FireScope previous)
	{
		_activeFire = previous;
	}

	internal static FireScope BeginFire(ItemEquippable weapon)
	{
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Expected O, but got Unknown
		//IL_0192: Unknown result type (might be due to invalid IL or missing references)
		FireScope fireScope = (_activeFire = new FireScope(_activeFire)
		{
			ShotId = Interlocked.Increment(ref _nextShotId)
		});
		try
		{
			if ((Object)(object)weapon == (Object)null)
			{
				return fireScope;
			}
			PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
			if ((Object)(object)localPlayerAgent == (Object)null || (Object)(object)localPlayerAgent.Owner == (Object)null || !localPlayerAgent.Owner.IsLocal)
			{
				return fireScope;
			}
			FirstPersonItemHolder fPItemHolder = localPlayerAgent.FPItemHolder;
			ItemEquippable val = (((Object)(object)fPItemHolder != (Object)null) ? fPItemHolder.WieldedItem : null);
			if ((Object)(object)val == (Object)null || ((Il2CppObjectBase)val).Pointer != ((Il2CppObjectBase)weapon).Pointer)
			{
				return fireScope;
			}
			PlayerInventoryBase inventory = localPlayerAgent.Inventory;
			if ((Object)(object)inventory == (Object)null)
			{
				return fireScope;
			}
			fireScope.Weapon = val;
			fireScope.WeaponPointer = ((Il2CppObjectBase)val).Pointer;
			fireScope.Shooter = localPlayerAgent;
			fireScope.ShooterPointer = ((Il2CppObjectBase)localPlayerAgent).Pointer;
			fireScope.IsLocalPlayer = true;
			fireScope.IsWeapon = val.IsWeapon;
			fireScope.Slot = ToWeaponSlot(inventory.WieldedSlot);
			fireScope.ArchetypeId = val.ArchetypeID;
			fireScope.ArchetypeName = ((Item)val).ArchetypeName ?? string.Empty;
			fireScope.PublicName = ((Item)val).PublicName ?? string.Empty;
			if (fireScope.IsWeapon && ReportedWeaponIds.Add(fireScope.ArchetypeId))
			{
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					ManualLogSource log = ((BasePlugin)instance).Log;
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(65, 4, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[RMBPLAYER] weapon observed: slot=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<InventorySlot>(inventory.WieldedSlot);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(";archetypeId=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<uint>(fireScope.ArchetypeId);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(";archetype=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(fireScope.ArchetypeName);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(";name=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(fireScope.PublicName);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
					}
					log.LogInfo(val2);
				}
			}
		}
		catch (Exception ex)
		{
			Note("fire capture skipped: " + ex.GetType().Name);
		}
		return fireScope;
	}

	internal static Exception EndFire(FireScope scope, Exception error)
	{
		try
		{
			if (_activeFire == scope)
			{
				_activeFire = scope?.Previous;
			}
		}
		catch (Exception ex)
		{
			Note("fire scope cleanup skipped: " + ex.GetType().Name);
		}
		return error;
	}

	internal static DamageScope BeginDamage(Dam_EnemyDamageBase enemy, pBulletDamageData data)
	{
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Invalid comparison between Unknown and I4
		DamageScope damageScope = new DamageScope
		{
			Shot = _activeFire
		};
		try
		{
			Agent val = null;
			((pAgent)(ref data.source)).TryGet(ref val);
			PlayerAgent val2 = (((Object)(object)val != (Object)null) ? ((Il2CppObjectBase)val).TryCast<PlayerAgent>() : null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)val2.Owner == (Object)null || !val2.Owner.IsLocal)
			{
				return damageScope;
			}
			damageScope.LocalPlayerSource = true;
			damageScope.ShooterPointer = ((Il2CppObjectBase)val2).Pointer;
			if ((Object)(object)enemy == (Object)null)
			{
				return damageScope;
			}
			damageScope.EnemyPointer = ((Il2CppObjectBase)enemy).Pointer;
			damageScope.HealthBefore = ((Dam_SyncedDamageBase)enemy).Health;
			int limbID = data.limbID;
			Il2CppReferenceArray<Dam_EnemyDamageLimb> damageLimbs = enemy.DamageLimbs;
			if (damageLimbs != null && limbID >= 0 && limbID < ((Il2CppArrayBase<Dam_EnemyDamageLimb>)(object)damageLimbs).Length)
			{
				Dam_EnemyDamageLimb val3 = ((Il2CppArrayBase<Dam_EnemyDamageLimb>)(object)damageLimbs)[limbID];
				if ((Object)(object)val3 != (Object)null)
				{
					damageScope.LimbObserved = true;
					damageScope.Weakspot = (int)val3.m_type == 1;
				}
			}
		}
		catch (Exception ex)
		{
			Note("damage capture skipped: " + ex.GetType().Name);
		}
		return damageScope;
	}

	internal static DamageScope BeginLimbDamage(Dam_EnemyDamageLimb limb, Agent sourceAgent)
	{
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Invalid comparison between Unknown and I4
		DamageScope damageScope = new DamageScope
		{
			Shot = _activeFire
		};
		try
		{
			PlayerAgent val = (((Object)(object)sourceAgent != (Object)null) ? ((Il2CppObjectBase)sourceAgent).TryCast<PlayerAgent>() : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val.Owner == (Object)null || !val.Owner.IsLocal || (Object)(object)limb == (Object)null)
			{
				return damageScope;
			}
			damageScope.LocalPlayerSource = true;
			damageScope.ShooterPointer = ((Il2CppObjectBase)val).Pointer;
			Dam_EnemyDamageBase val2 = limb.m_base;
			if ((Object)(object)val2 == (Object)null)
			{
				return damageScope;
			}
			damageScope.EnemyPointer = ((Il2CppObjectBase)val2).Pointer;
			damageScope.HealthBefore = ((Dam_SyncedDamageBase)val2).Health;
			damageScope.LimbObserved = true;
			damageScope.Weakspot = (int)limb.m_type == 1;
		}
		catch (Exception ex)
		{
			Note("limb damage capture skipped: " + ex.GetType().Name);
		}
		return damageScope;
	}

	internal static Exception EndLimbDamage(Dam_EnemyDamageLimb limb, DamageScope scope, Exception error)
	{
		Dam_EnemyDamageBase enemy = null;
		try
		{
			enemy = (((Object)(object)limb != (Object)null) ? limb.m_base : null);
		}
		catch (Exception ex)
		{
			Note("limb base lookup skipped: " + ex.GetType().Name);
		}
		return EndDamage(enemy, scope, error);
	}

	internal static Exception EndDamage(Dam_EnemyDamageBase enemy, DamageScope scope, Exception error)
	{
		//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f7: Expected O, but got Unknown
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Expected O, but got Unknown
		try
		{
			if (error != null || (Object)(object)enemy == (Object)null || scope == null || scope.Shot == null)
			{
				return error;
			}
			FireScope shot = scope.Shot;
			if (((Il2CppObjectBase)enemy).Pointer != scope.EnemyPointer || !scope.LocalPlayerSource || !shot.IsLocalPlayer || shot.ShooterPointer != scope.ShooterPointer || shot.WeaponPointer == IntPtr.Zero || (Object)(object)shot.Weapon == (Object)null)
			{
				return error;
			}
			bool weaponAllowed = RMBPLAYERPolicy.IsAllowedWeaponId((Plugin.AllowedWeaponArchetypeIDs != null) ? Plugin.AllowedWeaponArchetypeIDs.Value : string.Empty, shot.ArchetypeId);
			bool qualifyingKill = RMBPLAYERPolicy.ShouldRefund(Plugin.Enabled != null && Plugin.Enabled.Value, scope.LocalPlayerSource, scope.HealthBefore, ((Dam_SyncedDamageBase)enemy).Health, scope.LimbObserved, scope.Weakspot, shot.IsWeapon, shot.Slot, weaponAllowed);
			if (!shot.RewardGate.TryClaim(qualifyingKill))
			{
				return error;
			}
			int currentClip = shot.Weapon.GetCurrentClip();
			int maxClip = shot.Weapon.GetMaxClip();
			int num = RMBPLAYERPolicy.RefundOneRound(currentClip, maxClip);
			bool flag = default(bool);
			Plugin instance;
			if (num <= currentClip)
			{
				instance = Plugin.Instance;
				if (instance != null)
				{
					ManualLogSource log = ((BasePlugin)instance).Log;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(76, 4, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[RMBPLAYER] weakspot kill; magazine already full: shot=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(shot.ShotId);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";archetypeId=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<uint>(shot.ArchetypeId);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";clip=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(currentClip);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("/");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(maxClip);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					}
					log.LogInfo(val);
				}
				return error;
			}
			shot.Weapon.SetCurrentClip(num);
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log2 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(89, 6, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[RMBPLAYER] weakspot kill refunded one round: shot=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<long>(shot.ShotId);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";slot=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<WeaponSlot>(shot.Slot);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";archetypeId=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<uint>(shot.ArchetypeId);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";archetype=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(shot.ArchetypeName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";clip=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("/");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(maxClip);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log2.LogInfo(val);
			}
		}
		catch (Exception ex)
		{
			Note("magazine refund skipped: " + ex.GetType().Name);
		}
		return error;
	}

	internal static void Reset()
	{
		_activeFire = null;
		ReportedWeaponIds.Clear();
		EwcShotBridge.Reset();
	}

	internal static void LogPatchReceipts(Harmony harmony, ManualLogSource log)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		bool flag = default(bool);
		foreach (MethodBase patchedMethod in harmony.GetPatchedMethods())
		{
			Patches patchInfo = Harmony.GetPatchInfo(patchedMethod);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(44, 5, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[RMBPLAYER][DIAG] patch ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(patchedMethod.DeclaringType.Name);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(patchedMethod.Name);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": pre=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(patchInfo.Prefixes.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(",post=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(patchInfo.Postfixes.Count);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(",final=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(patchInfo.Finalizers.Count);
			}
			log.LogInfo(val);
		}
	}

	private static WeaponSlot ToWeaponSlot(InventorySlot slot)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Invalid comparison between Unknown and I4
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Invalid comparison between Unknown and I4
		if ((int)slot == 1)
		{
			return WeaponSlot.Primary;
		}
		if ((int)slot == 2)
		{
			return WeaponSlot.Secondary;
		}
		return WeaponSlot.Other;
	}

	private static void Note(string message)
	{
		if (_warningBudget-- > 0)
		{
			Plugin instance = Plugin.Instance;
			if (instance != null)
			{
				((BasePlugin)instance).Log.LogWarning((object)("[RMBPLAYER][DIAG] " + message));
			}
		}
	}
}
internal static class WeaponFireScopePatch
{
	private static readonly object PatchLock = new object();

	private static readonly HashSet<MethodBase> PatchedMethods = new HashSet<MethodBase>();

	private static Harmony _harmony;

	private static bool _watchingAssemblyLoad;

	internal static void Install(Harmony harmony)
	{
		_harmony = harmony;
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		for (int i = 0; i < assemblies.Length; i++)
		{
			PatchAssembly(assemblies[i]);
		}
		if (!_watchingAssemblyLoad)
		{
			AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
			_watchingAssemblyLoad = true;
		}
	}

	private static void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args)
	{
		try
		{
			PatchAssembly(args.LoadedAssembly);
		}
		catch (Exception ex)
		{
			Plugin instance = Plugin.Instance;
			if (instance != null)
			{
				((BasePlugin)instance).Log.LogWarning((object)("[RMBPLAYER][DIAG] late weapon scan skipped: " + ex.GetType().Name));
			}
		}
	}

	private static void PatchAssembly(Assembly assembly)
	{
		Type[] types;
		try
		{
			types = assembly.GetTypes();
		}
		catch (ReflectionTypeLoadException ex)
		{
			types = ex.Types;
		}
		catch
		{
			return;
		}
		Type[] array = types;
		foreach (Type type in array)
		{
			if (type != null && !type.IsAbstract && typeof(BulletWeapon).IsAssignableFrom(type))
			{
				PatchFire(type);
			}
		}
	}

	private static void PatchFire(Type type)
	{
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Expected O, but got Unknown
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Expected O, but got Unknown
		//IL_00ab: Expected O, but got Unknown
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Expected O, but got Unknown
		MethodInfo methodInfo;
		try
		{
			methodInfo = AccessTools.DeclaredMethod(type, "Fire", new Type[1] { typeof(bool) }, (Type[])null);
		}
		catch
		{
			return;
		}
		if (methodInfo == null)
		{
			return;
		}
		lock (PatchLock)
		{
			if (!PatchedMethods.Add(methodInfo))
			{
				return;
			}
		}
		try
		{
			MethodInfo method = typeof(WeaponFireScopePatch).GetMethod("Prefix", BindingFlags.Static | BindingFlags.NonPublic);
			MethodInfo method2 = typeof(WeaponFireScopePatch).GetMethod("Finalizer", BindingFlags.Static | BindingFlags.NonPublic);
			_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null);
			Plugin instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log = ((BasePlugin)instance).Log;
				bool flag;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(50, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[RMBPLAYER][DIAG] Fire scope patched: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(type.FullName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".Fire(bool).");
				}
				log.LogInfo(val);
			}
		}
		catch (Exception ex)
		{
			lock (PatchLock)
			{
				PatchedMethods.Remove(methodInfo);
			}
			Plugin instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log2 = ((BasePlugin)instance).Log;
				bool flag;
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(41, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[RMBPLAYER][DIAG] Fire patch skipped: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(type.FullName);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("; ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.GetType().Name);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
				}
				log2.LogWarning(val2);
			}
		}
	}

	private static void Prefix(ItemEquippable __instance, out FireScope __state)
	{
		__state = ShotRewardTracker.BeginFire(__instance);
	}

	private static Exception Finalizer(FireScope __state, Exception __exception)
	{
		return ShotRewardTracker.EndFire(__state, __exception);
	}
}
[HarmonyPatch(typeof(Dam_EnemyDamageBase), "ReceiveBulletDamage")]
internal static class WeakspotKillRewardPatch
{
	[HarmonyPrefix]
	private static void Prefix(Dam_EnemyDamageBase __instance, pBulletDamageData data, out DamageScope __state)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		__state = ShotRewardTracker.BeginDamage(__instance, data);
	}

	[HarmonyFinalizer]
	private static Exception Finalizer(Dam_EnemyDamageBase __instance, DamageScope __state, Exception __exception)
	{
		return ShotRewardTracker.EndDamage(__instance, __state, __exception);
	}
}
[HarmonyPatch(typeof(GameStateManager), "DoChangeState")]
internal static class RMBPLAYERStatePatch
{
	[HarmonyPrefix]
	private static void Prefix(eGameStateName nextState)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		if ((int)nextState != 10)
		{
			ShotRewardTracker.Reset();
		}
	}
}
[HarmonyPatch(typeof(Dam_EnemyDamageLimb), "BulletDamage")]
internal static class WeakspotLimbDamageRewardPatch
{
	[HarmonyPrefix]
	private static void Prefix(Dam_EnemyDamageLimb __instance, Agent sourceAgent, out DamageScope __state)
	{
		__state = ShotRewardTracker.BeginLimbDamage(__instance, sourceAgent);
	}

	[HarmonyFinalizer]
	private static Exception Finalizer(Dam_EnemyDamageLimb __instance, DamageScope __state, Exception __exception)
	{
		return ShotRewardTracker.EndLimbDamage(__instance, __state, __exception);
	}
}
internal static class EwcShotBridge
{
	private sealed class ProjectileLink
	{
		internal FireScope Shot;

		internal readonly long Sequence;

		internal ProjectileLink(FireScope shot, long sequence)
		{
			Shot = shot;
			Sequence = sequence;
		}
	}

	internal sealed class ExternalHitScope
	{
		internal readonly FireScope Previous;

		internal ExternalHitScope(FireScope previous)
		{
			Previous = previous;
		}
	}

	private const string EwcAssemblyName = "ExtraWeaponCustomization";

	private const string ProjectileBaseTypeName = "EWC.CustomWeapon.Properties.Traits.CustomProjectile.Components.EWCProjectileComponentBase";

	private const string ProjectileHitboxTypeName = "EWC.CustomWeapon.Properties.Traits.CustomProjectile.Components.EWCProjectileHitbox";

	private const int MaxTrackedProjectiles = 2048;

	private static readonly object Sync = new object();

	private static readonly Dictionary<IntPtr, ProjectileLink> ProjectileScopes = new Dictionary<IntPtr, ProjectileLink>();

	private static readonly Queue<KeyValuePair<IntPtr, long>> EvictionOrder = new Queue<KeyValuePair<IntPtr, long>>();

	private static readonly Dictionary<Type, FieldInfo> BaseFieldCache = new Dictionary<Type, FieldInfo>();

	private static readonly HashSet<MethodBase> PatchedMethods = new HashSet<MethodBase>();

	private static Harmony _harmony;

	private static ManualLogSource _log;

	private static long _nextLink;

	private static bool _watchingAssemblyLoad;

	private static int _warningBudget = 8;

	internal static void Install(Harmony harmony, ManualLogSource log)
	{
		_harmony = harmony;
		_log = log;
		bool flag = false;
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			if (IsEwcAssembly(assembly))
			{
				flag = true;
				TryInstall(assembly);
			}
		}
		if (!_watchingAssemblyLoad)
		{
			AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
			_watchingAssemblyLoad = true;
		}
		if (!flag)
		{
			ManualLogSource log2 = _log;
			if (log2 != null)
			{
				log2.LogInfo((object)"[RMBPLAYER][DIAG] EWC is not loaded yet; reflective projectile bridge is waiting for its assembly.");
			}
		}
	}

	internal static void Reset()
	{
		lock (Sync)
		{
			ProjectileScopes.Clear();
			EvictionOrder.Clear();
		}
	}

	private static void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args)
	{
		try
		{
			if (IsEwcAssembly(args.LoadedAssembly))
			{
				TryInstall(args.LoadedAssembly);
			}
		}
		catch (Exception ex)
		{
			Note("EWC assembly-load bridge skipped: " + ex.GetType().Name);
		}
	}

	private static bool IsEwcAssembly(Assembly assembly)
	{
		try
		{
			return assembly != null && string.Equals(assembly.GetName().Name, "ExtraWeaponCustomization", StringComparison.OrdinalIgnoreCase);
		}
		catch
		{
			return false;
		}
	}

	private static void TryInstall(Assembly assembly)
	{
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Expected O, but got Unknown
		Type type = assembly.GetType("EWC.CustomWeapon.Properties.Traits.CustomProjectile.Components.EWCProjectileComponentBase", throwOnError: false, ignoreCase: false);
		Type? type2 = assembly.GetType("EWC.CustomWeapon.Properties.Traits.CustomProjectile.Components.EWCProjectileHitbox", throwOnError: false, ignoreCase: false);
		MethodInfo methodInfo = FindMethod(type, "Init", delegate(MethodInfo method)
		{
			ParameterInfo[] parameters = method.GetParameters();
			return parameters.Length == 9 && parameters[7].ParameterType.FullName == "EWC.Utils.HitData";
		});
		MethodInfo methodInfo2 = FindMethod(type2, "BulletHit", delegate(MethodInfo method)
		{
			ParameterInfo[] parameters = method.GetParameters();
			return parameters.Length == 1 && parameters[0].ParameterType.Name == "IDamageable";
		});
		int num = 0;
		if (methodInfo != null && Patch(methodInfo, null, Method("ProjectileInitPostfix"), null))
		{
			num++;
		}
		if (methodInfo2 != null && Patch(methodInfo2, Method("ProjectileHitPrefix"), null, Method("ProjectileHitFinalizer")))
		{
			num++;
		}
		if (type != null)
		{
			MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo3 in methods)
			{
				if ((methodInfo3.Name == "OnDisable" || methodInfo3.Name == "OnDestroy") && methodInfo3.GetParameters().Length == 0 && Patch(methodInfo3, null, Method("ProjectileCleanupPostfix"), null))
				{
					num++;
				}
			}
		}
		if (methodInfo != null && methodInfo2 != null)
		{
			ManualLogSource log = _log;
			if (log != null)
			{
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(84, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[RMBPLAYER][DIAG] EWC delayed-projectile bridge installed: Init=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(methodInfo.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";hit=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(methodInfo2.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(";cleanupHooks=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num - 2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log.LogInfo(val);
			}
		}
		else
		{
			Note($"EWC bridge signature not found: projectileInit={methodInfo != null};delayedHit={methodInfo2 != null}.");
		}
	}

	private static MethodInfo FindMethod(Type type, string name, Predicate<MethodInfo> matches)
	{
		if (type == null)
		{
			return null;
		}
		MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (MethodInfo methodInfo in methods)
		{
			if (methodInfo.Name == name && matches(methodInfo))
			{
				return methodInfo;
			}
		}
		return null;
	}

	private static MethodInfo Method(string name)
	{
		return typeof(EwcShotBridge).GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic);
	}

	private static bool Patch(MethodBase original, MethodInfo prefix, MethodInfo postfix, MethodInfo finalizer)
	{
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		if (original == null || _harmony == null)
		{
			return false;
		}
		lock (PatchedMethods)
		{
			if (!PatchedMethods.Add(original))
			{
				return false;
			}
		}
		try
		{
			_harmony.Patch(original, (!(prefix != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(prefix), (!(postfix != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(postfix), (HarmonyMethod)null, (!(finalizer != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(finalizer), (HarmonyMethod)null);
			return true;
		}
		catch (Exception ex)
		{
			lock (PatchedMethods)
			{
				PatchedMethods.Remove(original);
			}
			Note("EWC patch failed for " + original.DeclaringType?.Name + "." + original.Name + ": " + ex.GetType().Name);
			return false;
		}
	}

	private static void ProjectileInitPostfix(object __instance)
	{
		try
		{
			FireScope activeFire = ShotRewardTracker.ActiveFire;
			if (activeFire == null || !activeFire.IsLocalPlayer || !activeFire.IsWeapon || activeFire.WeaponPointer == IntPtr.Zero || __instance == null)
			{
				return;
			}
			Il2CppObjectBase val = (Il2CppObjectBase)((__instance is Il2CppObjectBase) ? __instance : null);
			if (val == null || val.Pointer == IntPtr.Zero)
			{
				return;
			}
			lock (Sync)
			{
				IntPtr pointer = val.Pointer;
				if (ProjectileScopes.TryGetValue(pointer, out var value))
				{
					value.Shot = activeFire;
					return;
				}
				long num = Interlocked.Increment(ref _nextLink);
				ProjectileScopes[pointer] = new ProjectileLink(activeFire, num);
				EvictionOrder.Enqueue(new KeyValuePair<IntPtr, long>(pointer, num));
				while (ProjectileScopes.Count > 2048 && EvictionOrder.Count > 0)
				{
					KeyValuePair<IntPtr, long> keyValuePair = EvictionOrder.Dequeue();
					if (ProjectileScopes.TryGetValue(keyValuePair.Key, out var value2) && value2.Sequence == keyValuePair.Value)
					{
						ProjectileScopes.Remove(keyValuePair.Key);
					}
				}
			}
		}
		catch (Exception ex)
		{
			Note("EWC projectile registration skipped: " + ex.GetType().Name);
		}
	}

	private static void ProjectileHitPrefix(object __instance, out ExternalHitScope __state)
	{
		__state = null;
		try
		{
			if (__instance == null)
			{
				return;
			}
			FieldInfo baseField = GetBaseField(__instance.GetType());
			if (baseField == null)
			{
				return;
			}
			object? value = baseField.GetValue(__instance);
			Il2CppObjectBase val = (Il2CppObjectBase)((value is Il2CppObjectBase) ? value : null);
			if (val == null || val.Pointer == IntPtr.Zero)
			{
				return;
			}
			FireScope shot;
			lock (Sync)
			{
				if (!ProjectileScopes.TryGetValue(val.Pointer, out var value2))
				{
					return;
				}
				shot = value2.Shot;
			}
			if (shot != null)
			{
				__state = new ExternalHitScope(ShotRewardTracker.PushExternalFire(shot));
			}
		}
		catch (Exception ex)
		{
			Note("EWC delayed hit scope skipped: " + ex.GetType().Name);
		}
	}

	private static Exception ProjectileHitFinalizer(ExternalHitScope __state, Exception __exception)
	{
		try
		{
			if (__state != null)
			{
				ShotRewardTracker.RestoreExternalFire(__state.Previous);
			}
		}
		catch (Exception ex)
		{
			Note("EWC delayed hit scope restore skipped: " + ex.GetType().Name);
		}
		return __exception;
	}

	private static void ProjectileCleanupPostfix(object __instance)
	{
		try
		{
			Il2CppObjectBase val = (Il2CppObjectBase)((__instance is Il2CppObjectBase) ? __instance : null);
			if (val == null)
			{
				return;
			}
			lock (Sync)
			{
				ProjectileScopes.Remove(val.Pointer);
			}
		}
		catch (Exception ex)
		{
			Note("EWC projectile cleanup skipped: " + ex.GetType().Name);
		}
	}

	private static FieldInfo GetBaseField(Type type)
	{
		lock (Sync)
		{
			if (BaseFieldCache.TryGetValue(type, out var value))
			{
				return value;
			}
			FieldInfo field = type.GetField("_base", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			BaseFieldCache[type] = field;
			return field;
		}
	}

	private static void Note(string message)
	{
		if (_warningBudget-- > 0)
		{
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogWarning((object)("[RMBPLAYER][DIAG] " + message));
			}
		}
	}
}
[BepInPlugin("HawChow.RMBPLAYER", "RMBPLAYER", "1.0.0")]
public sealed class Plugin : BasePlugin
{
	internal static Plugin Instance;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<string> AllowedWeaponArchetypeIDs;

	public override void Load()
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Expected O, but got Unknown
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Expected O, but got Unknown
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Expected O, but got Unknown
		//IL_00ea: Expected O, but got Unknown
		Instance = this;
		Enabled = ((BasePlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable one-round magazine refunds for local weakspot kills.");
		AllowedWeaponArchetypeIDs = ((BasePlugin)this).Config.Bind<string>("Weapons", "AllowedWeaponArchetypeIDs", "*", "Comma-separated ItemEquippable ArchetypeID values; * enables every primary/secondary weapon. Hex IDs may use 0x prefix.");
		Harmony val = new Harmony("HawChow.RMBPLAYER");
		val.PatchAll(typeof(Plugin).Assembly);
		WeaponFireScopePatch.Install(val);
		EwcShotBridge.Install(val, ((BasePlugin)this).Log);
		ManualLogSource log = ((BasePlugin)this).Log;
		bool flag = default(bool);
		BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(142, 3, ref flag);
		if (flag)
		{
			((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("RMBPLAYER");
			((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
			((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("1.0.0");
			((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" loaded; local weakspot kills only; slots=GearStandard/GearSpecial; allowedArchetypeIDs=");
			((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(AllowedWeaponArchetypeIDs.Value);
			((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("; EWC path=ItemEquippable; no EWC assembly reference.");
		}
		log.LogInfo(val2);
		ShotRewardTracker.LogPatchReceipts(val, ((BasePlugin)this).Log);
	}
}
internal static class PluginInfo
{
	internal const string Guid = "HawChow.RMBPLAYER";

	internal const string Name = "RMBPLAYER";

	internal const string Version = "1.0.0";
}
internal enum WeaponSlot
{
	Other,
	Primary,
	Secondary
}
internal static class RMBPLAYERPolicy
{
	internal static bool IsEligibleSlot(WeaponSlot slot)
	{
		if (slot != WeaponSlot.Primary)
		{
			return slot == WeaponSlot.Secondary;
		}
		return true;
	}

	internal static bool IsAllowedWeaponId(string configuredIds, uint archetypeId)
	{
		if (string.IsNullOrWhiteSpace(configuredIds))
		{
			return false;
		}
		string[] array = configuredIds.Split(new char[4] { ',', ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
		for (int i = 0; i < array.Length; i++)
		{
			string text = array[i].Trim();
			if (text == "*")
			{
				return true;
			}
			if (text.StartsWith("id:", StringComparison.OrdinalIgnoreCase))
			{
				text = text.Substring(3).Trim();
			}
			uint result;
			if (text.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
			{
				if (uint.TryParse(text.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out result) && result == archetypeId)
				{
					return true;
				}
			}
			else if (uint.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out result) && result == archetypeId)
			{
				return true;
			}
		}
		return false;
	}

	internal static bool ShouldRefund(bool enabled, bool localPlayerSource, float healthBefore, float healthAfter, bool limbObserved, bool limbIsWeakspot, bool isWeapon, WeaponSlot slot, bool weaponAllowed)
	{
		return enabled && localPlayerSource && IsFinite(healthBefore) && IsFinite(healthAfter) && healthBefore > 0f && healthAfter <= 0f && limbObserved && limbIsWeakspot && isWeapon && IsEligibleSlot(slot) && weaponAllowed;
	}

	internal static int RefundOneRound(int currentClip, int clipSize)
	{
		if (clipSize <= 0)
		{
			return currentClip;
		}
		if (currentClip < 0)
		{
			currentClip = 0;
		}
		if (currentClip >= clipSize)
		{
			return clipSize;
		}
		return currentClip + 1;
	}

	internal static bool IsFinite(float value)
	{
		if (!float.IsNaN(value))
		{
			return !float.IsInfinity(value);
		}
		return false;
	}
}
internal sealed class ShotRewardGate
{
	private bool _claimed;

	internal bool Claimed => _claimed;

	internal bool TryClaim(bool qualifyingKill)
	{
		if (!qualifyingKill || _claimed)
		{
			return false;
		}
		_claimed = true;
		return true;
	}
}