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 _active = new List(); private static readonly List _picks = new List(); 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 _cartTransforms = new List(); 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 ActiveChallenges => _active; public static IReadOnlyList 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 RosterActiveList() { return ChallengeRegistry.All.Where((BaseChallenge c) => Plugin.GetMode(c.Id) == ChallengeMode.Active).ToList(); } private static List AvailableList() { return ChallengeRegistry.All.Where((BaseChallenge c) => Plugin.GetMode(c.Id) == ChallengeMode.Available).ToList(); } public static void ReconcileRoster() { List 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 desired) { List list = new List(); 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 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(); 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 _fieldCache = new Dictionary(); 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(); 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 _violatedItems = new HashSet(); 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 _weaponVerdicts = new Dictionary(); 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 list = new List(); 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(); 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 _warnedThisRound = new HashSet(); 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 _watches = new List(); 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 _voCache = new Dictionary(); 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(); 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() : 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(); 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(); 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 DebugKeysEnabled; internal static ConfigEntry VerboseLogging; internal static ConfigEntry CycleKey; internal static ConfigEntry ClearKey; internal static ConfigEntry ChallengeScopePerRound; internal static ConfigEntry CartLeashMaxDistance; internal static ConfigEntry CartLeashSlowStartDistance; internal static ConfigEntry CartLeashSlowPercent; internal static ConfigEntry ExpensiveItemThreshold; internal static ConfigEntry EmpathyDamagePerHit; internal static ConfigEntry AutoAssignOnRoundStart; internal static ConfigEntry ShortRangeUseOriginal; internal static ConfigEntry ShortRangeReductionPercent; internal static ConfigEntry HudEnabled; internal static ConfigEntry HudPositionX; internal static ConfigEntry HudPositionY; internal static ConfigEntry HudFontSize; internal static ConfigEntry HudShowDescription; internal static ConfigEntry HudShowOtherPlayers; internal static ConfigEntry SbEnabled; internal static ConfigEntry NameAliases; internal static ConfigEntry ManualTarget; internal static ConfigEntry ManualChallenge; internal static ConfigEntry ManualAssignTrigger; internal static ConfigEntry ManualClearTrigger; internal static Dictionary> 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:,challenge: or player:,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 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(); Log.LogInfo((object)"[Plugin] HUD created from gameplay context."); } GameObject val2 = new GameObject("GynxzChallengeUpdater_Live"); Object.DontDestroyOnLoad((Object)val2); val2.AddComponent(); 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("0 - Debug", "DebugKeysEnabled", true, "Enable F8 (cycle challenge) and F9 (clear challenge) hotkeys."); CycleKey = ((BaseUnityPlugin)this).Config.Bind("0 - Debug", "CycleKey", new KeyboardShortcut((KeyCode)289, Array.Empty()), "Cycle through challenges."); ClearKey = ((BaseUnityPlugin)this).Config.Bind("0 - Debug", "ClearKey", new KeyboardShortcut((KeyCode)290, Array.Empty()), "Clear active challenge."); VerboseLogging = ((BaseUnityPlugin)this).Config.Bind("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("1 - Challenges", "ChallengeScopePerRound", true, "true = challenge clears at the start of each new level."); CartLeashMaxDistance = ((BaseUnityPlugin)this).Config.Bind("1 - Challenges", "CartLeashMaxDistance", 5f, new ConfigDescription("Distance from cart for full stop.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 50f), Array.Empty())); CartLeashSlowStartDistance = ((BaseUnityPlugin)this).Config.Bind("1 - Challenges", "CartLeashSlowStartDistance", 3f, new ConfigDescription("Distance from cart where slowdown begins (must be less than CartLeashMaxDistance).", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 50f), Array.Empty())); CartLeashSlowPercent = ((BaseUnityPlugin)this).Config.Bind("1 - Challenges", "CartLeashSlowPercent", 50, new ConfigDescription("Speed reduction % in the slow zone between SlowStart and MaxDistance.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ExpensiveItemThreshold = ((BaseUnityPlugin)this).Config.Bind("1 - Challenges", "ExpensiveItemThreshold", 5000, new ConfigDescription("Value threshold for Frugal/ExpensiveOnly.", (AcceptableValueBase)(object)new AcceptableValueRange(100, 100000), Array.Empty())); ShortRangeUseOriginal = ((BaseUnityPlugin)this).Config.Bind("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("1 - Challenges", "ShortRangeReductionPercent", 50, new ConfigDescription("Percentage to reduce grab range for the Short Range challenge.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 99), Array.Empty())); EmpathyDamagePerHit = ((BaseUnityPlugin)this).Config.Bind("1 - Challenges", "EmpathyDamagePerHit", 5, new ConfigDescription("HP the Empathetic challenge deals to you per item hit.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 100), Array.Empty())); AutoAssignOnRoundStart = ((BaseUnityPlugin)this).Config.Bind("1 - Challenges", "AutoAssignOnRoundStart", false, "Auto-assign random challenge each level."); HudEnabled = ((BaseUnityPlugin)this).Config.Bind("2 - HUD", "Enabled", true, "Show challenge HUD."); HudPositionX = ((BaseUnityPlugin)this).Config.Bind("2 - HUD", "PositionX", 12, "Horizontal offset."); HudPositionY = ((BaseUnityPlugin)this).Config.Bind("2 - HUD", "PositionY", 12, "Vertical offset."); HudFontSize = ((BaseUnityPlugin)this).Config.Bind("2 - HUD", "FontSize", 18, new ConfigDescription("HUD font size.", (AcceptableValueBase)(object)new AcceptableValueRange(10, 40), Array.Empty())); HudShowDescription = ((BaseUnityPlugin)this).Config.Bind("2 - HUD", "ShowDescription", true, "Show challenge description."); HudShowOtherPlayers = ((BaseUnityPlugin)this).Config.Bind("2 - HUD", "ShowOtherPlayers", true, "Show other players challenges."); SbEnabled = ((BaseUnityPlugin)this).Config.Bind("4 - Streamer.bot Integration", "Enabled", true, "Watch challenge_cmd.txt for commands."); NameAliases = ((BaseUnityPlugin)this).Config.Bind("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>(StringComparer.OrdinalIgnoreCase); foreach (BaseChallenge item in ChallengeRegistry.All) { ConfigEntry val = ((BaseUnityPlugin)this).Config.Bind("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())); 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("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("3 - Manual Assign", "Challenge", text, new ConfigDescription("Challenge to assign when you flip 'Assign now'.", (AcceptableValueBase)(object)new AcceptableValueList(array), Array.Empty())); ManualAssignTrigger = ((BaseUnityPlugin)this).Config.Bind("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("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 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(); } 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: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (Plugin.DebugKeysEnabled.Value) { KeyboardShortcut value = Plugin.CycleKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { Plugin.Log.LogInfo((object)"[SBBridge] Cycle key pressed."); ChallengeManager.CycleChallenge(); } value = Plugin.ClearKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { Plugin.Log.LogInfo((object)"[SBBridge] Clear key pressed."); ChallengeManager.ClearChallenge(); } } _pollTimer += Time.unscaledDeltaTime; if (_pollTimer < 0.5f) { return; } _pollTimer = 0f; try { if (File.Exists(CMD_FILE)) { string text = File.ReadAllText(CMD_FILE); string text2 = ((text == null) ? "" : text.Trim().ToLowerInvariant()); if (!string.IsNullOrEmpty(text2) && !(text2 == _lastCmd)) { _lastCmd = text2; File.WriteAllText(CMD_FILE, ""); Plugin.Log.LogInfo((object)("[SBBridge] Command received: '" + text2 + "'")); ExecuteCommand(text2); } } } catch (Exception ex) { Plugin.Log.LogError((object)("[SBBridge] Poll error: " + ex.Message)); } } private void ExecuteCommand(string cmd) { if (cmd == "clear") { ChallengeManager.ClearChallenge(); } else if (cmd == "random") { ChallengeManager.AssignRandom(); } else { string text = cmd; if (cmd.Contains("challenge:")) { int num = cmd.IndexOf("challenge:", StringComparison.Ordinal); text = cmd.Substring(num + 10).Split(new char[1] { ',' })[0].Trim(); } if (!ChallengeManager.AssignById(text)) { Plugin.Log.LogWarning((object)("[SBBridge] Unknown id: '" + text + "'")); } } WriteStatus(); } private void WriteListFile() { try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# Valid challenge ids — write one to: " + CMD_FILE); stringBuilder.AppendLine("# Special commands: clear, random"); stringBuilder.AppendLine(); foreach (BaseChallenge item in ChallengeRegistry.All) { stringBuilder.AppendLine($"{item.Id,-20} # {item.DisplayName}"); } File.WriteAllText(LIST_FILE, stringBuilder.ToString()); } catch (Exception ex) { Plugin.Log.LogError((object)("[SBBridge] WriteListFile failed: " + ex.Message)); } } public static void WriteStatus() { try { List 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 { } } } public class MainThreadDispatcher : MonoBehaviour { private static MainThreadDispatcher _instance; private static readonly Queue _queue = new Queue(); private static readonly object _lock = new object(); public static void Enqueue(Action action) { lock (_lock) { _queue.Enqueue(action); } } public static void EnsureExists() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("GynxzMainThreadDispatcher"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent(); } } private void Awake() { _instance = this; } private void Update() { while (true) { Action action; lock (_lock) { if (_queue.Count == 0) { break; } action = _queue.Dequeue(); } try { action(); } catch (Exception ex) { Plugin.Log.LogError((object)("[Dispatcher] " + ex.Message)); } } } } } namespace GynxzRepoChallenges.Network { public class ChallengeSync : MonoBehaviour, IOnEventCallback { private const byte EVENT_ASSIGN = 77; private const byte EVENT_CLEAR = 78; private const byte EVENT_IMPACT = 79; private const byte EVENT_DESTROY = 80; private const byte EVENT_EXPLODE = 81; private float _playerListTimer; private const float PLAYER_LIST_INTERVAL = 5f; private static readonly Dictionary _aliasMap = new Dictionary(StringComparer.OrdinalIgnoreCase); private static string _aliasCacheKey = null; private static string _lastPlayerList = null; public static ChallengeSync Instance { get; private set; } public static void Create() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!((Object)(object)Instance != (Object)null)) { GameObject val = new GameObject("GynxzChallengeSync"); Object.DontDestroyOnLoad((Object)val); Instance = val.AddComponent(); } } private void Awake() { Instance = this; PhotonNetwork.AddCallbackTarget((object)this); Plugin.Log.LogInfo((object)"[ChallengeSync] Awake — listening for events."); WritePlayerList(); } private void OnDestroy() { PhotonNetwork.RemoveCallbackTarget((object)this); if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { _playerListTimer -= Time.unscaledDeltaTime; if (_playerListTimer <= 0f) { _playerListTimer = 5f; WritePlayerList(); } } public static void SendChallenge(string targetName, string challengeId, bool additive = false) { //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_00e7: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(challengeId)) { return; } if (string.IsNullOrEmpty(targetName)) { AssignLocal(challengeId, additive); return; } string text = ResolveAlias(targetName); if (!PhotonNetwork.InRoom) { Plugin.Log.LogWarning((object)("[ChallengeSync] '" + targetName + "' targeted but not in a Photon room — skipping.")); return; } Player val = FindPlayer(text); if (val == null) { Plugin.Log.LogWarning((object)("[ChallengeSync] Player '" + targetName + "'" + ((text != targetName) ? (" (alias → '" + text + "')") : "") + " not found in room — skipping (no assignment).")); } else if (val.IsLocal) { AssignLocal(challengeId, additive); } else { string text2 = (additive ? ("+" + challengeId) : challengeId); RaiseEventOptions val2 = new RaiseEventOptions(); val2.TargetActors = new int[1] { val.ActorNumber }; RaiseEventOptions val3 = val2; PhotonNetwork.RaiseEvent((byte)77, (object)text2, val3, SendOptions.SendReliable); Plugin.Log.LogInfo((object)$"[ChallengeSync] Sent '{text2}' → {val.NickName} (actor {val.ActorNumber})"); } } public static void SendClear(string targetName) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00c5: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(targetName)) { ClearLocal(); return; } string text = ResolveAlias(targetName); if (!PhotonNetwork.InRoom) { Plugin.Log.LogWarning((object)("[ChallengeSync] Clear '" + targetName + "' targeted but not in a Photon room — skipping.")); return; } Player val = FindPlayer(text); if (val == null) { Plugin.Log.LogWarning((object)("[ChallengeSync] Clear target '" + targetName + "'" + ((text != targetName) ? (" (alias → '" + text + "')") : "") + " not found in room — skipping.")); } else if (val.IsLocal) { ClearLocal(); } else { RaiseEventOptions val2 = new RaiseEventOptions(); val2.TargetActors = new int[1] { val.ActorNumber }; RaiseEventOptions val3 = val2; PhotonNetwork.RaiseEvent((byte)78, (object)null, val3, SendOptions.SendReliable); Plugin.Log.LogInfo((object)("[ChallengeSync] Sent clear → " + val.NickName)); } } public void OnEvent(EventData photonEvent) { //IL_0110: Unknown result type (might be due to invalid IL or missing references) try { if (photonEvent.Code == 77) { string text = photonEvent.CustomData as string; Plugin.Log.LogInfo((object)("[ChallengeSync] Received assign: '" + text + "'")); bool flag = !string.IsNullOrEmpty(text) && text[0] == '+'; AssignLocal(flag ? text.Substring(1) : text, flag); } else if (photonEvent.Code == 78) { Plugin.Log.LogInfo((object)"[ChallengeSync] Received clear."); ClearLocal(); } else if (photonEvent.Code == 79) { if (photonEvent.CustomData is int viewID) { ItemDamagePatch.OnRelayedImpact(viewID); } } else if (photonEvent.Code == 80) { if (PhotonNetwork.IsMasterClient && photonEvent.CustomData is int viewID2) { ItemDamagePatch.DestroyByViewID(viewID2); } } else if (photonEvent.Code == 81 && PhotonNetwork.IsMasterClient && photonEvent.CustomData is float[] array && array.Length == 3) { ItemDamagePatch.TrySpawnExplosion(new Vector3(array[0], array[1], array[2])); } } catch (Exception ex) { Plugin.Log.LogError((object)("[ChallengeSync] OnEvent error: " + ex.Message)); } } internal static void RelayImpactToHolder(int actorNumber, int viewID) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.InRoom) { RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = new int[1] { actorNumber }; RaiseEventOptions val2 = val; PhotonNetwork.RaiseEvent((byte)79, (object)viewID, val2, SendOptions.SendReliable); Plugin.LogVerbose($"[ChallengeSync] Impact relayed → actor {actorNumber} (view {viewID})"); } } internal static void RequestDestroy(int viewID) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.InRoom) { RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)2 }; PhotonNetwork.RaiseEvent((byte)80, (object)viewID, val, SendOptions.SendReliable); } } internal static void RequestExplosion(Vector3 pos) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.InRoom) { RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)2 }; PhotonNetwork.RaiseEvent((byte)81, (object)new float[3] { pos.x, pos.y, pos.z }, val, SendOptions.SendReliable); } } private static void AssignLocal(string id, bool additive = false) { ChallengeManager.AssignById(id, additive); Plugin.WriteStatus(); } private static void ClearLocal() { ChallengeManager.ClearChallenge(); Plugin.WriteStatus(); } private static void ParseAliasPairs(string raw) { if (string.IsNullOrEmpty(raw)) { return; } string[] array = raw.Split(new char[4] { ';', ',', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0 || text[0] == '#') { continue; } int num = text.IndexOf('='); if (num > 0) { string text2 = text.Substring(0, num).Trim(); string text3 = text.Substring(num + 1).Trim(); if (text2.Length != 0 && text3.Length != 0) { _aliasMap[text2] = text3; } } } } private static void RefreshAliasMap() { string text = Plugin.NameAliases?.Value ?? ""; long num = 0L; try { FileInfo fileInfo = new FileInfo(Plugin.ALIASES_FILE); if (fileInfo.Exists) { num = fileInfo.LastWriteTimeUtc.Ticks; } } catch { } string text2 = num + "|" + text; if (text2 == _aliasCacheKey) { return; } _aliasCacheKey = text2; _aliasMap.Clear(); ParseAliasPairs(text); if (num != 0L) { try { ParseAliasPairs(File.ReadAllText(Plugin.ALIASES_FILE)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[ChallengeSync] Alias file read failed: " + ex.Message)); } } Plugin.Log.LogInfo((object)string.Format("[ChallengeSync] Alias map loaded — {0} entr{1}.", _aliasMap.Count, (_aliasMap.Count == 1) ? "y" : "ies")); } private static string ResolveAlias(string name) { if (string.IsNullOrEmpty(name)) { return name; } RefreshAliasMap(); if (_aliasMap.TryGetValue(name.Trim(), out var value)) { if (!string.Equals(value, name, StringComparison.OrdinalIgnoreCase)) { Plugin.Log.LogInfo((object)("[ChallengeSync] Alias '" + name + "' → '" + value + "'")); } return value; } return name; } private static Player FindPlayer(string name) { Player val = null; int num = 0; Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val2 in playerList) { string nickName = val2.NickName; if (!string.IsNullOrEmpty(nickName)) { if (string.Equals(nickName, name, StringComparison.OrdinalIgnoreCase)) { return val2; } if (nickName.StartsWith(name, StringComparison.OrdinalIgnoreCase) || name.StartsWith(nickName, StringComparison.OrdinalIgnoreCase)) { val = val2; num++; } } } if (num == 1) { Plugin.Log.LogInfo((object)("[ChallengeSync] Partial match '" + name + "' → '" + val.NickName + "'")); return val; } if (num > 1) { Plugin.Log.LogWarning((object)$"[ChallengeSync] '{name}' matches {num} players — be more specific."); } return null; } internal static void WritePlayerList() { try { StringBuilder stringBuilder = new StringBuilder(); if (PhotonNetwork.InRoom) { Room currentRoom = PhotonNetwork.CurrentRoom; stringBuilder.AppendLine("# Room: " + (((currentRoom != null) ? currentRoom.Name : null) ?? "unknown")); Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { stringBuilder.AppendLine(string.Format("{0}{1} actor={2}", val.NickName, val.IsLocal ? " (you)" : "", val.ActorNumber)); } } else { stringBuilder.AppendLine("# Not in room (solo or main menu)"); Player localPlayer = PhotonNetwork.LocalPlayer; stringBuilder.AppendLine((((localPlayer != null) ? localPlayer.NickName : null) ?? "local") + " (you)"); } string text = stringBuilder.ToString(); if (!(text == _lastPlayerList)) { _lastPlayerList = text; File.WriteAllText(Plugin.PLAYERS_FILE, text); } } catch { } } } } namespace GynxzRepoChallenges.Challenges { public class NoCrouchChallenge : BaseChallenge { public override string Id => "no_crouch"; public override string DisplayName => "No Crouch"; public override string Description => "You cannot crouch. Stand tall, suffer fully."; public override void Apply() { ChallengeManager.NoCrouchActive = true; } public override void Remove() { ChallengeManager.NoCrouchActive = false; } } public class NoSprintChallenge : BaseChallenge { public override string Id => "no_sprint"; public override string DisplayName => "No Sprint"; public override string Description => "Walk only. No running. Enjoy the leisurely pace."; public override void Apply() { ChallengeManager.NoSprintActive = true; } public override void Remove() { ChallengeManager.NoSprintActive = false; } } public class NoMapChallenge : BaseChallenge { public override string Id => "no_map"; public override string DisplayName => "No Map"; public override string Description => "The map tool is disabled. Navigate by memory."; public override void Apply() { ChallengeManager.NoMapActive = true; } public override void Remove() { ChallengeManager.NoMapActive = false; } } public class NoHealthPackChallenge : BaseChallenge { public override string Id => "no_healthpack"; public override string DisplayName => "No Health Pack"; public override string Description => "Health packs cannot be used. Hope you don't get hurt."; public override void Apply() { ChallengeManager.NoHealthPackActive = true; } public override void Remove() { ChallengeManager.NoHealthPackActive = false; } } public class NoUpgradesChallenge : BaseChallenge { public override string Id => "no_upgrades"; public override string DisplayName => "No Upgrades"; public override string Description => "Upgrade stations are off-limits. Stay baseline."; public override void Apply() { ChallengeManager.NoUpgradesActive = true; } public override void Remove() { ChallengeManager.NoUpgradesActive = false; } } public class TextOnlyChallenge : BaseChallenge { public override string Id => "text_only"; public override string DisplayName => "Text Only"; public override string Description => "Communicate using text chat only. No voice."; public override void Apply() { } public override void Remove() { } } public class CartLeashChallenge : BaseChallenge { public override string Id => "cart_leash"; public override string DisplayName => "Cart Leash"; public override string Description => $"Stay within {Plugin.CartLeashMaxDistance.Value} units of the nearest cart at all times."; public override void Apply() { ChallengeManager.CartLeashActive = true; } public override void Remove() { ChallengeManager.CartLeashActive = false; } } public class FlawlessChallenge : BaseChallenge { public override string Id => "flawless"; public override string DisplayName => "Flawless Items"; public override string Description => "You must not damage any item. Handle with care."; public override void Apply() { ChallengeManager.FlawlessActive = true; } public override void Remove() { ChallengeManager.FlawlessActive = false; } } public class FrugalChallenge : BaseChallenge { public override string Id => "frugal"; public override string DisplayName => "Frugal"; public override string Description => $"Only grab items worth less than ${Plugin.ExpensiveItemThreshold.Value:N0}. No splurging."; public override void Apply() { ChallengeManager.FrugalActive = true; } public override void Remove() { ChallengeManager.FrugalActive = false; } } public class ExpensiveOnlyChallenge : BaseChallenge { public override string Id => "expensive_only"; public override string DisplayName => "Expensive Only"; public override string Description => $"Only grab items worth ${Plugin.ExpensiveItemThreshold.Value:N0} or more. High standards only."; public override void Apply() { ChallengeManager.ExpensiveOnlyActive = true; } public override void Remove() { ChallengeManager.ExpensiveOnlyActive = false; } } public class PacifistChallenge : BaseChallenge { public override string Id => "pacifist"; public override string DisplayName => "Pacifist"; public override string Description => "No grabbing weapons. Violence is not the answer."; public override void Apply() { ChallengeManager.PacifistActive = true; } public override void Remove() { ChallengeManager.PacifistActive = false; } } public class EmpathyChallenge : BaseChallenge { public override string Id => "empathetic"; public override string DisplayName => "Empathetic"; public override string Description => $"You feel everything. Items you hold share their pain — every hit deals {Plugin.EmpathyDamagePerHit.Value}HP to you."; public override void Apply() { ChallengeManager.EmpathyActive = true; } public override void Remove() { ChallengeManager.EmpathyActive = false; } } public class NitroFingersChallenge : BaseChallenge { public override string Id => "nitro_fingers"; public override string DisplayName => "Nitro Fingers"; public override string Description => "Everything you touch that takes damage EXPLODES. Handle with extreme care."; public override void Apply() { ChallengeManager.NitroFingersActive = true; } public override void Remove() { ChallengeManager.NitroFingersActive = false; } } public class ShortRangeChallenge : BaseChallenge { public override string Id => "t_rex"; public override string DisplayName => "T-Rex"; public override string Description { get { int value = Plugin.ShortRangeReductionPercent.Value; float shortRangeOriginalValue = ChallengeManager.ShortRangeOriginalValue; float shortRangeCurrentValue = ChallengeManager.ShortRangeCurrentValue; if (shortRangeOriginalValue >= 0f && shortRangeCurrentValue >= 0f) { float num = (Plugin.ShortRangeUseOriginal.Value ? shortRangeOriginalValue : shortRangeCurrentValue) * (1f - (float)value / 100f); return $"Short arms, big heart. Range -{value}% " + $"(base {shortRangeOriginalValue:F1} current {shortRangeCurrentValue:F1} → {num:F1})"; } return $"Short arms, big heart. Grab range reduced by {value}%."; } } public override void Apply() { ChallengeManager.ShortRangeActive = true; } public override void Remove() { ChallengeManager.ShortRangeActive = false; } } public enum ChallengeMode { Off, Available, Active } public abstract class BaseChallenge { public abstract string Id { get; } public abstract string DisplayName { get; } public abstract string Description { get; } public virtual void Apply() { } public virtual void Remove() { } public override string ToString() { return DisplayName + " (" + Id + ")"; } } public static class ChallengeRegistry { private static readonly Dictionary _challenges = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Random _rng = new Random(); public static int Count => _challenges.Count; public static IEnumerable All => _challenges.Values; public static void RegisterAll() { Register(new NoCrouchChallenge()); Register(new NoSprintChallenge()); Register(new NoMapChallenge()); Register(new NoHealthPackChallenge()); Register(new NoUpgradesChallenge()); Register(new TextOnlyChallenge()); Register(new CartLeashChallenge()); Register(new FlawlessChallenge()); Register(new FrugalChallenge()); Register(new ExpensiveOnlyChallenge()); Register(new PacifistChallenge()); Register(new EmpathyChallenge()); Register(new NitroFingersChallenge()); Register(new ShortRangeChallenge()); } public static void Register(BaseChallenge challenge) { _challenges[challenge.Id] = challenge; } public static BaseChallenge Get(string id) { if (!_challenges.TryGetValue(id, out var value)) { return null; } return value; } public static bool Has(string id) { return _challenges.ContainsKey(id); } public static BaseChallenge GetRandom() { if (_challenges.Count == 0) { return null; } List list = _challenges.Values.ToList(); return list[_rng.Next(list.Count)]; } public static BaseChallenge GetByIndex(int index) { List list = _challenges.Values.ToList(); if (list.Count == 0) { return null; } return list[index % list.Count]; } public static IEnumerable AllIds() { return _challenges.Keys; } } }