using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using MyceliumNetworking; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("UnderdogBuff")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.30.0")] [assembly: AssemblyInformationalVersion("1.0.30")] [assembly: AssemblyProduct("UnderdogBuff")] [assembly: AssemblyTitle("UnderdogBuff")] [assembly: AssemblyVersion("1.0.30.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace UnderdogBuffMod { [BepInPlugin("com.openai.straftat.underdogbuff", "Underdog Advantage", "1.0.30")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class UnderdogBuff : BaseUnityPlugin { private sealed class FieldSnapshot { public object Target; public FieldInfo Field; public object Original; public float Multiplier; } private sealed class ReferenceEqualityComparer : IEqualityComparer { public static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer(); public new bool Equals(object a, object b) { return a == b; } public int GetHashCode(object obj) { return RuntimeHelpers.GetHashCode(obj); } } public static UnderdogBuff Instance; private const uint MOD_ID = 4287319041u; private const BindingFlags BF = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private ConfigEntry _healthMultiplier; private ConfigEntry _speedMultiplier; private ConfigEntry _jumpMultiplier; private ConfigEntry _extraJumps; private ConfigEntry _pollSeconds; private float _effectiveHealthMultiplier = 1f; private float _effectiveSpeedMultiplier = 1f; private float _effectiveJumpMultiplier = 1f; private int _effectiveExtraJumps; private bool _receivedHostSettings; private readonly HashSet _trailingSteamIds = new HashSet(); private readonly HashSet _trailingHealthObjects = new HashSet(ReferenceEqualityComparer.Instance); private readonly Dictionary _baseMaxHealth = new Dictionary(ReferenceEqualityComparer.Instance); private readonly HashSet _baseHealthBoosted = new HashSet(ReferenceEqualityComparer.Instance); private readonly Dictionary _lastAppliedHealthMultiplier = new Dictionary(ReferenceEqualityComparer.Instance); private static readonly Dictionary _typeCache = new Dictionary(); private string _lastBroadcastState; private float _nextNetworkHeartbeat; private float _nextMovementStatRefresh; private GameObject _underdogHudRoot; private Component _underdogHudText; private Type _tmpTextType; private Component _underdogHudPanel; private int _lastHealthCacheCount = -1; private float _nextPoll; private ulong _localSteamId; private GameObject _localPlayer; private object _localFpc; private bool _movementActive; private readonly List _movementFields = new List(); private bool _wasGrounded; private bool _boostedThisAir; private int _airJumpsRemaining; private bool _extraJumpArmed; private float _airborneSince; private Vector2 _takeoffHorizontal; private float _takeoffHorizontalSpeed; private bool _takeoffWasSprinting; private bool _loggedHealthScale; private float _observedBaseJumpY = 6.5f; private bool _loggedMovement; private Harmony _harmony; private bool _myceliumRegistered; private int _myceliumRegisterAttempts; private static int _hpSetterSeenLogs; private void Awake() { Instance = this; _healthMultiplier = ((BaseUnityPlugin)this).Config.Bind("Buff", "HealthMultiplier", 1.5f, "HOST ONLY. REAL base/max health multiplier. 2.0 turns base 4 HP into 8 HP. Joined clients ignore their local value."); _speedMultiplier = ((BaseUnityPlugin)this).Config.Bind("Buff", "SpeedMultiplier", 1.2f, "HOST ONLY. Walk/sprint speed multiplier. Joined clients ignore their local value."); _jumpMultiplier = ((BaseUnityPlugin)this).Config.Bind("Buff", "JumpMultiplier", 1.2f, "HOST ONLY. Vertical jump strength multiplier. Joined clients ignore their local value."); _extraJumps = ((BaseUnityPlugin)this).Config.Bind("Buff", "ExtraJumps", 1, "HOST ONLY. Extra mid-air jumps. Joined clients ignore their local value."); _pollSeconds = ((BaseUnityPlugin)this).Config.Bind("Advanced", "PollSeconds", 0.25f, "How often the host checks scores and syncs the underdog list."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Underdog Advantage 1.0.30 loaded from the known-good 1.0.17 movement/network branch. HP mode: direct base/max health."); } private void Start() { ((MonoBehaviour)this).StartCoroutine(RegisterMyceliumSafely()); } private void OnDestroy() { try { if ((Object)(object)_underdogHudRoot != (Object)null) { Object.Destroy((Object)(object)_underdogHudRoot); } } catch { } RestoreMovement(); if (_myceliumRegistered) { try { MyceliumNetwork.DeregisterNetworkObject((object)this, 4287319041u, 0); } catch { } } try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } if (Instance == this) { Instance = null; } } private void Update() { if (Time.unscaledTime >= _nextPoll) { _nextPoll = Time.unscaledTime + Mathf.Max(0.1f, _pollSeconds.Value); try { RefreshPlayersAndNetwork(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Refresh failed: " + ex.Message)); } } try { MaintainLocalMovement(); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Movement maintenance failed: " + ex2.Message)); } try { UpdateUnderdogHud(); } catch (Exception ex3) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("HUD update failed: " + ex3.Message)); } } private IEnumerator RegisterMyceliumSafely() { yield return null; while (!_myceliumRegistered && _myceliumRegisterAttempts < 100) { _myceliumRegisterAttempts++; try { MyceliumNetwork.RegisterNetworkObject((object)this, 4287319041u, 0); _myceliumRegistered = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Mycelium networking registered successfully."); yield break; } catch (Exception ex) { if (_myceliumRegisterAttempts == 1 || _myceliumRegisterAttempts % 10 == 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Mycelium registration retry " + _myceliumRegisterAttempts + ": " + ex.Message)); } } yield return (object)new WaitForSecondsRealtime(0.2f); } ((BaseUnityPlugin)this).Logger.LogError((object)"Mycelium registration failed after retries. Host/local gameplay still works, but joined-client sync is disabled for this session."); } private void PatchDamage() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown try { Type type = FindType("PlayerHealth"); if (type == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"PlayerHealth type not found; HP buff disabled."); return; } _harmony = new Harmony("com.openai.straftat.underdogbuff.healthsetter"); MethodInfo method = typeof(UnderdogBuff).GetMethod("HealthSetterPrefix", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo[] array = (from m in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == "sync___set_value_health" where m.GetParameters().Length >= 1 where IsNumeric(m.GetParameters()[0].ParameterType) select m).ToArray(); MethodInfo[] array2 = array; foreach (MethodInfo methodInfo in array2) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)("HP SYNC SETTER patch installed: " + methodInfo)); } if (array.Length == 0) { ((BaseUnityPlugin)this).Logger.LogError((object)"sync___set_value_health was not found; HP buff disabled."); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not patch health SyncVar setter: " + ex)); } } private static void HealthSetterPrefix(object __instance, object[] __args) { try { UnderdogBuff instance = Instance; if ((Object)(object)instance == (Object)null || __instance == null || __args == null || __args.Length == 0) { return; } bool flag = true; if (__args.Length >= 2 && __args[1] is bool flag2) { flag = flag2; } if (!flag) { return; } if (_hpSetterSeenLogs < 3) { _hpSetterSeenLogs++; ((BaseUnityPlugin)instance).Logger.LogInfo((object)("HP setter observed on server (diagnostic " + _hpSetterSeenLogs + "/3).")); } if (!instance._trailingHealthObjects.Contains(__instance)) { return; } Type type = __args[0]?.GetType(); if (type == null || !IsNumeric(type)) { return; } float num = Convert.ToSingle(__args[0]); float num2 = instance.ReadHealthValue(__instance); if (float.IsNaN(num2)) { return; } float num3 = num2 - num; if (!(num3 <= 0.0001f)) { float num4 = Mathf.Max(1f, instance._effectiveHealthMultiplier); if (!(num4 <= 1.0001f)) { float num5 = num3 / num4; float num6 = num2 - num5; __args[0] = ConvertNumeric(num6, type); ((BaseUnityPlugin)instance).Logger.LogInfo((object)$"HP BUFF ACTIVE: damage {num3:0.##} -> {num5:0.##}; HP {num2:0.##} -> {num6:0.##} (x{num4:0.##})."); } } } catch (Exception ex) { try { UnderdogBuff instance2 = Instance; if (instance2 != null) { ((BaseUnityPlugin)instance2).Logger.LogWarning((object)("HP SyncVar setter hook error: " + ex.Message)); } } catch { } } } private float ReadHealthValue(object health) { try { MethodInfo method = health.GetType().GetMethod("sync___get_value_health", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method != null) { object obj = method.Invoke(health, null); if (obj != null && IsNumeric(obj.GetType())) { return Convert.ToSingle(obj); } } object member = GetMember(health, "health"); if (member != null && IsNumeric(member.GetType())) { return Convert.ToSingle(member); } } catch { } return float.NaN; } private void UpdateUnderdogHud() { if (!_movementActive) { if ((Object)(object)_underdogHudRoot != (Object)null) { _underdogHudRoot.SetActive(false); } return; } if ((Object)(object)_underdogHudRoot == (Object)null || (Object)(object)_underdogHudText == (Object)null) { CreateUnderdogHud(); } if (!((Object)(object)_underdogHudRoot == (Object)null) && !((Object)(object)_underdogHudText == (Object)null)) { _underdogHudRoot.SetActive(true); string value = "UNDERDOG ADVANTAGE\n" + $"HP x{_effectiveHealthMultiplier:0.##} • " + $"SPD x{_effectiveSpeedMultiplier:0.##} • " + $"JMP x{_effectiveJumpMultiplier:0.##} • " + $"+{_effectiveExtraJumps} AIR"; SetMemberValue(_underdogHudText, "text", value); } } private void CreateUnderdogHud() { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown //IL_00c0: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0113: 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_0197: Expected O, but got Unknown //IL_01b5: 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_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) if ((object)_tmpTextType == null) { _tmpTextType = FindTypeCached("TMPro.TextMeshProUGUI"); } Type type = FindTypeCached("UnityEngine.Canvas"); Type type2 = FindTypeCached("UnityEngine.UI.Image"); if (_tmpTextType == null || type == null) { return; } Component val = Resources.FindObjectsOfTypeAll(type).OfType().FirstOrDefault((Func)((Component c) => (Object)(object)c != (Object)null && c.gameObject.activeInHierarchy)); if ((Object)(object)val == (Object)null) { return; } _underdogHudRoot = new GameObject("UnderdogAdvantage_HUD"); _underdogHudRoot.transform.SetParent(val.transform, false); RectTransform obj = _underdogHudRoot.AddComponent(); obj.anchorMin = new Vector2(0.5f, 1f); obj.anchorMax = new Vector2(0.5f, 1f); obj.pivot = new Vector2(0.5f, 1f); obj.anchoredPosition = new Vector2(0f, -22f); obj.sizeDelta = new Vector2(420f, 58f); if (type2 != null) { _underdogHudPanel = _underdogHudRoot.AddComponent(type2); if ((Object)(object)_underdogHudPanel != (Object)null) { SetMemberValue(_underdogHudPanel, "color", (object)new Color(0.02f, 0.02f, 0.025f, 0.72f)); SetMemberValue(_underdogHudPanel, "raycastTarget", false); } } GameObject val2 = new GameObject("Text"); val2.transform.SetParent(_underdogHudRoot.transform, false); RectTransform obj2 = val2.AddComponent(); obj2.anchorMin = Vector2.zero; obj2.anchorMax = Vector2.one; obj2.offsetMin = new Vector2(10f, 4f); obj2.offsetMax = new Vector2(-10f, -4f); _underdogHudText = val2.AddComponent(_tmpTextType); if ((Object)(object)_underdogHudText == (Object)null) { return; } SetMemberValue(_underdogHudText, "fontSize", 18f); SetMemberValue(_underdogHudText, "enableWordWrapping", false); SetMemberValue(_underdogHudText, "raycastTarget", false); SetMemberValue(_underdogHudText, "richText", true); SetMemberValue(_underdogHudText, "color", (object)new Color(1f, 0.82f, 0.28f, 1f)); PropertyInfo property = _tmpTextType.GetProperty("alignment", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite) { try { property.SetValue(_underdogHudText, Enum.ToObject(property.PropertyType, 514)); } catch { } } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Underdog Advantage HUD created."); } private Type FindTypeCached(string fullName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type type = assembly.GetType(fullName, throwOnError: false); if (type != null) { return type; } } catch { } } return null; } private void SetMemberValue(object obj, string name, object value) { if (obj == null) { return; } try { Type type = obj.GetType(); PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite) { object value2 = value; if (value != null && !property.PropertyType.IsInstanceOfType(value)) { value2 = Convert.ChangeType(value, property.PropertyType); } property.SetValue(obj, value2); return; } FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && !field.IsInitOnly) { object value3 = value; if (value != null && !field.FieldType.IsInstanceOfType(value)) { value3 = Convert.ChangeType(value, field.FieldType); } field.SetValue(obj, value3); } } catch { } } private void RefreshPlayersAndNetwork() { Type type = FindType("ClientInstance"); if (type == null) { return; } Dictionary playerInstances = GetPlayerInstances(type); if (playerInstances.Count == 0) { return; } _localSteamId = GetOwnSteamId(); object localPlayerController = GetLocalPlayerController(); object obj = ((localPlayerController is Component) ? localPlayerController : null); _localPlayer = ((obj != null) ? ((Component)obj).gameObject : null); bool flag = false; try { flag = MyceliumNetwork.InLobby && MyceliumNetwork.IsHost; } catch { } if (flag) { _effectiveHealthMultiplier = Mathf.Max(1f, _healthMultiplier.Value); _effectiveSpeedMultiplier = Mathf.Max(0.05f, _speedMultiplier.Value); _effectiveJumpMultiplier = Mathf.Max(0.05f, _jumpMultiplier.Value); _effectiveExtraJumps = Mathf.Max(0, _extraJumps.Value); _receivedHostSettings = true; HashSet hashSet = ComputeTrailingSteamIds(playerInstances); SetTrailingLocally(hashSet); RebuildTrailingHealthCache(playerInstances, hashSet); ApplyRealBaseHealth(); if (_myceliumRegistered) { string text = BuildHostState(hashSet); bool num = !string.Equals(text, _lastBroadcastState, StringComparison.Ordinal); bool flag2 = Time.unscaledTime >= _nextNetworkHeartbeat; if (num || flag2) { try { MyceliumNetwork.RPC(4287319041u, "ReceiveHostState", (ReliableType)1, new object[1] { text }); _lastBroadcastState = text; _nextNetworkHeartbeat = Time.unscaledTime + 2f; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Mycelium RPC failed: " + ex.Message)); } } } } if (_localSteamId != 0L && _trailingSteamIds.Contains(_localSteamId) && (Object)(object)_localPlayer != (Object)null) { EnableMovementIfNeeded(); } else { DisableMovementIfNeeded(); } } private void RebuildTrailingHealthCache(Dictionary players, HashSet trailing) { _trailingHealthObjects.Clear(); if (trailing == null || trailing.Count == 0) { return; } Type type = FindType("PlayerHealth"); Type type2 = FindType("PlayerManager"); if (type == null) { return; } foreach (KeyValuePair player in players) { object value = player.Value; ulong playerSteamId = GetPlayerSteamId(value); if (playerSteamId == 0L || !trailing.Contains(playerSteamId)) { continue; } try { object member = GetMember(value, "PlayerHealth", "playerHealth", "Health", "health"); if (member != null && type.IsInstanceOfType(member)) { _trailingHealthObjects.Add(member); } Component val = (Component)((value is Component) ? value : null); Component[] componentsInChildren; if ((Object)(object)val != (Object)null) { componentsInChildren = val.GetComponentsInChildren(type, true); foreach (Component val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null) { _trailingHealthObjects.Add(val2); } } } if ((Object)(object)val != (Object)null && type2 != null) { Component component = val.GetComponent(type2); if ((Object)(object)component != (Object)null) { object member2 = GetMember(component, "PlayerHealth", "playerHealth", "Health", "health"); if (member2 != null && type.IsInstanceOfType(member2)) { _trailingHealthObjects.Add(member2); } componentsInChildren = component.GetComponentsInChildren(type, true); foreach (Component val3 in componentsInChildren) { if ((Object)(object)val3 != (Object)null) { _trailingHealthObjects.Add(val3); } } } } GameObject spawnedPlayer = GetSpawnedPlayer(value); if (!((Object)(object)spawnedPlayer != (Object)null)) { continue; } componentsInChildren = spawnedPlayer.GetComponentsInChildren(type, true); foreach (Component val4 in componentsInChildren) { if ((Object)(object)val4 != (Object)null) { _trailingHealthObjects.Add(val4); } } Component componentInParent = spawnedPlayer.GetComponentInParent(type); if ((Object)(object)componentInParent != (Object)null) { _trailingHealthObjects.Add(componentInParent); } } catch { } } if (_trailingHealthObjects.Count != _lastHealthCacheCount) { _lastHealthCacheCount = _trailingHealthObjects.Count; if (_trailingHealthObjects.Count > 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("HP cache ready: " + _trailingHealthObjects.Count + " trailing PlayerHealth instance(s).")); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"HP cache is empty for current underdog(s); health scaling cannot apply until their PlayerHealth object is discovered."); } } } private void ApplyRealBaseHealth() { try { HashSet hashSet = new HashSet(_trailingHealthObjects, ReferenceEqualityComparer.Instance); float num = Mathf.Max(1f, _effectiveHealthMultiplier); foreach (object item in hashSet) { if (item == null) { continue; } if (!_baseMaxHealth.TryGetValue(item, out var value)) { value = ReadRawNumericField(item, "maxHealth"); if (float.IsNaN(value) || value <= 0f) { value = 4f; } _baseMaxHealth[item] = value; } float num2 = value * num; float value2; float num3 = (_lastAppliedHealthMultiplier.TryGetValue(item, out value2) ? value2 : (-1f)); bool flag = !_baseHealthBoosted.Contains(item); bool flag2 = Mathf.Abs(num3 - num) > 0.001f; WriteRawNumericField(item, "maxHealth", num2); if (flag || flag2) { float num4 = ReadHealthValue(item); if (!float.IsNaN(num4) && num4 < num2) { if (WriteRawHealthField(item, num2)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"REAL BASE HP APPLIED: max {value:0.##} -> {num2:0.##}; current {num4:0.##} -> {num2:0.##} (x{num:0.##})."); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"REAL BASE HP: maxHealth changed to {num2:0.##}, but raw current-health field was not found."); } } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"REAL BASE HP APPLIED: max {value:0.##} -> {num2:0.##} (x{num:0.##})."); } } _baseHealthBoosted.Add(item); _lastAppliedHealthMultiplier[item] = num; } object[] array = _baseHealthBoosted.ToArray(); foreach (object obj in array) { if (obj == null || hashSet.Contains(obj)) { continue; } if (_baseMaxHealth.TryGetValue(obj, out var value3)) { WriteRawNumericField(obj, "maxHealth", value3); float num5 = ReadHealthValue(obj); if (!float.IsNaN(num5) && num5 > value3) { WriteRawHealthField(obj, value3); } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"REAL BASE HP REMOVED: max restored to {value3:0.##}."); } _baseHealthBoosted.Remove(obj); _lastAppliedHealthMultiplier.Remove(obj); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Real base-health update failed: " + ex.Message)); } } private float ReadRawNumericField(object obj, string name) { try { FieldInfo fieldInfo = obj?.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null && IsNumeric(fieldInfo.FieldType)) { return Convert.ToSingle(fieldInfo.GetValue(obj)); } } catch { } return float.NaN; } private bool WriteRawNumericField(object obj, string name, float value) { try { FieldInfo fieldInfo = obj?.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo == null || !IsNumeric(fieldInfo.FieldType) || fieldInfo.IsInitOnly) { return false; } fieldInfo.SetValue(obj, ConvertNumeric(value, fieldInfo.FieldType)); return true; } catch { return false; } } private bool WriteRawHealthField(object hp, float value) { if (WriteRawNumericField(hp, "health", value)) { return true; } if (WriteRawNumericField(hp, "syncVar___health", value)) { return true; } return false; } private HashSet ComputeTrailingSteamIds(Dictionary players) { HashSet hashSet = new HashSet(); Type type = FindType("ScoreManager"); if (type == null || players.Count < 2) { return hashSet; } object staticMember = GetStaticMember(type, "Instance", "instance"); if (staticMember == null) { return hashSet; } MethodInfo method = type.GetMethod("GetTeamId", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null); MethodInfo method2 = type.GetMethod("GetPoints", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null); if (method == null || method2 == null) { return hashSet; } List> list = new List>(); foreach (KeyValuePair player in players) { try { ulong playerSteamId = GetPlayerSteamId(player.Value); if (playerSteamId != 0L) { int num = Convert.ToInt32(method.Invoke(staticMember, new object[1] { player.Key })); int item = Convert.ToInt32(method2.Invoke(staticMember, new object[1] { num })); list.Add(Tuple.Create(playerSteamId, item)); } } catch { } } if (list.Count < 2) { return hashSet; } int num2 = list.Min((Tuple x) => x.Item2); int num3 = list.Max((Tuple x) => x.Item2); if (num2 == num3) { return hashSet; } foreach (Tuple item2 in list) { if (item2.Item2 == num2) { hashSet.Add(item2.Item1); } } return hashSet; } private string BuildHostState(IEnumerable trailing) { string text = string.Join(",", trailing.Select((ulong x) => x.ToString()).ToArray()); return string.Join("|", text, _effectiveHealthMultiplier.ToString(CultureInfo.InvariantCulture), _effectiveSpeedMultiplier.ToString(CultureInfo.InvariantCulture), _effectiveJumpMultiplier.ToString(CultureInfo.InvariantCulture), _effectiveExtraJumps.ToString(CultureInfo.InvariantCulture)); } [CustomRPC] public void ReceiveHostState(string state) { try { try { if (MyceliumNetwork.InLobby && MyceliumNetwork.IsHost) { return; } } catch { } string[] array = (state ?? string.Empty).Split('|'); if (array.Length != 5) { return; } HashSet hashSet = new HashSet(); if (!string.IsNullOrWhiteSpace(array[0])) { string[] array2 = array[0].Split(','); for (int i = 0; i < array2.Length; i++) { if (ulong.TryParse(array2[i], out var result) && result != 0L) { hashSet.Add(result); } } } CultureInfo invariantCulture = CultureInfo.InvariantCulture; if (float.TryParse(array[1], NumberStyles.Float, invariantCulture, out var result2) && float.TryParse(array[2], NumberStyles.Float, invariantCulture, out var result3) && float.TryParse(array[3], NumberStyles.Float, invariantCulture, out var result4) && int.TryParse(array[4], NumberStyles.Integer, invariantCulture, out var result5)) { _effectiveHealthMultiplier = Mathf.Max(1f, result2); _effectiveSpeedMultiplier = Mathf.Max(0.05f, result3); _effectiveJumpMultiplier = Mathf.Max(0.05f, result4); _effectiveExtraJumps = Mathf.Max(0, result5); _receivedHostSettings = true; SetTrailingLocally(hashSet); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Host-state RPC parse failed: " + ex.Message)); } } private void SetTrailingLocally(IEnumerable ids) { _trailingSteamIds.Clear(); foreach (ulong id in ids) { _trailingSteamIds.Add(id); } } private Dictionary GetPlayerInstances(Type clientType) { Dictionary dictionary = new Dictionary(); if (GetStaticMember(clientType, "playerInstances", "PlayerInstances") is IDictionary dictionary2) { foreach (DictionaryEntry item in dictionary2) { try { dictionary[Convert.ToInt32(item.Key)] = item.Value; } catch { } } } return dictionary; } private ulong GetOwnSteamId() { try { object obj = (FindType("Steamworks.SteamUser")?.GetMethod("GetSteamID", BindingFlags.Static | BindingFlags.Public))?.Invoke(null, null); if (obj == null) { return 0uL; } object member = GetMember(obj, "m_SteamID", "SteamID", "Value", "value"); if (member != null && ulong.TryParse(Convert.ToString(member), out var result)) { return result; } if (ulong.TryParse(Convert.ToString(obj), out var result2)) { return result2; } } catch { } return 0uL; } private ulong GetPlayerSteamId(object client) { try { object member = GetMember(client, "PlayerSteamID", "playerSteamID", "SteamID", "steamID"); if (member == null) { return 0uL; } if (member is ulong result) { return result; } if (member is long result2) { return (ulong)result2; } object member2 = GetMember(member, "m_SteamID", "SteamID", "Value", "value"); if (member2 != null && ulong.TryParse(Convert.ToString(member2), out var result3)) { return result3; } if (ulong.TryParse(Convert.ToString(member), out var result4)) { return result4; } } catch { } return 0uL; } private GameObject GetSpawnedPlayer(object client) { try { Component val = (Component)((client is Component) ? client : null); if ((Object)(object)val == (Object)null) { return null; } Type type = FindType("PlayerManager"); if (type == null) { return null; } Component component = val.GetComponent(type); if ((Object)(object)component == (Object)null) { return null; } object member = GetMember(component, "SpawnedObject", "spawnedObject"); return (GameObject)((member is GameObject) ? member : null); } catch { return null; } } private void EnableMovementIfNeeded() { //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) object componentNamed = GetComponentNamed(_localPlayer, "FirstPersonController"); if (componentNamed != null && (!_movementActive || _localFpc != componentNamed)) { RestoreMovement(); _localFpc = componentNamed; _movementFields.Clear(); Type type = componentNamed.GetType(); AddMovementField(type, componentNamed, "walkSpeed", _effectiveSpeedMultiplier); AddMovementField(type, componentNamed, "sprintSpeed", _effectiveSpeedMultiplier); AddMovementField(type, componentNamed, "crouchSpeed", _effectiveSpeedMultiplier); AddMovementField(type, componentNamed, "airSpeed", _effectiveSpeedMultiplier); AddMovementField(type, componentNamed, "airSpeedFactor", _effectiveSpeedMultiplier); AddMovementField(type, componentNamed, "airControl", _effectiveSpeedMultiplier); AddMovementField(type, componentNamed, "airControlFactor", _effectiveSpeedMultiplier); AddMovementField(type, componentNamed, "airAcceleration", _effectiveSpeedMultiplier); AddMovementField(type, componentNamed, "jumpForce", _effectiveJumpMultiplier); AddMovementField(type, componentNamed, "jumpHeight", _effectiveJumpMultiplier); AddMovementField(type, componentNamed, "jumpPower", _effectiveJumpMultiplier); AddMovementField(type, componentNamed, "jumpFactor", _effectiveJumpMultiplier); _movementActive = true; _airJumpsRemaining = Mathf.Max(0, _effectiveExtraJumps); _wasGrounded = IsGrounded(componentNamed); _boostedThisAir = false; _extraJumpArmed = false; _airborneSince = 0f; _takeoffHorizontal = Vector2.zero; _takeoffHorizontalSpeed = 0f; _takeoffWasSprinting = false; _nextMovementStatRefresh = 0f; ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("Movement buff ON for local SteamID {0}. Runtime fields: {1}", _localSteamId, string.Join(", ", _movementFields.Select((FieldSnapshot x) => x.Field.Name)))); LogMovementInternalsOnce(type); } } private void AddMovementField(Type t, object target, string name, float multiplier) { FieldInfo field = t.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null) && IsNumeric(field.FieldType) && !field.IsStatic && !field.IsInitOnly) { object value = field.GetValue(target); float f = Convert.ToSingle(value); if (!float.IsNaN(f) && !float.IsInfinity(f)) { _movementFields.Add(new FieldSnapshot { Target = target, Field = field, Original = value, Multiplier = multiplier }); } } } private void MaintainLocalMovement() { //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: 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_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Unknown result type (might be due to invalid IL or missing references) if (!_movementActive || _localFpc == null) { return; } if (Time.unscaledTime >= _nextMovementStatRefresh) { _nextMovementStatRefresh = Time.unscaledTime + 0.05f; foreach (FieldSnapshot movementField in _movementFields) { try { float num = (movementField.Field.Name.ToLowerInvariant().Contains("jump") ? Mathf.Max(0.05f, _effectiveJumpMultiplier) : Mathf.Max(0.05f, _effectiveSpeedMultiplier)); SetNumeric(movementField.Field, movementField.Target, Convert.ToSingle(movementField.Original) * num); } catch { } } } bool flag = IsGrounded(_localFpc); FieldInfo field = _localFpc.GetType().GetField("moveDirection", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (flag) { _airJumpsRemaining = Mathf.Max(0, _effectiveExtraJumps); _boostedThisAir = false; _extraJumpArmed = false; _airborneSince = 0f; _takeoffHorizontal = Vector2.zero; _takeoffHorizontalSpeed = 0f; _takeoffWasSprinting = false; } else if (field != null && field.FieldType == typeof(Vector3)) { if (_wasGrounded) { _airborneSince = Time.unscaledTime; _extraJumpArmed = false; Vector3 val = (Vector3)field.GetValue(_localFpc); _takeoffHorizontal = new Vector2(val.x, val.z); _takeoffHorizontalSpeed = ((Vector2)(ref _takeoffHorizontal)).magnitude; _takeoffWasSprinting = IsSprintHeld(); } Vector3 val2 = (Vector3)field.GetValue(_localFpc); if (_takeoffHorizontalSpeed > 0.05f) { Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(val2.x, val2.z); float magnitude = ((Vector2)(ref val3)).magnitude; float num2 = _takeoffHorizontalSpeed; if (_takeoffWasSprinting) { num2 = Mathf.Max(num2, _takeoffHorizontalSpeed); } if (magnitude + 0.01f < num2) { Vector2 val4 = ((magnitude > 0.05f) ? (val3 / magnitude) : ((((Vector2)(ref _takeoffHorizontal)).sqrMagnitude > 0.001f) ? ((Vector2)(ref _takeoffHorizontal)).normalized : Vector2.zero)) * num2; val2.x = val4.x; val2.z = val4.y; field.SetValue(_localFpc, val2); } } if (!_boostedThisAir && val2.y > 0.15f) { _observedBaseJumpY = Mathf.Max(0.1f, val2.y); val2.y *= Mathf.Max(0.05f, _effectiveJumpMultiplier); field.SetValue(_localFpc, val2); _boostedThisAir = true; } if (!_extraJumpArmed && Time.unscaledTime - _airborneSince >= 0.08f && !SpaceHeld()) { _extraJumpArmed = true; } if (_airJumpsRemaining > 0 && _extraJumpArmed && SpacePressedThisFrame()) { val2 = (Vector3)field.GetValue(_localFpc); float num3 = (val2.y = Mathf.Max(2f, _observedBaseJumpY * Mathf.Max(0.05f, _effectiveJumpMultiplier))); field.SetValue(_localFpc, val2); TryPlayJumpSound(_localFpc); _airJumpsRemaining--; _extraJumpArmed = false; ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Extra jump fired ({_airJumpsRemaining} remaining), vertical velocity {num3:0.00}."); } } _wasGrounded = flag; } private bool IsGrounded(object fpc) { try { object member = GetMember(fpc, "characterController", "CharacterController"); CharacterController val = (CharacterController)((member is CharacterController) ? member : null); if (val != null) { return val.isGrounded; } FieldInfo fieldInfo = fpc.GetType().GetField("grounded", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? fpc.GetType().GetField("isGrounded", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null && fieldInfo.FieldType == typeof(bool)) { return (bool)fieldInfo.GetValue(fpc); } } catch { } return false; } private bool IsSprintHeld() { //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: 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) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) if (_localFpc == null) { return false; } string[] array = new string[5] { "isSprinting", "sprinting", "sprint", "Sprint", "m_Sprinting" }; foreach (string name in array) { try { FieldInfo field = _localFpc.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(bool)) { return (bool)field.GetValue(_localFpc); } PropertyInfo property = _localFpc.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead && property.PropertyType == typeof(bool)) { return (bool)property.GetValue(_localFpc); } } catch { } } try { FieldInfo field2 = _localFpc.GetType().GetField("moveDirection", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field3 = _localFpc.GetType().GetField("walkSpeed", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field2 != null && field3 != null && field2.FieldType == typeof(Vector3) && IsNumeric(field3.FieldType)) { Vector3 val = (Vector3)field2.GetValue(_localFpc); Vector2 val2 = new Vector2(val.x, val.z); float magnitude = ((Vector2)(ref val2)).magnitude; float num = Convert.ToSingle(field3.GetValue(_localFpc)); return magnitude > num * 1.05f; } } catch { } return false; } private bool SpacePressedThisFrame() { try { Type type = FindType("UnityEngine.Input"); Type type2 = FindType("UnityEngine.KeyCode"); if (type == null || type2 == null) { return false; } MethodInfo method = type.GetMethod("GetKeyDown", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { type2 }, null); if (method == null) { return false; } object obj = Enum.Parse(type2, "Space"); return Convert.ToBoolean(method.Invoke(null, new object[1] { obj })); } catch { return false; } } private bool SpaceHeld() { try { Type type = FindType("UnityEngine.Input"); Type type2 = FindType("UnityEngine.KeyCode"); if (type == null || type2 == null) { return false; } MethodInfo method = type.GetMethod("GetKey", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { type2 }, null); if (method == null) { return false; } object obj = Enum.Parse(type2, "Space"); return Convert.ToBoolean(method.Invoke(null, new object[1] { obj })); } catch { return false; } } private void TryPlayJumpSound(object fpc) { try { MethodInfo method = fpc.GetType().GetMethod("PlaySoundServer", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null); if (method != null) { method.Invoke(fpc, new object[1] { 23 }); } } catch { } } private void DisableMovementIfNeeded() { if (_movementActive) { RestoreMovement(); } } private void RestoreMovement() { for (int num = _movementFields.Count - 1; num >= 0; num--) { try { _movementFields[num].Field.SetValue(_movementFields[num].Target, _movementFields[num].Original); } catch { } } if (_movementActive) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Movement buff OFF for local player."); } _movementFields.Clear(); _movementActive = false; _localFpc = null; _airJumpsRemaining = 0; } private void LogMovementInternalsOnce(Type t) { if (_loggedMovement) { return; } _loggedMovement = true; try { string[] value = (from f in t.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where f.Name.IndexOf("jump", StringComparison.OrdinalIgnoreCase) >= 0 || f.Name.IndexOf("speed", StringComparison.OrdinalIgnoreCase) >= 0 || f.Name.IndexOf("ground", StringComparison.OrdinalIgnoreCase) >= 0 || f.Name.IndexOf("gravity", StringComparison.OrdinalIgnoreCase) >= 0 || f.Name.IndexOf("moveDirection", StringComparison.OrdinalIgnoreCase) >= 0 select f.Name + ":" + f.FieldType.Name).ToArray(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("FirstPersonController relevant fields: " + string.Join(", ", value))); } catch { } } private bool HasServerAuthority(object obj) { try { if (GetMember(obj, "IsServerInitialized", "IsServerStarted", "IsServer") is bool result) { return result; } } catch { } Type type = FindType("FishNet.InstanceFinder"); if (type != null) { try { if (GetMember(GetStaticMember(type, "ServerManager"), "Started", "IsStarted") is bool result2) { return result2; } } catch { } } return false; } private object GetLocalPlayerController() { try { Type type = FindType("Settings"); if (type == null) { return null; } return GetMember(GetStaticMember(type, "Instance", "instance"), "localPlayer", "LocalPlayer"); } catch { return null; } } private static object ConvertNumeric(float value, Type t) { if (t == typeof(float)) { return value; } if (t == typeof(double)) { return (double)value; } if (t == typeof(int)) { return Mathf.RoundToInt(value); } if (t == typeof(short)) { return (short)Mathf.RoundToInt(value); } if (t == typeof(byte)) { return (byte)Mathf.Clamp(Mathf.RoundToInt(value), 0, 255); } return Convert.ChangeType(value, t); } private static object GetDefault(Type t) { if (!t.IsValueType) { return null; } return Activator.CreateInstance(t); } private object GetComponentNamed(GameObject go, string typeName) { if ((Object)(object)go == (Object)null) { return null; } Type type = FindType(typeName); if (type == null) { return null; } Component component = go.GetComponent(type); if ((Object)(object)component != (Object)null) { return component; } component = go.GetComponentInChildren(type, true); if ((Object)(object)component != (Object)null) { return component; } return go.GetComponentInParent(type); } private static bool IsNumeric(Type t) { if (!(t == typeof(float)) && !(t == typeof(double)) && !(t == typeof(int)) && !(t == typeof(short))) { return t == typeof(byte); } return true; } private static void SetNumeric(FieldInfo f, object target, float value) { if (f.FieldType == typeof(float)) { f.SetValue(target, value); } else if (f.FieldType == typeof(double)) { f.SetValue(target, (double)value); } else if (f.FieldType == typeof(int)) { f.SetValue(target, Mathf.RoundToInt(value)); } else if (f.FieldType == typeof(short)) { f.SetValue(target, (short)Mathf.RoundToInt(value)); } } private static Type FindType(string fullOrSimpleName) { if (string.IsNullOrEmpty(fullOrSimpleName)) { return null; } if (_typeCache.TryGetValue(fullOrSimpleName, out var value)) { return value; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type type = assembly.GetType(fullOrSimpleName, throwOnError: false); if (type != null) { _typeCache[fullOrSimpleName] = type; return type; } Type type2 = assembly.GetTypes().FirstOrDefault((Type x) => x.Name == fullOrSimpleName); if (type2 != null) { _typeCache[fullOrSimpleName] = type2; return type2; } } catch { } } return null; } private static object GetStaticMember(Type t, params string[] names) { foreach (string name in names) { PropertyInfo property = t.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.GetGetMethod(nonPublic: true) != null && property.GetGetMethod(nonPublic: true).IsStatic) { try { return property.GetValue(null, null); } catch { } } FieldInfo field = t.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.IsStatic) { try { return field.GetValue(null); } catch { } } } return null; } private static object GetMember(object target, params string[] names) { if (target == null) { return null; } Type type = target.GetType(); foreach (string name in names) { PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead) { try { return property.GetValue(target, null); } catch { } } FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { try { return field.GetValue(target); } catch { } } } return null; } } }