Decompiled source of UnderdogAdvantage v1.0.30

BepInEx/plugins/UnderdogAdvantage/UnderdogBuff.dll

Decompiled 4 hours ago
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<object>
		{
			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<float> _healthMultiplier;

		private ConfigEntry<float> _speedMultiplier;

		private ConfigEntry<float> _jumpMultiplier;

		private ConfigEntry<int> _extraJumps;

		private ConfigEntry<float> _pollSeconds;

		private float _effectiveHealthMultiplier = 1f;

		private float _effectiveSpeedMultiplier = 1f;

		private float _effectiveJumpMultiplier = 1f;

		private int _effectiveExtraJumps;

		private bool _receivedHostSettings;

		private readonly HashSet<ulong> _trailingSteamIds = new HashSet<ulong>();

		private readonly HashSet<object> _trailingHealthObjects = new HashSet<object>(ReferenceEqualityComparer.Instance);

		private readonly Dictionary<object, float> _baseMaxHealth = new Dictionary<object, float>(ReferenceEqualityComparer.Instance);

		private readonly HashSet<object> _baseHealthBoosted = new HashSet<object>(ReferenceEqualityComparer.Instance);

		private readonly Dictionary<object, float> _lastAppliedHealthMultiplier = new Dictionary<object, float>(ReferenceEqualityComparer.Instance);

		private static readonly Dictionary<string, Type> _typeCache = new Dictionary<string, Type>();

		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<FieldSnapshot> _movementFields = new List<FieldSnapshot>();

		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<float>("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<float>("Buff", "SpeedMultiplier", 1.2f, "HOST ONLY. Walk/sprint speed multiplier. Joined clients ignore their local value.");
			_jumpMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Buff", "JumpMultiplier", 1.2f, "HOST ONLY. Vertical jump strength multiplier. Joined clients ignore their local value.");
			_extraJumps = ((BaseUnityPlugin)this).Config.Bind<int>("Buff", "ExtraJumps", 1, "HOST ONLY. Extra mid-air jumps. Joined clients ignore their local value.");
			_pollSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("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 = "<b><size=22>UNDERDOG ADVANTAGE</size></b>\n" + $"<size=12>HP <b>x{_effectiveHealthMultiplier:0.##}</b>   •   " + $"SPD <b>x{_effectiveSpeedMultiplier:0.##}</b>   •   " + $"JMP <b>x{_effectiveJumpMultiplier:0.##}</b>   •   " + $"+<b>{_effectiveExtraJumps}</b> AIR</size>";
				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<Component>().FirstOrDefault((Func<Component, bool>)((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<RectTransform>();
			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<RectTransform>();
			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<int, object> 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<ulong> 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<int, object> players, HashSet<ulong> trailing)
		{
			_trailingHealthObjects.Clear();
			if (trailing == null || trailing.Count == 0)
			{
				return;
			}
			Type type = FindType("PlayerHealth");
			Type type2 = FindType("PlayerManager");
			if (type == null)
			{
				return;
			}
			foreach (KeyValuePair<int, object> 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<object> hashSet = new HashSet<object>(_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<ulong> ComputeTrailingSteamIds(Dictionary<int, object> players)
		{
			HashSet<ulong> hashSet = new HashSet<ulong>();
			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<Tuple<ulong, int>> list = new List<Tuple<ulong, int>>();
			foreach (KeyValuePair<int, object> 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<ulong, int> x) => x.Item2);
			int num3 = list.Max((Tuple<ulong, int> x) => x.Item2);
			if (num2 == num3)
			{
				return hashSet;
			}
			foreach (Tuple<ulong, int> item2 in list)
			{
				if (item2.Item2 == num2)
				{
					hashSet.Add(item2.Item1);
				}
			}
			return hashSet;
		}

		private string BuildHostState(IEnumerable<ulong> 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<ulong> hashSet = new HashSet<ulong>();
				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<ulong> ids)
		{
			_trailingSteamIds.Clear();
			foreach (ulong id in ids)
			{
				_trailingSteamIds.Add(id);
			}
		}

		private Dictionary<int, object> GetPlayerInstances(Type clientType)
		{
			Dictionary<int, object> dictionary = new Dictionary<int, object>();
			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;
		}
	}
}