Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of GynxzRepoChallenges v1.4.0
plugins\GynxzRepoChallenges\GynxzRepoChallenges.dll
Decompiled 6 days ago
The result has been truncated due to the large size, download it to view full contents!
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: