Decompiled source of GynxzRepoChallenges v1.4.0

plugins\GynxzRepoChallenges\GynxzRepoChallenges.dll

Decompiled 6 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using GynxzRepoChallenges.Challenges;
using GynxzRepoChallenges.Network;
using GynxzRepoChallenges.UI;
using HarmonyLib;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("GynxzRepoChallenges")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.4.0.0")]
[assembly: AssemblyInformationalVersion("1.4.0")]
[assembly: AssemblyProduct("GynxzRepoChallenges")]
[assembly: AssemblyTitle("GynxzRepoChallenges")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.0.0")]
[module: UnverifiableCode]
namespace GynxzRepoChallenges
{
	public static class ChallengeManager
	{
		private static readonly List<BaseChallenge> _active = new List<BaseChallenge>();

		private static readonly List<BaseChallenge> _picks = new List<BaseChallenge>();

		public static bool NoCrouchActive = false;

		public static bool NoSprintActive = false;

		public static bool NoMapActive = false;

		public static bool NoHealthPackActive = false;

		public static bool NoUpgradesActive = false;

		public static bool CartLeashActive = false;

		public static bool FlawlessActive = false;

		public static bool FrugalActive = false;

		public static bool ExpensiveOnlyActive = false;

		public static bool PacifistActive = false;

		public static bool EmpathyActive = false;

		public static bool NitroFingersActive = false;

		public static bool ShortRangeActive = false;

		public static float ShortRangeOriginalValue = -1f;

		public static float ShortRangeCurrentValue = -1f;

		public static bool InLevel = false;

		public static bool InMapLevel = false;

		private static int _f8Index = -1;

		private static int _lastCycleFrame = -1;

		private static int _lastClearFrame = -1;

		public static int FlawlessViolations = 0;

		public static int CartLeashViolations = 0;

		private static readonly List<Transform> _cartTransforms = new List<Transform>();

		private static float _leashTimer = 0f;

		private const float LEASH_INTERVAL = 1f;

		public static float CartLeashSlowFactor = 0f;

		public static Vector3 NearestCartPos = Vector3.zero;

		public static IEnumerable<BaseChallenge> ActiveChallenges => _active;

		public static IReadOnlyList<BaseChallenge> ActiveList => _active;

		public static BaseChallenge ActiveChallenge
		{
			get
			{
				if (_active.Count <= 0)
				{
					return null;
				}
				return _active[0];
			}
		}

		public static bool RosterHasActive()
		{
			foreach (BaseChallenge item in ChallengeRegistry.All)
			{
				if (Plugin.GetMode(item.Id) == ChallengeMode.Active)
				{
					return true;
				}
			}
			return false;
		}

		private static List<BaseChallenge> RosterActiveList()
		{
			return ChallengeRegistry.All.Where((BaseChallenge c) => Plugin.GetMode(c.Id) == ChallengeMode.Active).ToList();
		}

		private static List<BaseChallenge> AvailableList()
		{
			return ChallengeRegistry.All.Where((BaseChallenge c) => Plugin.GetMode(c.Id) == ChallengeMode.Available).ToList();
		}

		public static void ReconcileRoster()
		{
			List<BaseChallenge> list = RosterActiveList();
			foreach (BaseChallenge pick in _picks)
			{
				if (!list.Contains(pick))
				{
					list.Add(pick);
				}
			}
			SetActiveSet(list);
			Plugin.Log.LogInfo((object)($"[ChallengeManager] Reconciled — {list.Count} enforced" + ((list.Count > 0) ? (": " + string.Join(", ", list.Select((BaseChallenge c) => c.Id))) : ".")));
		}

		private static void SetActiveSet(IEnumerable<BaseChallenge> desired)
		{
			List<BaseChallenge> list = new List<BaseChallenge>();
			foreach (BaseChallenge item in desired)
			{
				if (item != null && !list.Contains(item))
				{
					list.Add(item);
				}
			}
			for (int num = _active.Count - 1; num >= 0; num--)
			{
				if (!list.Contains(_active[num]))
				{
					_active[num].Remove();
					_active.RemoveAt(num);
				}
			}
			foreach (BaseChallenge item2 in list)
			{
				if (!_active.Contains(item2))
				{
					item2.Apply();
					_active.Add(item2);
				}
			}
			ResetViolations();
			ChallengeHUD.Dirty = true;
			Plugin.WriteStatus();
		}

		public static bool AssignById(string id, bool additive = false)
		{
			BaseChallenge baseChallenge = ChallengeRegistry.Get(id);
			if (baseChallenge == null)
			{
				Plugin.Log.LogWarning((object)("[ChallengeManager] Unknown challenge id: '" + id + "'"));
				return false;
			}
			Assign(baseChallenge, additive);
			return true;
		}

		public static void AssignRandom()
		{
			Assign(ChallengeRegistry.GetRandom());
		}

		public static void Assign(BaseChallenge challenge, bool additive = false)
		{
			if (challenge != null)
			{
				if (!additive)
				{
					_picks.Clear();
				}
				if (!_picks.Contains(challenge))
				{
					_picks.Add(challenge);
				}
				ReconcileRoster();
				Plugin.Log.LogInfo((object)("[ChallengeManager] Challenge " + (additive ? "stacked" : "assigned") + " → " + challenge.DisplayName + (additive ? $" ({_picks.Count} picks)" : "")));
			}
		}

		public static void ClearChallenge()
		{
			if (Time.frameCount != _lastClearFrame)
			{
				_lastClearFrame = Time.frameCount;
				_picks.Clear();
				ReconcileRoster();
				Plugin.Log.LogInfo((object)"[ChallengeManager] Clear — manual picks cleared (Active roster kept).");
			}
		}

		public static void CycleChallenge()
		{
			if (Time.frameCount == _lastCycleFrame)
			{
				return;
			}
			_lastCycleFrame = Time.frameCount;
			if (RosterHasActive())
			{
				Plugin.Log.LogInfo((object)"[ChallengeManager] F8 ignored — Active challenges are set in config.");
				ChallengeHUD.ShowViolation("F8 disabled — Active challenges set in config");
				return;
			}
			List<BaseChallenge> list = AvailableList();
			if (list.Count == 0)
			{
				Plugin.Log.LogInfo((object)"[ChallengeManager] F8 ignored — no Available challenges in roster.");
				ChallengeHUD.ShowViolation("No Available challenges — set some to Available in config");
				return;
			}
			_f8Index = (_f8Index + 1) % list.Count;
			BaseChallenge baseChallenge = list[_f8Index];
			_picks.Clear();
			_picks.Add(baseChallenge);
			ReconcileRoster();
			Plugin.Log.LogInfo((object)$"[ChallengeManager] F8 → {baseChallenge.DisplayName} ({_f8Index + 1}/{list.Count})");
		}

		public static void OnRoundStart()
		{
			if (!Plugin.Ready)
			{
				Plugin.Log.LogInfo((object)"[ChallengeManager] OnRoundStart — plugin not ready yet, skipping.");
				return;
			}
			Plugin.Log.LogInfo((object)"[ChallengeManager] OnRoundStart triggered.");
			InLevel = true;
			ItemDamagePatch.ClearDestroyedSet();
			ItemDamagePatch.ClearValueCache();
			GrabPatch.OnRoundStart();
			HeldItemTicker.OnRoundStart();
			CacheCartPositions();
			Type type = Type.GetType("ValuableObject, Assembly-CSharp");
			Object[] array = ((type != null) ? Object.FindObjectsOfType(type) : null);
			InMapLevel = array != null && array.Length != 0;
			Plugin.Log.LogInfo((object)$"[ChallengeManager] InMapLevel = {InMapLevel} ({((array != null) ? array.Length : 0)} valuables found)");
			if (!InMapLevel)
			{
				Plugin.Log.LogInfo((object)"[ChallengeManager] Not a map level — challenge state unchanged.");
			}
			else if (Plugin.AutoAssignOnRoundStart.Value)
			{
				AssignRandom();
			}
			else if (Plugin.ChallengeScopePerRound.Value && _picks.Count > 0)
			{
				Plugin.Log.LogInfo((object)"[ChallengeManager] New round — clearing per-round picks.");
				_picks.Clear();
				ReconcileRoster();
			}
		}

		public static void OnSceneLoad()
		{
			InLevel = false;
			InMapLevel = false;
			_cartTransforms.Clear();
			_leashTimer = 0f;
			ChallengeHUD.ClearPersistentMessage();
			Plugin.Log.LogInfo((object)"[ChallengeManager] Scene changed — cart leash suspended.");
		}

		private static void CacheCartPositions()
		{
			_cartTransforms.Clear();
			_leashTimer = 0f;
			Type type = Type.GetType("PhysGrabObject, Assembly-CSharp");
			if (type != null)
			{
				FieldInfo field = type.GetField("isCart", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					Component[] array = Object.FindObjectsOfType(type) as Component[];
					bool flag = default(bool);
					foreach (Component val in array)
					{
						if (!((Object)(object)val == (Object)null))
						{
							object value = field.GetValue(val);
							int num;
							if (value is bool)
							{
								flag = (bool)value;
								num = 1;
							}
							else
							{
								num = 0;
							}
							if (((uint)num & (flag ? 1u : 0u)) != 0)
							{
								_cartTransforms.Add(val.transform);
								Plugin.Log.LogInfo((object)("[CartLeash] Cached cart: " + ((Object)val.gameObject).name));
							}
						}
					}
					Plugin.Log.LogInfo((object)$"[CartLeash] {_cartTransforms.Count} cart(s) cached via isCart.");
					return;
				}
			}
			GameObject[] array2 = Object.FindObjectsOfType<GameObject>();
			foreach (GameObject val2 in array2)
			{
				if (!((Object)(object)val2.transform.parent != (Object)null))
				{
					string text = ((Object)val2).name.ToLowerInvariant();
					if (text.Contains("cart") || text.Contains("trolley"))
					{
						_cartTransforms.Add(val2.transform);
						Plugin.Log.LogInfo((object)("[CartLeash] Cached (fallback): " + ((Object)val2).name));
					}
				}
			}
			Plugin.Log.LogInfo((object)$"[CartLeash] {_cartTransforms.Count} cart(s) cached (fallback).");
		}

		public static void CheckCartLeash(Vector3 playerPos)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			if (!CartLeashActive || !InLevel || !InMapLevel)
			{
				CartLeashSlowFactor = 0f;
			}
			else
			{
				if (_cartTransforms.Count == 0)
				{
					return;
				}
				float num = float.MaxValue;
				Vector3 nearestCartPos = Vector3.zero;
				foreach (Transform cartTransform in _cartTransforms)
				{
					if (!((Object)(object)cartTransform == (Object)null))
					{
						float num2 = Vector3.Distance(playerPos, cartTransform.position);
						if (num2 < num)
						{
							num = num2;
							nearestCartPos = cartTransform.position;
						}
					}
				}
				if (num == float.MaxValue)
				{
					return;
				}
				NearestCartPos = nearestCartPos;
				float value = Plugin.CartLeashSlowStartDistance.Value;
				float value2 = Plugin.CartLeashMaxDistance.Value;
				float num3 = (float)Plugin.CartLeashSlowPercent.Value / 100f;
				if (num <= value)
				{
					CartLeashSlowFactor = 0f;
					return;
				}
				if (num >= value2)
				{
					CartLeashSlowFactor = 1f;
				}
				else
				{
					float num4 = (num - value) / (value2 - value);
					CartLeashSlowFactor = Mathf.Lerp(0f, num3, num4);
				}
				if (!(CartLeashSlowFactor < 1f))
				{
					_leashTimer += Time.deltaTime;
					if (!(_leashTimer < 1f))
					{
						_leashTimer = 0f;
						CartLeashViolations++;
						Plugin.LogVerbose($"[CartLeash] Too far! {num:F1}u");
						ChallengeHUD.ShowViolation("CART LEASH! Return to cart!");
					}
				}
			}
		}

		public static void OnItemDamaged(string itemName)
		{
			if (FlawlessActive)
			{
				FlawlessViolations++;
				Plugin.Log.LogWarning((object)$"[Flawless] Item damaged: {itemName} (violation #{FlawlessViolations})");
				ChallengeHUD.ShowViolation("FLAWLESS BROKEN! Damaged: " + itemName);
			}
		}

		public static void OnEmpathyHit()
		{
			if (EmpathyActive)
			{
				ChallengeHUD.ShowViolation($"EMPATHETIC! -{Plugin.EmpathyDamagePerHit.Value}HP!");
			}
		}

		private static void ResetViolations()
		{
			FlawlessViolations = 0;
			CartLeashViolations = 0;
		}
	}
	public static class Patches
	{
		public static void PatchAll(Harmony harmony)
		{
			PatchPlayerController(harmony);
			PatchMethod(harmony, "MapToolController", "Update", typeof(MapPatch), "Prefix");
			PatchHealthPack(harmony);
			PatchUpgrade(harmony);
			PatchMethod(harmony, "PhysGrabber", "PhysGrabLogic", typeof(GrabPatch), "Prefix");
			PatchItemDamage(harmony);
			PatchShortRange(harmony);
			PatchLevelStart(harmony);
		}

		private static void PatchMethod(Harmony harmony, string typeName, string methodName, Type patchClass, string patchMethodName)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			try
			{
				Type gameType = GetGameType(typeName);
				if (gameType == null)
				{
					Plugin.Log.LogError((object)("[Patches] Type not found: " + typeName));
					return;
				}
				MethodInfo method = gameType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					Plugin.Log.LogError((object)("[Patches] Method not found: " + typeName + "." + methodName));
					return;
				}
				MethodInfo method2 = patchClass.GetMethod(patchMethodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				harmony.Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)("[Patches] ✓ " + typeName + "." + methodName + "()"));
				Plugin.Log.LogInfo((object)("[Patches] Applied: " + patchClass.Name));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[Patches] Failed to patch " + typeName + "." + methodName + ": " + ex.Message));
			}
		}

		private static void PatchPlayerController(Harmony harmony)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_0097: Expected O, but got Unknown
			try
			{
				Type gameType = GetGameType("PlayerController");
				if (gameType == null)
				{
					Plugin.Log.LogError((object)"[Patches] Type not found: PlayerController");
					return;
				}
				MethodInfo method = gameType.GetMethod("Update", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					Plugin.Log.LogError((object)"[Patches] Method not found: PlayerController.Update");
					return;
				}
				MethodInfo method2 = typeof(PlayerControllerPatch).GetMethod("Prefix", BindingFlags.Static | BindingFlags.Public);
				MethodInfo method3 = typeof(PlayerControllerPatch).GetMethod("Postfix", BindingFlags.Static | BindingFlags.Public);
				harmony.Patch((MethodBase)method, new HarmonyMethod(method2), new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)"[Patches] ✓ PlayerController.Update() (prefix + postfix)");
				Plugin.Log.LogInfo((object)"[Patches] Applied: PlayerControllerPatch");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[Patches] Failed to patch PlayerController.Update: " + ex.Message));
			}
		}

		private static void PatchItemDamage(Harmony harmony)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00ca: Expected O, but got Unknown
			try
			{
				Type gameType = GetGameType("PhysGrabObjectImpactDetector");
				if (gameType == null)
				{
					Plugin.Log.LogError((object)"[Patches] PhysGrabObjectImpactDetector not found");
					return;
				}
				MethodInfo method = typeof(ItemDamagePatch).GetMethod("Prefix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				MethodInfo method2 = typeof(ItemDamagePatch).GetMethod("Postfix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				string[] array = new string[3] { "ImpactHeavy", "ImpactMedium", "ImpactLight" };
				foreach (string text in array)
				{
					MethodInfo method3 = gameType.GetMethod(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (method3 == null)
					{
						Plugin.Log.LogWarning((object)("[Patches] " + text + " not found"));
						continue;
					}
					harmony.Patch((MethodBase)method3, new HarmonyMethod(method), new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Plugin.Log.LogInfo((object)("[Patches] ✓ PhysGrabObjectImpactDetector." + text + "()"));
				}
				Plugin.Log.LogInfo((object)"[Patches] Applied: ItemDamagePatch");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[Patches] ItemDamage patch failed: " + ex.Message));
			}
		}

		private static void PatchShortRange(Harmony harmony)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			try
			{
				Type gameType = GetGameType("PhysGrabber");
				if (gameType == null)
				{
					Plugin.Log.LogError((object)"[Patches] PhysGrabber not found for ShortRange");
					return;
				}
				MethodInfo method = gameType.GetMethod("Update", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					Plugin.Log.LogError((object)"[Patches] PhysGrabber.Update not found");
					return;
				}
				MethodInfo method2 = typeof(ShortRangePatch).GetMethod("Postfix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)"[Patches] ✓ PhysGrabber.Update() (postfix)");
				Plugin.Log.LogInfo((object)"[Patches] Applied: ShortRangePatch");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[Patches] ShortRange patch failed: " + ex.Message));
			}
		}

		private static void PatchLevelStart(Harmony harmony)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			try
			{
				Type gameType = GetGameType("GameDirector");
				if (gameType == null)
				{
					Plugin.Log.LogError((object)"[Patches] GameDirector not found");
					return;
				}
				MethodInfo method = gameType.GetMethod("SetStart", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method == null)
				{
					Plugin.Log.LogError((object)"[Patches] GameDirector.SetStart not found");
					return;
				}
				HarmonyMethod val = new HarmonyMethod(typeof(LevelStartPatch).GetMethod("Postfix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
				val.priority = 0;
				harmony.Patch((MethodBase)method, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)"[Patches] ✓ GameDirector.SetStart() (Priority.Last)");
				Plugin.Log.LogInfo((object)"[Patches] Applied: LevelStartPatch");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[Patches] LevelStart patch failed: " + ex.Message));
			}
		}

		private static void PatchHealthPack(Harmony harmony)
		{
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Expected O, but got Unknown
			try
			{
				Type gameType = GetGameType("ItemHealthPack");
				if (gameType == null)
				{
					Plugin.Log.LogError((object)"[Patches] ItemHealthPack not found");
					return;
				}
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("[Patches] ItemHealthPack methods:");
				MethodInfo[] methods = gameType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					string text = string.Join(", ", Array.ConvertAll(methodInfo.GetParameters(), (ParameterInfo p) => p.ParameterType.Name + " " + p.Name));
					stringBuilder.AppendLine("  " + methodInfo.ReturnType.Name + " " + methodInfo.Name + "(" + text + ")");
				}
				Plugin.Log.LogInfo((object)stringBuilder.ToString());
				MethodInfo method = typeof(HealthPackPatch).GetMethod("Prefix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				int num = 0;
				string[] array = new string[21]
				{
					"Update", "UsedRPC", "Used", "UseItem", "Use", "Interact", "OnInteract", "Activate", "TryUse", "UseLocal",
					"OnUse", "PickUp", "Heal", "HealRPC", "UseHealthPack", "PickupActivate", "ItemActivate", "UseActivate", "SetUsed", "ActivateItem",
					"ApplyHeal"
				};
				foreach (string text2 in array)
				{
					MethodInfo method2 = gameType.GetMethod(text2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (!(method2 == null))
					{
						harmony.Patch((MethodBase)method2, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						Plugin.Log.LogInfo((object)("[Patches] ✓ ItemHealthPack." + text2 + "()"));
						num++;
					}
				}
				if (num == 0)
				{
					Plugin.Log.LogError((object)"[Patches] No ItemHealthPack methods matched — check dump above");
				}
				Plugin.Log.LogInfo((object)"[Patches] Applied: HealthPackPatch");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[Patches] HealthPack patch failed: " + ex.Message));
			}
		}

		private static void PatchUpgrade(Harmony harmony)
		{
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Expected O, but got Unknown
			try
			{
				Type gameType = GetGameType("ItemUpgrade");
				if (gameType == null)
				{
					Plugin.Log.LogError((object)"[Patches] ItemUpgrade not found");
					return;
				}
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("[Patches] ItemUpgrade methods:");
				MethodInfo[] methods = gameType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					string text = string.Join(", ", Array.ConvertAll(methodInfo.GetParameters(), (ParameterInfo p) => p.ParameterType.Name + " " + p.Name));
					stringBuilder.AppendLine("  " + methodInfo.ReturnType.Name + " " + methodInfo.Name + "(" + text + ")");
				}
				Plugin.Log.LogInfo((object)stringBuilder.ToString());
				MethodInfo method = typeof(UpgradePatch).GetMethod("Prefix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				int num = 0;
				string[] array = new string[12]
				{
					"ButtonToggle", "PlayerUpgrade", "Interact", "Use", "Toggle", "UpgradePlayer", "PressButton", "Purchase", "Buy", "OnInteract",
					"Activate", "Press"
				};
				foreach (string text2 in array)
				{
					MethodInfo method2 = gameType.GetMethod(text2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (!(method2 == null))
					{
						harmony.Patch((MethodBase)method2, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						Plugin.Log.LogInfo((object)("[Patches] ✓ ItemUpgrade." + text2 + "()"));
						num++;
					}
				}
				if (num == 0)
				{
					Plugin.Log.LogError((object)"[Patches] No ItemUpgrade methods matched — check dump above");
				}
				Plugin.Log.LogInfo((object)"[Patches] Applied: UpgradePatch");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[Patches] Upgrade patch failed: " + ex.Message));
			}
		}

		private static Type GetGameType(string name)
		{
			return Type.GetType(name + ", Assembly-CSharp");
		}
	}
	public static class PlayerControllerPatch
	{
		private static readonly Dictionary<string, FieldInfo> _fieldCache = new Dictionary<string, FieldInfo>();

		public static void Prefix(object __instance)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Plugin.EnsureUpdaterCreated();
			try
			{
				if (ChallengeManager.CartLeashActive)
				{
					Component val = (Component)((__instance is Component) ? __instance : null);
					if ((Object)(object)val != (Object)null)
					{
						ChallengeManager.CheckCartLeash(val.transform.position);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[PlayerControllerPatch.Prefix] " + ex.Message));
			}
		}

		public static void Postfix(object __instance)
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Type type = __instance.GetType();
				if (ChallengeManager.NoCrouchActive && ChallengeManager.InMapLevel)
				{
					SetBool(__instance, type, "Crouching", val: false);
					SetBool(__instance, type, "Crawling", val: false);
					SetBool(__instance, type, "toggleCrouch", val: false);
					SetBool(__instance, type, "previousCrouchingState", val: false);
					SetBool(__instance, type, "previousCrawlingState", val: false);
				}
				if (ChallengeManager.NoSprintActive && ChallengeManager.InMapLevel)
				{
					SetBool(__instance, type, "sprinting", val: false);
					SetBool(__instance, type, "toggleSprint", val: false);
					SetBool(__instance, type, "previousSprintingState", val: false);
					SetFloat(__instance, type, "SprintSpeedLerp", 0f);
				}
				float cartLeashSlowFactor = ChallengeManager.CartLeashSlowFactor;
				if (!ChallengeManager.CartLeashActive || !(cartLeashSlowFactor > 0f))
				{
					return;
				}
				Component val = (Component)((__instance is Component) ? __instance : null);
				if (!((Object)(object)val != (Object)null))
				{
					return;
				}
				Vector3 val2 = ChallengeManager.NearestCartPos - val.transform.position;
				val2.y = 0f;
				float magnitude = ((Vector3)(ref val2)).magnitude;
				float value = Plugin.CartLeashMaxDistance.Value;
				if (cartLeashSlowFactor >= 1f && magnitude > value && magnitude > 0.001f)
				{
					Vector3 position = ChallengeManager.NearestCartPos - ((Vector3)(ref val2)).normalized * value;
					position.y = val.transform.position.y;
					val.transform.position = position;
				}
				else
				{
					if (!(cartLeashSlowFactor > 0f) || !(cartLeashSlowFactor < 1f) || !(magnitude > 0.001f))
					{
						return;
					}
					Rigidbody component = val.GetComponent<Rigidbody>();
					if ((Object)(object)component != (Object)null)
					{
						Vector3 normalized = ((Vector3)(ref val2)).normalized;
						Vector3 velocity = component.velocity;
						Vector3 val3 = default(Vector3);
						((Vector3)(ref val3))..ctor(velocity.x, 0f, velocity.z);
						float num = Vector3.Dot(val3, -normalized);
						if (num > 0f)
						{
							val3 -= -normalized * num * cartLeashSlowFactor;
							component.velocity = new Vector3(val3.x, velocity.y, val3.z);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[PlayerControllerPatch.Postfix] " + ex.Message));
			}
		}

		private static FieldInfo CachedField(Type t, string name)
		{
			if (!_fieldCache.TryGetValue(name, out var value))
			{
				value = t.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				_fieldCache[name] = value;
			}
			return value;
		}

		private static void SetBool(object inst, Type t, string name, bool val)
		{
			CachedField(t, name)?.SetValue(inst, val);
		}

		private static void SetFloat(object inst, Type t, string name, float val)
		{
			CachedField(t, name)?.SetValue(inst, val);
		}
	}
	public static class MapPatch
	{
		public static bool Prefix()
		{
			if (ChallengeManager.NoMapActive)
			{
				return !ChallengeManager.InMapLevel;
			}
			return true;
		}
	}
	public static class HealthPackPatch
	{
		public static bool Prefix()
		{
			if (!ChallengeManager.NoHealthPackActive)
			{
				return true;
			}
			ChallengeHUD.ShowViolation("NO HEALTH PACK! Challenge active!");
			return false;
		}
	}
	public static class UpgradePatch
	{
		public static bool Prefix(MethodBase __originalMethod, object[] __args)
		{
			if (!ChallengeManager.NoUpgradesActive)
			{
				return true;
			}
			if (__originalMethod?.Name == "PlayerUpgrade" && __args != null && __args.Length != 0)
			{
				try
				{
					object obj = __args[0];
					object obj2 = obj?.GetType().GetProperty("Sender")?.GetValue(obj);
					if (obj2?.GetType().GetProperty("IsLocal")?.GetValue(obj2) as bool? == false)
					{
						return true;
					}
				}
				catch
				{
				}
			}
			Plugin.LogVerbose("[UpgradePatch] Blocked: " + __originalMethod?.Name);
			ChallengeHUD.ShowViolation("NO UPGRADES! Challenge active!");
			return false;
		}
	}
	public static class GrabPatch
	{
		private static readonly HashSet<int> _violatedItems = new HashSet<int>();

		private static bool _disengageDumped = false;

		private static FieldInfo _grabObjField;

		private static bool _grabObjFieldResolved;

		private static Type _grabVoType;

		private static FieldInfo _grabDollarField;

		private static bool _grabVoResolved;

		private static Type[] _weaponTypes;

		private static readonly Dictionary<int, bool> _weaponVerdicts = new Dictionary<int, bool>();

		private static bool _weaponDumped = false;

		public static bool Prefix(object __instance)
		{
			bool flag = ChallengeManager.FrugalActive && ChallengeManager.InMapLevel;
			bool flag2 = ChallengeManager.ExpensiveOnlyActive && ChallengeManager.InMapLevel;
			bool pacifistActive = ChallengeManager.PacifistActive;
			if (!flag && !flag2 && !pacifistActive)
			{
				return true;
			}
			try
			{
				GameObject grabbedObject = GetGrabbedObject(__instance);
				if ((Object)(object)grabbedObject == (Object)null)
				{
					return true;
				}
				int instanceID = ((Object)grabbedObject).GetInstanceID();
				if (flag || flag2)
				{
					int itemValue = GetItemValue(grabbedObject);
					if (itemValue >= 0)
					{
						int value = Plugin.ExpensiveItemThreshold.Value;
						if ((!flag || itemValue < value) && (!flag2 || itemValue >= value))
						{
							_violatedItems.Remove(instanceID);
						}
						else
						{
							if (_violatedItems.Add(instanceID))
							{
								string text = (ChallengeManager.FrugalActive ? $"FRUGAL: Too expensive! (${itemValue})" : $"EXPENSIVE ONLY: Too cheap! (${itemValue})");
								Plugin.LogVerbose("[GrabPatch] " + text);
								ChallengeHUD.ShowViolation(text);
							}
							ForceRelease(__instance);
						}
					}
				}
				if (pacifistActive && IsWeapon(grabbedObject))
				{
					if (_violatedItems.Add(instanceID))
					{
						Plugin.LogVerbose("[GrabPatch] PACIFIST: weapon grab blocked (" + ((Object)grabbedObject).name + ")");
						ChallengeHUD.ShowViolation("PACIFIST! No weapons!");
					}
					ForceRelease(__instance);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[GrabPatch] " + ex.Message));
			}
			return true;
		}

		private static void ForceRelease(object grabber)
		{
			try
			{
				Type type = grabber.GetType();
				FieldInfo field = type.GetField("grabbedPhysGrabObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				MethodInfo methodInfo = null;
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo2 in methods)
				{
					if (methodInfo2.Name == "disengagePhysGrabObject")
					{
						methodInfo = methodInfo2;
						break;
					}
				}
				if (methodInfo != null)
				{
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (!_disengageDumped)
					{
						_disengageDumped = true;
						string text = string.Join(", ", Array.ConvertAll(parameters, (ParameterInfo p) => p.ParameterType.Name + " " + p.Name));
						Plugin.Log.LogInfo((object)("[GrabPatch] disengagePhysGrabObject(" + text + ")"));
					}
					if (parameters.Length == 0)
					{
						methodInfo.Invoke(grabber, null);
						return;
					}
					if (parameters.Length == 1)
					{
						object obj = field?.GetValue(grabber);
						methodInfo.Invoke(grabber, new object[1] { obj });
						return;
					}
				}
				field?.SetValue(grabber, null);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[ForceRelease] " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private static GameObject GetGrabbedObject(object grabber)
		{
			if (!_grabObjFieldResolved)
			{
				_grabObjFieldResolved = true;
				Type type = grabber.GetType();
				string[] array = new string[5] { "grabbedPhysGrabObject", "physGrabObject", "grabObject", "currentGrabObject", "grabbedObject" };
				foreach (string name in array)
				{
					FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (field != null)
					{
						_grabObjField = field;
						break;
					}
				}
			}
			if (_grabObjField == null)
			{
				return null;
			}
			object value = _grabObjField.GetValue(grabber);
			Component val = (Component)((value is Component) ? value : null);
			if (val != null)
			{
				return val.gameObject;
			}
			GameObject val2 = (GameObject)((value is GameObject) ? value : null);
			if (val2 != null)
			{
				return val2;
			}
			return null;
		}

		private static int GetItemValue(GameObject go)
		{
			if (!_grabVoResolved)
			{
				_grabVoResolved = true;
				_grabVoType = Type.GetType("ValuableObject, Assembly-CSharp");
				if (_grabVoType != null)
				{
					_grabDollarField = _grabVoType.GetField("dollarValueCurrent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
			}
			if (_grabVoType == null || _grabDollarField == null)
			{
				return -1;
			}
			Component component = go.GetComponent(_grabVoType);
			if ((Object)(object)component == (Object)null)
			{
				return -1;
			}
			object value = _grabDollarField.GetValue(component);
			if (value is float num)
			{
				return (int)num;
			}
			if (value is int)
			{
				return (int)value;
			}
			return -1;
		}

		private static bool IsWeapon(GameObject go)
		{
			int instanceID = ((Object)go).GetInstanceID();
			if (_weaponVerdicts.TryGetValue(instanceID, out var value))
			{
				return value;
			}
			if (_weaponTypes == null)
			{
				List<Type> list = new List<Type>();
				string[] array = new string[9] { "ItemGun", "ItemWeapon", "ItemMelee", "ItemRevolver", "ItemShotgun", "ItemRifle", "ItemCrossbow", "ItemGrenade", "ItemGrenadeStun" };
				for (int i = 0; i < array.Length; i++)
				{
					Type type = Type.GetType(array[i] + ", Assembly-CSharp");
					if (type != null)
					{
						list.Add(type);
					}
				}
				_weaponTypes = list.ToArray();
			}
			bool flag = false;
			Type[] weaponTypes = _weaponTypes;
			foreach (Type type2 in weaponTypes)
			{
				if ((Object)(object)go.GetComponent(type2) != (Object)null)
				{
					flag = true;
					break;
				}
			}
			if (!flag && !_weaponDumped)
			{
				_weaponDumped = true;
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("[GrabPatch] Components on '" + ((Object)go).name + "' (pacifist dump):");
				Component[] components = go.GetComponents<Component>();
				for (int i = 0; i < components.Length; i++)
				{
					stringBuilder.AppendLine("  " + ((object)components[i])?.GetType().Name);
				}
				Plugin.Log.LogInfo((object)stringBuilder.ToString());
			}
			_weaponVerdicts[instanceID] = flag;
			return flag;
		}

		internal static void OnRoundStart()
		{
			_weaponVerdicts.Clear();
		}
	}
	public static class ItemDamagePatch
	{
		private struct ValueWatch
		{
			public Component Pg;

			public object Detector;

			public float PreValue;

			public float Deadline;

			public bool HolderIsLocal;

			public int HolderActor;
		}

		private static readonly HashSet<int> _warnedThisRound = new HashSet<int>();

		private static bool _prefixHeld = false;

		private static bool _prefixHolderIsLocal = false;

		private static int _prefixHolderActor = -1;

		private static float _flawlessLastBreak = -10f;

		private static float _empathyNextHit = 0f;

		private static float _nitroLastExplosion = -10f;

		private static Component _empathyComp;

		private static MethodInfo _empathyMethod;

		private static FieldInfo _empathyField;

		private static bool _empathyMethodIsFloat;

		private static bool _empathyFieldIsFloat;

		private static bool _explosionResolved;

		private static MethodInfo _explosionMethod;

		private static int _explosionParamCount;

		private static FieldInfo _pgField;

		private static bool _pgFieldResolved;

		private static FieldInfo _isValField;

		private static bool _isValResolved;

		private static Type _voType;

		private static FieldInfo _dollarField;

		private static bool _voResolved;

		private static readonly List<ValueWatch> _watches = new List<ValueWatch>();

		private const float WATCH_WINDOW = 0.75f;

		private static Type _physGrabberType;

		private static FieldInfo _grabbedField;

		private static FieldInfo _grabberIsLocalField;

		private static bool _grabberFieldsResolved;

		private static Object[] _grabbers;

		private static float _grabbersNextRefresh = 0f;

		private static Type _pgType;

		private static Type _detType;

		private static readonly Dictionary<int, Component> _voCache = new Dictionary<int, Component>();

		public static void ClearDestroyedSet()
		{
			_warnedThisRound.Clear();
			_watches.Clear();
		}

		private static bool FindHolder(Component pg, out bool isLocal, out int actor)
		{
			isLocal = false;
			actor = -1;
			try
			{
				if (_physGrabberType == null)
				{
					_physGrabberType = Type.GetType("PhysGrabber, Assembly-CSharp");
				}
				if (_physGrabberType == null)
				{
					return false;
				}
				if (!_grabberFieldsResolved)
				{
					_grabberFieldsResolved = true;
					_grabbedField = _physGrabberType.GetField("grabbedPhysGrabObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_grabberIsLocalField = _physGrabberType.GetField("isLocal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if (_grabbedField == null)
				{
					return false;
				}
				float unscaledTime = Time.unscaledTime;
				if (_grabbers == null || unscaledTime >= _grabbersNextRefresh)
				{
					_grabbers = Object.FindObjectsOfType(_physGrabberType);
					_grabbersNextRefresh = unscaledTime + 2f;
				}
				Component val = null;
				Object[] grabbers = _grabbers;
				bool flag = default(bool);
				foreach (Object obj in grabbers)
				{
					Component val2 = (Component)(object)((obj is Component) ? obj : null);
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					object? value = _grabbedField.GetValue(val2);
					Component val3 = (Component)((value is Component) ? value : null);
					if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3 != (Object)(object)pg))
					{
						object obj2 = _grabberIsLocalField?.GetValue(val2);
						int num;
						if (obj2 is bool)
						{
							flag = (bool)obj2;
							num = 1;
						}
						else
						{
							num = 0;
						}
						if (((uint)num & (flag ? 1u : 0u)) != 0)
						{
							isLocal = true;
							return true;
						}
						val = val2;
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					PhotonView componentInParent = val.GetComponentInParent<PhotonView>();
					if ((Object)(object)componentInParent != (Object)null)
					{
						actor = componentInParent.OwnerActorNr;
						return true;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[FindHolder] " + ex.Message));
			}
			return false;
		}

		public static bool Prefix(object __instance, MethodBase __originalMethod, ref float __state)
		{
			__state = -1f;
			_prefixHeld = false;
			string text = __originalMethod?.Name;
			if (text != "ImpactHeavy" && text != "ImpactMedium")
			{
				return true;
			}
			if (!ChallengeManager.InMapLevel)
			{
				return true;
			}
			bool flag = ChallengeManager.FlawlessActive || ChallengeManager.NitroFingersActive || ChallengeManager.EmpathyActive;
			bool flag2 = PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient;
			if (!flag && !flag2)
			{
				return true;
			}
			try
			{
				Component physGrabObject = GetPhysGrabObject(__instance);
				if ((Object)(object)physGrabObject == (Object)null)
				{
					return true;
				}
				if (!IsValuable(physGrabObject))
				{
					return true;
				}
				if (!FindHolder(physGrabObject, out var isLocal, out var actor))
				{
					return true;
				}
				if (isLocal && !flag)
				{
					return true;
				}
				if (!isLocal && (!flag2 || actor < 0))
				{
					return true;
				}
				_prefixHeld = true;
				_prefixHolderIsLocal = isLocal;
				_prefixHolderActor = actor;
				__state = ReadItemDollarValue(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[ItemDamagePatch.Prefix] " + ex.Message));
			}
			return true;
		}

		public static void Postfix(object __instance, MethodBase __originalMethod, float __state)
		{
			if (!_prefixHeld)
			{
				return;
			}
			string text = __originalMethod?.Name;
			if (text != "ImpactHeavy" && text != "ImpactMedium")
			{
				return;
			}
			try
			{
				Component physGrabObject = GetPhysGrabObject(__instance);
				if (!((Object)(object)physGrabObject == (Object)null))
				{
					float num = ReadItemDollarValue(__instance);
					Plugin.LogVerbose($"[Impact] {text} {((Object)physGrabObject.gameObject).name} value {__state:F0} -> {num:F0}" + (_prefixHolderIsLocal ? "" : $" (held by actor {_prefixHolderActor})"));
					if (__state >= 0f && num >= 0f && num < __state - 0.01f)
					{
						FireOrRelay(__instance, physGrabObject, _prefixHolderIsLocal, _prefixHolderActor);
					}
					else if (text == "ImpactHeavy")
					{
						FireOrRelay(__instance, physGrabObject, _prefixHolderIsLocal, _prefixHolderActor);
					}
					else if (__state >= 0f && num >= 0f)
					{
						AddWatch(physGrabObject, __instance, __state, _prefixHolderIsLocal, _prefixHolderActor);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[ItemDamagePatch.Postfix] " + ex.Message));
			}
		}

		private static void FireOrRelay(object detector, Component pg, bool holderIsLocal, int holderActor)
		{
			if (holderIsLocal)
			{
				FireEffects(detector, pg);
				return;
			}
			PhotonView val = (((Object)(object)pg != (Object)null) ? pg.GetComponentInParent<PhotonView>() : null);
			if ((Object)(object)val != (Object)null)
			{
				ChallengeSync.RelayImpactToHolder(holderActor, val.ViewID);
			}
		}

		internal static void OnRelayedImpact(int viewID)
		{
			try
			{
				PhotonView val = PhotonView.Find(viewID);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				if (_pgType == null)
				{
					_pgType = Type.GetType("PhysGrabObject, Assembly-CSharp");
				}
				if (_detType == null)
				{
					_detType = Type.GetType("PhysGrabObjectImpactDetector, Assembly-CSharp");
				}
				Component val2 = ((_pgType != null) ? ((Component)val).GetComponent(_pgType) : null);
				object obj = null;
				if (_detType != null)
				{
					obj = ((Component)val).GetComponent(_detType);
					if (obj == null)
					{
						obj = ((Component)val).GetComponentInChildren(_detType);
					}
				}
				Component val3 = (Component)(((Object)(object)val2 != (Object)null) ? ((object)val2) : ((object)val));
				Plugin.LogVerbose("[ItemDamagePatch] Relayed impact: " + ((Object)val3.gameObject).name);
				FireEffects(obj, val3);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[OnRelayedImpact] " + ex.Message));
			}
		}

		internal static void DestroyByViewID(int viewID)
		{
			try
			{
				PhotonView val = PhotonView.Find(viewID);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				if (_detType == null)
				{
					_detType = Type.GetType("PhysGrabObjectImpactDetector, Assembly-CSharp");
				}
				if (_detType == null)
				{
					return;
				}
				object obj = ((Component)val).GetComponent(_detType);
				if (obj == null)
				{
					obj = ((Component)val).GetComponentInChildren(_detType);
				}
				if (obj != null)
				{
					if (_pgType == null)
					{
						_pgType = Type.GetType("PhysGrabObject, Assembly-CSharp");
					}
					Component val2 = ((_pgType != null) ? ((Component)val).GetComponent(_pgType) : null);
					DestroyValuable(obj, obj.GetType(), (Component)(((Object)(object)val2 != (Object)null) ? ((object)val2) : ((object)val)));
					Plugin.Log.LogWarning((object)("[Flawless] Destroyed " + ((Object)((Component)val).gameObject).name + " (remote holder request)"));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[DestroyByViewID] " + ex.Message));
			}
		}

		internal static void FireEffects(object detector, Component pg)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)pg != (Object)null) ? pg.transform.position : Vector3.zero);
			float time = Time.time;
			bool flag = PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient;
			if (ChallengeManager.FlawlessActive && (Object)(object)pg != (Object)null)
			{
				int instanceID = ((Object)pg.gameObject).GetInstanceID();
				if (_warnedThisRound.Add(instanceID) && time - _flawlessLastBreak >= 0.3f)
				{
					_flawlessLastBreak = time;
					if (flag)
					{
						PhotonView componentInParent = pg.GetComponentInParent<PhotonView>();
						if ((Object)(object)componentInParent != (Object)null)
						{
							ChallengeSync.RequestDestroy(componentInParent.ViewID);
						}
					}
					else if (detector != null)
					{
						DestroyValuable(detector, detector.GetType(), pg);
					}
					Plugin.Log.LogWarning((object)("[Flawless] Destroyed " + ((Object)pg.gameObject).name + " (value dropped)"));
					ChallengeManager.OnItemDamaged(((Object)pg.gameObject).name);
				}
			}
			if (ChallengeManager.NitroFingersActive && time - _nitroLastExplosion >= 0.5f)
			{
				_nitroLastExplosion = time;
				if (flag)
				{
					ChallengeSync.RequestExplosion(val);
				}
				else
				{
					TrySpawnExplosion(val);
				}
				if ((Object)(object)pg != (Object)null)
				{
					ChallengeHUD.ShowViolation("BOOM! " + ((Object)pg.gameObject).name);
				}
				Plugin.LogVerbose($"[NitroFingers] Explosion at {val}");
			}
			if (ChallengeManager.EmpathyActive && time >= _empathyNextHit)
			{
				_empathyNextHit = time + 0.5f;
				DamageLocalPlayer(Plugin.EmpathyDamagePerHit.Value);
				ChallengeManager.OnEmpathyHit();
			}
		}

		private static void AddWatch(Component pg, object detector, float preValue, bool holderIsLocal, int holderActor)
		{
			float deadline = Time.time + 0.75f;
			for (int i = 0; i < _watches.Count; i++)
			{
				if ((Object)(object)_watches[i].Pg == (Object)(object)pg)
				{
					ValueWatch value = _watches[i];
					if (preValue > value.PreValue)
					{
						value.PreValue = preValue;
					}
					value.Deadline = deadline;
					value.HolderIsLocal = holderIsLocal;
					value.HolderActor = holderActor;
					_watches[i] = value;
					return;
				}
			}
			_watches.Add(new ValueWatch
			{
				Pg = pg,
				Detector = detector,
				PreValue = preValue,
				Deadline = deadline,
				HolderIsLocal = holderIsLocal,
				HolderActor = holderActor
			});
		}

		internal static void TickWatches()
		{
			if (_watches.Count == 0)
			{
				return;
			}
			float time = Time.time;
			for (int num = _watches.Count - 1; num >= 0; num--)
			{
				ValueWatch valueWatch = _watches[num];
				if ((Object)(object)valueWatch.Pg == (Object)null)
				{
					_watches.RemoveAt(num);
				}
				else
				{
					float num2 = ReadItemDollarValue(valueWatch.Detector);
					if (num2 >= 0f && num2 < valueWatch.PreValue - 0.01f)
					{
						Plugin.LogVerbose($"[Impact] delayed drop {((Object)valueWatch.Pg.gameObject).name} {valueWatch.PreValue:F0} -> {num2:F0}");
						FireOrRelay(valueWatch.Detector, valueWatch.Pg, valueWatch.HolderIsLocal, valueWatch.HolderActor);
						_watches.RemoveAt(num);
					}
					else if (time > valueWatch.Deadline)
					{
						_watches.RemoveAt(num);
					}
				}
			}
		}

		private static Component GetPhysGrabObject(object detector)
		{
			if (!_pgFieldResolved)
			{
				_pgFieldResolved = true;
				_pgField = detector.GetType().GetField("physGrabObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
			object? obj = _pgField?.GetValue(detector);
			return (Component)((obj is Component) ? obj : null);
		}

		private static bool IsValuable(Component pg)
		{
			if (!_isValResolved)
			{
				_isValResolved = true;
				_isValField = ((object)pg).GetType().GetField("isValuable", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
			object obj = _isValField?.GetValue(pg);
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		private static void DestroyValuable(object detector, Type detType, Component pg)
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			MethodInfo method = detType.GetMethod("DestroyObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(bool) }, null);
			if (method != null)
			{
				try
				{
					method.Invoke(detector, new object[1] { true });
					return;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("[Flawless] DestroyObject threw: " + ex.Message));
				}
			}
			MethodInfo method2 = detType.GetMethod("Break", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[4]
			{
				typeof(float),
				typeof(Vector3),
				typeof(int),
				typeof(bool)
			}, null);
			if (method2 != null)
			{
				try
				{
					method2.Invoke(detector, new object[4]
					{
						999999f,
						pg.transform.position,
						0,
						true
					});
					return;
				}
				catch (Exception ex2)
				{
					Plugin.Log.LogWarning((object)("[Flawless] Break() threw: " + ex2.Message));
				}
			}
			try
			{
				Object.Destroy((Object)(object)pg.gameObject);
			}
			catch (Exception ex3)
			{
				Plugin.Log.LogWarning((object)("[Flawless] GameObject destroy threw: " + ex3.Message));
			}
		}

		internal static void TrySpawnExplosion(Vector3 pos)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			if (_explosionResolved)
			{
				if (_explosionMethod != null)
				{
					try
					{
						_explosionMethod.Invoke(null, (_explosionParamCount != 1) ? new object[2] { pos, 10f } : new object[1] { pos });
						return;
					}
					catch
					{
					}
				}
				PhysicsExplosion(pos);
				return;
			}
			string[] array = new string[6] { "Explosion", "ExplosionCustom", "ExplosionManager", "GrenadeBoom", "GrenadeExplosion", "ItemExplosion" };
			foreach (string text in array)
			{
				Type type = Type.GetType(text + ", Assembly-CSharp");
				if (type == null)
				{
					continue;
				}
				MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (methodInfo.Name != "Spawn" && methodInfo.Name != "Create" && methodInfo.Name != "SpawnExplosion" && methodInfo.Name != "CreateExplosion" && methodInfo.Name != "Explode")
					{
						continue;
					}
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (parameters.Length != 0 && !(parameters[0].ParameterType != typeof(Vector3)))
					{
						try
						{
							methodInfo.Invoke(null, (parameters.Length != 1) ? new object[2] { pos, 10f } : new object[1] { pos });
							_explosionResolved = true;
							_explosionMethod = methodInfo;
							_explosionParamCount = parameters.Length;
							Plugin.Log.LogInfo((object)("[Flawless] Explosion via " + text + "." + methodInfo.Name + "() (cached)"));
							return;
						}
						catch (Exception ex)
						{
							Plugin.Log.LogWarning((object)("[Flawless] " + text + "." + methodInfo.Name + " threw: " + ex.Message));
						}
					}
				}
			}
			_explosionResolved = true;
			_explosionMethod = null;
			Plugin.Log.LogInfo((object)"[Flawless] No explosion API — using physics impulse fallback (cached).");
			PhysicsExplosion(pos);
		}

		private static void PhysicsExplosion(Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			Collider[] array = Physics.OverlapSphere(pos, 3f);
			int num = 0;
			Collider[] array2 = array;
			foreach (Collider val in array2)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Rigidbody attachedRigidbody = val.attachedRigidbody;
					if ((Object)(object)attachedRigidbody != (Object)null && !attachedRigidbody.isKinematic)
					{
						attachedRigidbody.AddExplosionForce(600f, pos, 3f, 1f, (ForceMode)1);
						num++;
					}
				}
			}
			if (num > 0)
			{
				Plugin.LogVerbose($"[Flawless] Physics explosion — pushed {num} rigidbodies");
			}
		}

		internal static void ClearValueCache()
		{
			_voCache.Clear();
		}

		private static float ReadItemDollarValue(object impactDetector)
		{
			try
			{
				Component val = (Component)((impactDetector is Component) ? impactDetector : null);
				if ((Object)(object)val == (Object)null)
				{
					return -1f;
				}
				if (!_voResolved)
				{
					_voResolved = true;
					_voType = Type.GetType("ValuableObject, Assembly-CSharp");
					if (_voType != null)
					{
						_dollarField = _voType.GetField("dollarValueCurrent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					}
				}
				if (_voType == null || _dollarField == null)
				{
					return -1f;
				}
				int instanceID = ((Object)val).GetInstanceID();
				if (!_voCache.TryGetValue(instanceID, out var value) || (Object)(object)value == (Object)null)
				{
					Transform val2 = val.transform;
					while ((Object)(object)val2.parent != (Object)null)
					{
						val2 = val2.parent;
					}
					value = ((Component)val2).GetComponentInChildren(_voType);
					_voCache[instanceID] = value;
				}
				if ((Object)(object)value == (Object)null)
				{
					return -1f;
				}
				object value2 = _dollarField.GetValue(value);
				if (value2 is float result)
				{
					return result;
				}
				if (value2 is int num)
				{
					return num;
				}
			}
			catch
			{
			}
			return -1f;
		}

		internal static void DamageLocalPlayer(float amount)
		{
			try
			{
				if ((Object)(object)_empathyComp != (Object)null)
				{
					if (ApplyEmpathyDamage(amount))
					{
						return;
					}
					_empathyComp = null;
					_empathyMethod = null;
					_empathyField = null;
				}
				Type type = Type.GetType("PlayerAvatar, Assembly-CSharp");
				if (type == null)
				{
					Plugin.Log.LogWarning((object)"[Empathy] PlayerAvatar type not found");
					return;
				}
				FieldInfo field = type.GetField("isLocal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				Component val = null;
				Component[] array = Object.FindObjectsOfType(type) as Component[];
				foreach (Component val2 in array)
				{
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					if (field != null)
					{
						object value = field.GetValue(val2);
						if (value is bool && !(bool)value)
						{
							continue;
						}
					}
					val = val2;
					break;
				}
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)"[Empathy] Local PlayerAvatar not found");
					return;
				}
				array = val.gameObject.GetComponents<Component>();
				foreach (Component val3 in array)
				{
					if ((Object)(object)val3 == (Object)null)
					{
						continue;
					}
					Type type2 = ((object)val3).GetType();
					string[] array2 = new string[7] { "HurtLocal", "Hurt", "TakeDamage", "DealDamage", "HurtPlayer", "ApplyDamage", "Damage" };
					foreach (string text in array2)
					{
						MethodInfo method = type2.GetMethod(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(float) }, null);
						if (method != null)
						{
							_empathyComp = val3;
							_empathyMethod = method;
							_empathyMethodIsFloat = true;
							Plugin.Log.LogInfo((object)("[Empathy] Damage via " + type2.Name + "." + text + "(float) (cached)"));
							ApplyEmpathyDamage(amount);
							return;
						}
						MethodInfo method2 = type2.GetMethod(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null);
						if (method2 != null)
						{
							_empathyComp = val3;
							_empathyMethod = method2;
							_empathyMethodIsFloat = false;
							Plugin.Log.LogInfo((object)("[Empathy] Damage via " + type2.Name + "." + text + "(int) (cached)"));
							ApplyEmpathyDamage(amount);
							return;
						}
					}
					array2 = new string[7] { "health", "hp", "currentHealth", "playerHealth", "hitPoints", "HP", "maxHealth" };
					foreach (string text2 in array2)
					{
						FieldInfo field2 = type2.GetField(text2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						if (!(field2 == null))
						{
							object value2 = field2.GetValue(val3);
							if (value2 is float || value2 is int)
							{
								_empathyComp = val3;
								_empathyField = field2;
								_empathyFieldIsFloat = value2 is float;
								Plugin.Log.LogInfo((object)("[Empathy] Damage via field " + type2.Name + "." + text2 + " (cached)"));
								ApplyEmpathyDamage(amount);
								return;
							}
						}
					}
				}
				Plugin.Log.LogWarning((object)"[Empathy] No damage method/field found.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[DamageLocalPlayer] " + ex.Message));
			}
		}

		private static bool ApplyEmpathyDamage(float amount)
		{
			if ((Object)(object)_empathyComp == (Object)null)
			{
				return false;
			}
			try
			{
				if (_empathyMethod != null)
				{
					_empathyMethod.Invoke(_empathyComp, (!_empathyMethodIsFloat) ? new object[1] { (int)amount } : new object[1] { amount });
					Plugin.LogVerbose($"[Empathy] -{amount}hp (cached method)");
					return true;
				}
				if (_empathyField != null)
				{
					object value = _empathyField.GetValue(_empathyComp);
					if (_empathyFieldIsFloat && value is float num)
					{
						_empathyField.SetValue(_empathyComp, Mathf.Max(0f, num - amount));
					}
					else
					{
						if (_empathyFieldIsFloat || !(value is int num2))
						{
							return false;
						}
						_empathyField.SetValue(_empathyComp, Mathf.Max(0, num2 - (int)amount));
					}
					Plugin.LogVerbose($"[Empathy] -{amount}hp (cached field)");
					return true;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Empathy] cached apply failed: " + ex.Message));
				return false;
			}
			return false;
		}
	}
	public static class ShortRangePatch
	{
		private const string RANGE_FIELD = "grabRange";

		private static float _originalRange = -1f;

		private static float _preChallengeRange = -1f;

		private static float _targetRange = -1f;

		private static bool _challengeWasActive = false;

		private static FieldInfo _isLocalFld;

		private static FieldInfo _rangeFld;

		private static bool _fieldsResolved;

		public static void Postfix(object __instance)
		{
			try
			{
				Type type = __instance.GetType();
				if (!_fieldsResolved)
				{
					_fieldsResolved = true;
					_isLocalFld = type.GetField("isLocal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_rangeFld = type.GetField("grabRange", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if (_isLocalFld != null)
				{
					object value = _isLocalFld.GetValue(__instance);
					if (value is bool && !(bool)value)
					{
						return;
					}
				}
				FieldInfo rangeFld = _rangeFld;
				if (rangeFld == null)
				{
					return;
				}
				float num = (float)rangeFld.GetValue(__instance);
				if (_originalRange < 0f)
				{
					_originalRange = num;
					ChallengeManager.ShortRangeOriginalValue = num;
					Plugin.Log.LogInfo((object)string.Format("[ShortRange] Base grab range = {0:F2} (field: {1})", num, "grabRange"));
				}
				bool shortRangeActive = ChallengeManager.ShortRangeActive;
				if (!shortRangeActive)
				{
					ChallengeManager.ShortRangeCurrentValue = num;
				}
				if (!shortRangeActive)
				{
					if (_challengeWasActive)
					{
						_challengeWasActive = false;
						if (_preChallengeRange >= 0f)
						{
							rangeFld.SetValue(__instance, _preChallengeRange);
						}
						Plugin.Log.LogInfo((object)$"[ShortRange] Ended — range restored to {_preChallengeRange:F2}");
						_targetRange = -1f;
						_preChallengeRange = -1f;
					}
					return;
				}
				if (!_challengeWasActive)
				{
					_challengeWasActive = true;
					_preChallengeRange = num;
					float num2 = (float)Plugin.ShortRangeReductionPercent.Value / 100f;
					_targetRange = (Plugin.ShortRangeUseOriginal.Value ? _originalRange : num) * (1f - num2);
					Plugin.Log.LogInfo((object)($"[ShortRange] Activated — original={_originalRange:F2} " + $"current={num:F2} useOriginal={Plugin.ShortRangeUseOriginal.Value} " + $"reduction={num2 * 100f:F0}% target={_targetRange:F2}"));
				}
				if (num != _targetRange)
				{
					rangeFld.SetValue(__instance, _targetRange);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[ShortRangePatch] " + ex.Message));
			}
		}
	}
	public static class LevelStartPatch
	{
		public static void Postfix()
		{
			try
			{
				Plugin.Log.LogInfo((object)"[LevelStartPatch] GameDirector.SetStart fired.");
				ChallengeManager.OnRoundStart();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[LevelStartPatch] FAILED: " + ex.Message + "\n" + ex.StackTrace));
			}
		}
	}
	internal static class HeldItemTicker
	{
		public static void Tick()
		{
			ItemDamagePatch.TickWatches();
		}

		public static void OnRoundStart()
		{
		}

		public static void OnSceneLoad()
		{
		}
	}
	[BepInPlugin("com.gynxz.repochallenges", "Gynxz: RepoChallenges", "1.4.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "com.gynxz.repochallenges";

		public const string MOD_NAME = "Gynxz: RepoChallenges";

		public const string VERSION = "1.4.0";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal static bool Ready = false;

		internal static bool UpdaterCreated = false;

		internal static ConfigEntry<bool> DebugKeysEnabled;

		internal static ConfigEntry<bool> VerboseLogging;

		internal static ConfigEntry<KeyboardShortcut> CycleKey;

		internal static ConfigEntry<KeyboardShortcut> ClearKey;

		internal static ConfigEntry<bool> ChallengeScopePerRound;

		internal static ConfigEntry<float> CartLeashMaxDistance;

		internal static ConfigEntry<float> CartLeashSlowStartDistance;

		internal static ConfigEntry<int> CartLeashSlowPercent;

		internal static ConfigEntry<int> ExpensiveItemThreshold;

		internal static ConfigEntry<int> EmpathyDamagePerHit;

		internal static ConfigEntry<bool> AutoAssignOnRoundStart;

		internal static ConfigEntry<bool> ShortRangeUseOriginal;

		internal static ConfigEntry<int> ShortRangeReductionPercent;

		internal static ConfigEntry<bool> HudEnabled;

		internal static ConfigEntry<int> HudPositionX;

		internal static ConfigEntry<int> HudPositionY;

		internal static ConfigEntry<int> HudFontSize;

		internal static ConfigEntry<bool> HudShowDescription;

		internal static ConfigEntry<bool> HudShowOtherPlayers;

		internal static ConfigEntry<bool> SbEnabled;

		internal static ConfigEntry<string> NameAliases;

		internal static ConfigEntry<string> ManualTarget;

		internal static ConfigEntry<string> ManualChallenge;

		internal static ConfigEntry<bool> ManualAssignTrigger;

		internal static ConfigEntry<bool> ManualClearTrigger;

		internal static Dictionary<string, ConfigEntry<ChallengeMode>> RosterModes;

		private static readonly string BASE_PATH = ComputeBasePath();

		public static readonly string CMD_FILE = Path.Combine(BASE_PATH, "challenge_cmd.txt");

		public static readonly string STATUS_FILE = Path.Combine(BASE_PATH, "challenge_status.txt");

		public static readonly string LIST_FILE = Path.Combine(BASE_PATH, "challenge_list.txt");

		public static readonly string PLAYERS_FILE = Path.Combine(BASE_PATH, "challenge_players.txt");

		public static readonly string IDS_FILE = Path.Combine(BASE_PATH, "challenge_ids.txt");

		public static readonly string ALIASES_FILE = Path.Combine(BASE_PATH, "challenge_aliases.txt");

		private Harmony _harmony;

		private float _pollTimer;

		private bool _updateOnce;

		internal const float POLL_INTERVAL = 0.5f;

		private static string _pendingCmd = null;

		internal static ChallengeMode GetMode(string id)
		{
			if (RosterModes != null && RosterModes.TryGetValue(id, out var value))
			{
				return value.Value;
			}
			return ChallengeMode.Off;
		}

		internal static void LogVerbose(string msg)
		{
			if (VerboseLogging != null && VerboseLogging.Value)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)msg);
				}
			}
		}

		private static string ComputeBasePath()
		{
			try
			{
				string text = Directory.GetParent(Paths.BepInExRootPath)?.FullName;
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
			catch
			{
			}
			return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Thunderstore Mod Manager\\DataFolder\\REPO\\profiles\\REPO");
		}

		private void Awake()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			try
			{
				Instance = this;
				Log = ((BaseUnityPlugin)this).Logger;
				BindConfig();
				Log.LogInfo((object)"[Plugin] Config bound.");
				ChallengeRegistry.RegisterAll();
				Log.LogInfo((object)("[Plugin] Registered: " + string.Join(", ", ChallengeRegistry.AllIds())));
				BindRosterConfig();
				BindManualAssign();
				_harmony = new Harmony("com.gynxz.repochallenges");
				Patches.PatchAll(_harmony);
				Log.LogInfo((object)"[Plugin] Patches applied.");
				ChallengeManager.ReconcileRoster();
				if (SbEnabled.Value)
				{
					WriteListFile();
					TryClearCmd();
					WriteStatus();
					Log.LogInfo((object)("[Plugin] File bridge ready. CMD: " + CMD_FILE));
				}
				Ready = true;
				Log.LogInfo((object)"Gynxz: RepoChallenges v1.4.0 ready.");
			}
			catch (Exception ex)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogError((object)("[Plugin] Awake() FAILED: " + ex.Message + "\n" + ex.StackTrace));
				}
			}
		}

		private void OnDestroy()
		{
			Log.LogWarning((object)"[Plugin] OnDestroy() — BepInEx lifecycle, ignoring.");
		}

		private void Update()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (!Ready)
			{
				return;
			}
			if (!_updateOnce)
			{
				_updateOnce = true;
				Log.LogInfo((object)"[Plugin] Update() is alive.");
			}
			if (UpdaterCreated)
			{
				return;
			}
			if (DebugKeysEnabled.Value)
			{
				KeyboardShortcut value = CycleKey.Value;
				if (IsKeyDown(((KeyboardShortcut)(ref value)).MainKey))
				{
					Log.LogInfo((object)"[Plugin] Cycle key pressed.");
					ChallengeManager.CycleChallenge();
				}
				value = ClearKey.Value;
				if (IsKeyDown(((KeyboardShortcut)(ref value)).MainKey))
				{
					Log.LogInfo((object)"[Plugin] Clear key pressed.");
					ChallengeManager.ClearChallenge();
				}
			}
			if (SbEnabled.Value)
			{
				_pollTimer += Time.unscaledDeltaTime;
				if (!(_pollTimer < 0.5f))
				{
					_pollTimer = 0f;
					PollCmdFile();
				}
			}
		}

		internal static void PollCmdFile()
		{
			try
			{
				if (!File.Exists(CMD_FILE))
				{
					return;
				}
				string text = File.ReadAllText(CMD_FILE);
				string text2 = ((text == null) ? "" : text.Trim().ToLowerInvariant());
				if (text2.Length != 0 && !(text2 == _pendingCmd))
				{
					try
					{
						File.WriteAllText(CMD_FILE, "");
						_pendingCmd = null;
					}
					catch
					{
						_pendingCmd = text2;
					}
					Log.LogInfo((object)("[Bridge] Command: '" + text2 + "'"));
					ExecuteBridgeCommand(text2);
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("[Bridge] Poll error: " + ex.Message));
			}
		}

		internal static void ExecuteBridgeCommand(string cmd)
		{
			bool flag = cmd.IndexOf('+') >= 0;
			if (flag)
			{
				cmd = cmd.Replace("+", "");
			}
			string targetName = null;
			string text = null;
			bool flag2 = false;
			bool flag3 = false;
			string[] array = cmd.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim().Trim('<', '>', '"', '\'').Trim();
				if (text2.Length != 0)
				{
					if (text2.StartsWith("player:", StringComparison.Ordinal))
					{
						targetName = text2.Substring(7).Trim().Trim('<', '>')
							.Trim();
					}
					else if (text2.StartsWith("challenge:", StringComparison.Ordinal))
					{
						text = text2.Substring(10).Trim();
					}
					else if (text2 == "clear")
					{
						flag2 = true;
					}
					else if (text2 == "random")
					{
						flag3 = true;
					}
					else
					{
						text = text2;
					}
				}
			}
			if (flag2)
			{
				ChallengeSync.SendClear(targetName);
			}
			else if (flag3)
			{
				ChallengeSync.SendChallenge(targetName, ChallengeRegistry.GetRandom()?.Id ?? "", flag);
			}
			else if (!string.IsNullOrEmpty(text))
			{
				if (!ChallengeRegistry.Has(text))
				{
					Log.LogWarning((object)("[Bridge] Unknown challenge id: '" + text + "'"));
				}
				else
				{
					ChallengeSync.SendChallenge(targetName, text, flag);
				}
			}
			else
			{
				Log.LogWarning((object)("[Bridge] Could not parse command: '" + cmd + "'"));
			}
			WriteStatus();
		}

		private void WriteListFile()
		{
			try
			{
				Directory.CreateDirectory(BASE_PATH);
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("# Valid challenge ids — write one to: " + CMD_FILE);
				stringBuilder.AppendLine("# Special commands: clear, random");
				stringBuilder.AppendLine("# Add a '+' to STACK instead of replace, e.g.: no_map+");
				stringBuilder.AppendLine("# Target a player: player:<name>,challenge:<id>  or  player:<name>,clear");
				stringBuilder.AppendLine();
				foreach (BaseChallenge item in ChallengeRegistry.All)
				{
					stringBuilder.AppendLine($"{item.Id,-20} # {item.DisplayName}");
				}
				File.WriteAllText(LIST_FILE, stringBuilder.ToString());
				StringBuilder stringBuilder2 = new StringBuilder();
				foreach (BaseChallenge item2 in ChallengeRegistry.All)
				{
					stringBuilder2.AppendLine(item2.Id);
				}
				File.WriteAllText(IDS_FILE, stringBuilder2.ToString());
				if (!File.Exists(ALIASES_FILE))
				{
					File.WriteAllText(ALIASES_FILE, "# Twitch/chat name = Steam name — one pair per line (or ; separated).\r\n# Read LIVE: edit this file anytime, even while the game is running.\r\n# Lines starting with # are ignored. Names are not case sensitive.\r\n# Example:\r\n# Kahzimeira=Kahzi\r\n");
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("[Plugin] WriteListFile: " + ex.Message));
			}
		}

		public static void WriteStatus()
		{
			try
			{
				List<BaseChallenge> list = ChallengeManager.ActiveChallenges.ToList();
				string contents = ((list.Count == 0) ? "active: none" : ("active: " + string.Join(", ", list.Select((BaseChallenge a) => a.Id + " | " + a.DisplayName))));
				File.WriteAllText(STATUS_FILE, contents);
			}
			catch
			{
			}
		}

		private static void TryClearCmd()
		{
			try
			{
				File.WriteAllText(CMD_FILE, "");
			}
			catch
			{
			}
		}

		internal static void EnsureUpdaterCreated()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_001f: 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
			if (UpdaterCreated)
			{
				return;
			}
			UpdaterCreated = true;
			try
			{
				if (HudEnabled.Value)
				{
					GameObject val = new GameObject("GynxzChallengeHUD");
					Object.DontDestroyOnLoad((Object)val);
					val.AddComponent<ChallengeHUD>();
					Log.LogInfo((object)"[Plugin] HUD created from gameplay context.");
				}
				GameObject val2 = new GameObject("GynxzChallengeUpdater_Live");
				Object.DontDestroyOnLoad((Object)val2);
				val2.AddComponent<ChallengeUpdater>();
				Log.LogInfo((object)"[Plugin] Updater created from gameplay context.");
				ChallengeSync.Create();
				Log.LogInfo((object)"[Plugin] ChallengeSync created.");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("[Plugin] EnsureUpdaterCreated failed: " + ex.Message));
			}
		}

		internal static bool IsKeyDown(KeyCode kc)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected I4, but got Unknown
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Keyboard current = Keyboard.current;
				if (current != null)
				{
					switch (kc - 256)
					{
					case 26:
						return ((ButtonControl)current.f1Key).wasPressedThisFrame;
					case 27:
						return ((ButtonControl)current.f2Key).wasPressedThisFrame;
					case 28:
						return ((ButtonControl)current.f3Key).wasPressedThisFrame;
					case 29:
						return ((ButtonControl)current.f4Key).wasPressedThisFrame;
					case 30:
						return ((ButtonControl)current.f5Key).wasPressedThisFrame;
					case 31:
						return ((ButtonControl)current.f6Key).wasPressedThisFrame;
					case 32:
						return ((ButtonControl)current.f7Key).wasPressedThisFrame;
					case 33:
						return ((ButtonControl)current.f8Key).wasPressedThisFrame;
					case 34:
						return ((ButtonControl)current.f9Key).wasPressedThisFrame;
					case 35:
						return ((ButtonControl)current.f10Key).wasPressedThisFrame;
					case 36:
						return ((ButtonControl)current.f11Key).wasPressedThisFrame;
					case 37:
						return ((ButtonControl)current.f12Key).wasPressedThisFrame;
					case 0:
						return ((ButtonControl)current.numpad0Key).wasPressedThisFrame;
					case 1:
						return ((ButtonControl)current.numpad1Key).wasPressedThisFrame;
					case 2:
						return ((ButtonControl)current.numpad2Key).wasPressedThisFrame;
					case 3:
						return ((ButtonControl)current.numpad3Key).wasPressedThisFrame;
					case 4:
						return ((ButtonControl)current.numpad4Key).wasPressedThisFrame;
					case 5:
						return ((ButtonControl)current.numpad5Key).wasPressedThisFrame;
					case 6:
						return ((ButtonControl)current.numpad6Key).wasPressedThisFrame;
					case 7:
						return ((ButtonControl)current.numpad7Key).wasPressedThisFrame;
					case 8:
						return ((ButtonControl)current.numpad8Key).wasPressedThisFrame;
					case 9:
						return ((ButtonControl)current.numpad9Key).wasPressedThisFrame;
					case 10:
					case 11:
					case 12:
					case 13:
					case 14:
					case 15:
					case 16:
					case 17:
					case 18:
					case 19:
					case 20:
					case 21:
					case 22:
					case 23:
					case 24:
					case 25:
						break;
					}
				}
			}
			catch
			{
			}
			return Input.GetKeyDown(kc);
		}

		private void BindConfig()
		{
			//IL_003a: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Expected O, but got Unknown
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Expected O, but got Unknown
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Expected O, but got Unknown
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Expected O, but got Unknown
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Expected O, but got Unknown
			DebugKeysEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Debug", "DebugKeysEnabled", true, "Enable F8 (cycle challenge) and F9 (clear challenge) hotkeys.");
			CycleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("0 - Debug", "CycleKey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Cycle through challenges.");
			ClearKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("0 - Debug", "ClearKey", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), "Clear active challenge.");
			VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Debug", "VerboseLogging", false, "Log per-event spam (violations, explosions, grab blocks) to LogOutput.log. Leave OFF for performance — heavy logging during bursts can cause frame hitches.");
			ChallengeScopePerRound = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Challenges", "ChallengeScopePerRound", true, "true = challenge clears at the start of each new level.");
			CartLeashMaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Challenges", "CartLeashMaxDistance", 5f, new ConfigDescription("Distance from cart for full stop.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
			CartLeashSlowStartDistance = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Challenges", "CartLeashSlowStartDistance", 3f, new ConfigDescription("Distance from cart where slowdown begins (must be less than CartLeashMaxDistance).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
			CartLeashSlowPercent = ((BaseUnityPlugin)this).Config.Bind<int>("1 - Challenges", "CartLeashSlowPercent", 50, new ConfigDescription("Speed reduction % in the slow zone between SlowStart and MaxDistance.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			ExpensiveItemThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("1 - Challenges", "ExpensiveItemThreshold", 5000, new ConfigDescription("Value threshold for Frugal/ExpensiveOnly.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 100000), Array.Empty<object>()));
			ShortRangeUseOriginal = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Challenges", "ShortRangeUseOriginal", true, "true = reduction is based on the original base grab range (ignores upgrades). false = reduction is based on the current grab range at the time the challenge is assigned.");
			ShortRangeReductionPercent = ((BaseUnityPlugin)this).Config.Bind<int>("1 - Challenges", "ShortRangeReductionPercent", 50, new ConfigDescription("Percentage to reduce grab range for the Short Range challenge.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 99), Array.Empty<object>()));
			EmpathyDamagePerHit = ((BaseUnityPlugin)this).Config.Bind<int>("1 - Challenges", "EmpathyDamagePerHit", 5, new ConfigDescription("HP the Empathetic challenge deals to you per item hit.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
			AutoAssignOnRoundStart = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Challenges", "AutoAssignOnRoundStart", false, "Auto-assign random challenge each level.");
			HudEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - HUD", "Enabled", true, "Show challenge HUD.");
			HudPositionX = ((BaseUnityPlugin)this).Config.Bind<int>("2 - HUD", "PositionX", 12, "Horizontal offset.");
			HudPositionY = ((BaseUnityPlugin)this).Config.Bind<int>("2 - HUD", "PositionY", 12, "Vertical offset.");
			HudFontSize = ((BaseUnityPlugin)this).Config.Bind<int>("2 - HUD", "FontSize", 18, new ConfigDescription("HUD font size.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 40), Array.Empty<object>()));
			HudShowDescription = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - HUD", "ShowDescription", true, "Show challenge description.");
			HudShowOtherPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - HUD", "ShowOtherPlayers", true, "Show other players challenges.");
			SbEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Streamer.bot Integration", "Enabled", true, "Watch challenge_cmd.txt for commands.");
			NameAliases = ((BaseUnityPlugin)this).Config.Bind<string>("4 - Streamer.bot Integration", "NameAliases", "", "Map chat/Twitch names to in-game Steam names so player-targeted commands resolve. Format: TwitchName=SteamName, pairs separated by ';', ',' or new lines. Not case sensitive. Example: Kahzimeira=Kahzi; Bob123=Bobby");
		}

		private void BindRosterConfig()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			RosterModes = new Dictionary<string, ConfigEntry<ChallengeMode>>(StringComparer.OrdinalIgnoreCase);
			foreach (BaseChallenge item in ChallengeRegistry.All)
			{
				ConfigEntry<ChallengeMode> val = ((BaseUnityPlugin)this).Config.Bind<ChallengeMode>("5 - Challenge Roster", item.Id, ChallengeMode.Off, new ConfigDescription(item.DisplayName + ". Active = always enforced (stacks with other Active challenges). Available = part of the F8 rotation. Off = disabled. NOTE: setting ANY challenge to Active disables F8.", (AcceptableValueBase)null, Array.Empty<object>()));
				val.SettingChanged += delegate
				{
					try
					{
						ChallengeManager.ReconcileRoster();
					}
					catch (Exception ex)
					{
						Log.LogError((object)("[Roster] Reconcile failed: " + ex.Message));
					}
				};
				RosterModes[item.Id] = val;
			}
			Log.LogInfo((object)$"[Plugin] Roster config bound for {RosterModes.Count} challenges.");
		}

		private void BindManualAssign()
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			string[] array = ChallengeRegistry.All.Select((BaseChallenge c) => c.Id).ToArray();
			string text = ((array.Length != 0) ? array[0] : "");
			ManualTarget = ((BaseUnityPlugin)this).Config.Bind<string>("3 - Manual Assign", "Target", "", "Player to target — Steam name, or a Twitch/alias name from NameAliases. Leave blank to target yourself.");
			ManualChallenge = ((BaseUnityPlugin)this).Config.Bind<string>("3 - Manual Assign", "Challenge", text, new ConfigDescription("Challenge to assign when you flip 'Assign now'.", (AcceptableValueBase)(object)new AcceptableValueList<string>(array), Array.Empty<object>()));
			ManualAssignTrigger = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Manual Assign", "Assign now", false, "Flip ON to assign the chosen Challenge to Target. Resets to OFF automatically.");
			ManualAssignTrigger.SettingChanged += delegate
			{
				if (!ManualAssignTrigger.Value)
				{
					return;
				}
				try
				{
					string text2 = (string.IsNullOrWhiteSpace(ManualTarget.Value) ? null : ManualTarget.Value.Trim());
					string value = ManualChallenge.Value;
					Log.LogInfo((object)("[ManualAssign] Assign '" + value + "' → " + (text2 ?? "self")));
					ChallengeSync.SendChallenge(text2, value);
				}
				catch (Exception ex)
				{
					Log.LogError((object)("[ManualAssign] Assign failed: " + ex.Message));
				}
				finally
				{
					ManualAssignTrigger.Value = false;
				}
			};
			ManualClearTrigger = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Manual Assign", "Clear now", false, "Flip ON to clear Target's challenge (blank Target = yourself). Resets to OFF automatically.");
			ManualClearTrigger.SettingChanged += delegate
			{
				if (!ManualClearTrigger.Value)
				{
					return;
				}
				try
				{
					string text2 = (string.IsNullOrWhiteSpace(ManualTarget.Value) ? null : ManualTarget.Value.Trim());
					Log.LogInfo((object)("[ManualAssign] Clear → " + (text2 ?? "self")));
					ChallengeSync.SendClear(text2);
				}
				catch (Exception ex)
				{
					Log.LogError((object)("[ManualAssign] Clear failed: " + ex.Message));
				}
				finally
				{
					ManualClearTrigger.Value = false;
				}
			};
			Log.LogInfo((object)"[Plugin] Manual Assign panel bound.");
		}
	}
	public class ChallengeUpdater : MonoBehaviour
	{
		private bool _firstUpdate = true;

		private float _pollTimer;

		private void Awake()
		{
			Plugin.Log.LogInfo((object)"[ChallengeUpdater] Awake — standalone updater alive.");
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			Plugin.Log.LogInfo((object)("[ChallengeUpdater] Scene loaded: " + ((Scene)(ref scene)).name));
			ChallengeManager.OnSceneLoad();
			HeldItemTicker.OnSceneLoad();
		}

		private void Update()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if (_firstUpdate)
			{
				_firstUpdate = false;
				Plugin.Log.LogInfo((object)$"[ChallengeUpdater] *** FIRST UPDATE *** Ready={Plugin.Ready}");
			}
			if (!Plugin.Ready)
			{
				return;
			}
			HeldItemTicker.Tick();
			if (Plugin.DebugKeysEnabled.Value)
			{
				KeyboardShortcut value = Plugin.CycleKey.Value;
				if (Plugin.IsKeyDown(((KeyboardShortcut)(ref value)).MainKey))
				{
					Plugin.Log.LogInfo((object)"[ChallengeUpdater] Cycle key pressed.");
					ChallengeManager.CycleChallenge();
					Plugin.WriteStatus();
				}
				value = Plugin.ClearKey.Value;
				if (Plugin.IsKeyDown(((KeyboardShortcut)(ref value)).MainKey))
				{
					Plugin.Log.LogInfo((object)"[ChallengeUpdater] Clear key pressed.");
					ChallengeManager.ClearChallenge();
					Plugin.WriteStatus();
				}
			}
			if (Plugin.SbEnabled.Value)
			{
				_pollTimer += Time.unscaledDeltaTime;
				if (!(_pollTimer < 0.5f))
				{
					_pollTimer = 0f;
					Plugin.PollCmdFile();
				}
			}
		}
	}
}
namespace GynxzRepoChallenges.UI
{
	public class ChallengeHUD : MonoBehaviour
	{
		public static bool Dirty;

		private static string _violationText;

		private static float _violationTimer;

		private const float VIOLATION_DURATION = 3f;

		private static string _persistentText;

		private GUIStyle _boxStyle;

		private GUIStyle _titleStyle;

		private GUIStyle _descStyle;

		private GUIStyle _violationStyle;

		private bool _stylesInitialised;

		public static void ShowPersistentMessage(string message)
		{
			_persistentText = message;
		}

		public static void ClearPersistentMessage()
		{
			_persistentText = null;
		}

		public static void ShowViolation(string message)
		{
			_violationText = message;
			_violationTimer = 3f;
		}

		private void Update()
		{
			if (_violationTimer > 0f)
			{
				_violationTimer -= Time.unscaledDeltaTime;
			}
		}

		private void OnGUI()
		{
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.HudEnabled.Value)
			{
				return;
			}
			InitStyles();
			int value = Plugin.HudPositionX.Value;
			int value2 = Plugin.HudPositionY.Value;
			int value3 = Plugin.HudFontSize.Value;
			int num = 8;
			int num2 = 260;
			if (_violationTimer > 0f && _violationText != null)
			{
				float num3 = Mathf.Clamp01(_violationTimer / 3f);
				Color color = GUI.color;
				GUI.color = new Color(1f, 0.2f, 0.2f, num3);
				Vector2 val = _violationStyle.CalcSize(new GUIContent(_violationText));
				float num4 = (float)Screen.width * 0.5f - val.x * 0.5f;
				float num5 = (float)Screen.height * 0.35f;
				GUI.Label(new Rect(num4 - (float)num, num5 - (float)num, val.x + (float)(num * 2), val.y + (float)(num * 2)), _violationText, _violationStyle);
				GUI.color = color;
			}
			if (_persistentText != null)
			{
				Vector2 val2 = _violationStyle.CalcSize(new GUIContent(_persistentText));
				float num6 = (float)Screen.width * 0.5f - val2.x * 0.5f;
				float num7 = (float)Screen.height * 0.5f - val2.y * 0.5f;
				Color color2 = GUI.color;
				GUI.color = new Color(1f, 0.55f, 0f, 1f);
				GUI.Label(new Rect(num6 - (float)num, num7 - (float)num, val2.x + (float)(num * 2), val2.y + (float)(num * 2)), _persistentText, _violationStyle);
				GUI.color = color2;
			}
			IReadOnlyList<BaseChallenge> activeList = ChallengeManager.ActiveList;
			if (activeList.Count == 0)
			{
				GUI.Box(new Rect((float)value, (float)value2, (float)num2, (float)(30 + num * 2)), "", _boxStyle);
				string text = (ChallengeManager.RosterHasActive() ? "No challenge active" : "No challenge active  |  F8 to cycle");
				GUI.Label(new Rect((float)(value + num), (float)(value2 + num), (float)(num2 - num * 2), 26f), text, _descStyle);
				return;
			}
			float num8 = value2;
			_titleStyle.fontSize = value3;
			_descStyle.fontSize = value3 - 2;
			for (int i = 0; i < activeList.Count; i++)
			{
				BaseChallenge baseChallenge = activeList[i];
				string text2 = "⚠ " + baseChallenge.DisplayName;
				string text3 = (Plugin.HudShowDescription.Value ? baseChallenge.Description : "");
				float num9 = value3 + 6;
				float num10 = (Plugin.HudShowDescription.Value ? ((value3 - 2) * 2 + 4) : 0);
				float num11 = num9 + num10 + (float)(num * 3);
				GUI.Box(new Rect((float)value, num8, (float)num2, num11), "", _boxStyle);
				GUI.Label(new Rect((float)(value + num), num8 + (float)num, (float)(num2 - num * 2), num9), text2, _titleStyle);
				if (Plugin.HudShowDescription.Value && !string.IsNullOrEmpty(text3))
				{
					GUI.Label(new Rect((float)(value + num), num8 + (float)num + num9 + 2f, (float)(num2 - num * 2), num10), text3, _descStyle);
				}
				num8 += num11 + 4f;
			}
			int num12 = 0;
			string text4 = "";
			if (ChallengeManager.FlawlessActive)
			{
				num12 = ChallengeManager.FlawlessViolations;
				text4 = "Damage events";
			}
			else if (ChallengeManager.CartLeashActive)
			{
				num12 = ChallengeManager.CartLeashViolations;
				text4 = "Leash breaks";
			}
			if (text4 != "" && num12 > 0)
			{
				string text5 = $"{text4}: {num12}";
				GUI.Label(new Rect((float)(value + num), num8, (float)(num2 - num * 2), 20f), text5, _descStyle);
			}
		}

		private void InitStyles()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Expected O, but got Unknown
			if (!_stylesInitialised)
			{
				_stylesInitialised = true;
				Texture2D val = new Texture2D(1, 1);
				val.SetPixel(0, 0, new Color(0f, 0f, 0f, 0.65f));
				val.Apply();
				GUIStyle val2 = new GUIStyle(GUI.skin.box);
				val2.normal.background = val;
				_boxStyle = val2;
				GUIStyle val3 = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)1
				};
				val3.normal.textColor = new Color(1f, 0.85f, 0.2f);
				val3.wordWrap = false;
				_titleStyle = val3;
				GUIStyle val4 = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)0
				};
				val4.normal.textColor = new Color(0.9f, 0.9f, 0.9f);
				val4.wordWrap = true;
				_descStyle = val4;
				GUIStyle val5 = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)1,
					fontSize = 24,
					alignment = (TextAnchor)4
				};
				val5.normal.textColor = Color.red;
				_violationStyle = val5;
			}
		}
	}
}
namespace GynxzRepoChallenges.SB
{
	public class SBBridge : MonoBehaviour
	{
		private static readonly string BASE = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Thunderstore Mod Manager\\DataFolder\\REPO\\profiles\\REPO");

		public static readonly string CMD_FILE = Path.Combine(BASE, "challenge_cmd.txt");

		public static readonly string STATUS_FILE = Path.Combine(BASE, "challenge_status.txt");

		public static readonly string LIST_FILE = Path.Combine(BASE, "challenge_list.txt");

		private string _lastCmd = "";

		private float _pollTimer;

		private const float POLL_INTERVAL = 0.5f;

		public static SBBridge Create()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			GameObject val = new GameObject("GynxzSBBridge");
			Object.DontDestroyOnLoad((Object)val);
			return val.AddComponent<SBBridge>();
		}

		private void Awake()
		{
			try
			{
				WriteListFile();
				TryClearCmd();
				WriteStatus();
				Plugin.Log.LogInfo((object)"[SBBridge] File bridge ready.");
				Plugin.Log.LogInfo((object)("[SBBridge] Command file: " + CMD_FILE));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("[SBBridge] Awake failed: " + ex.Message));
			}
		}

		private void Update()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: