Decompiled source of FreeFly v1.3.0

plugins/FreeFly.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FreeFly.Core;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Peak;
using Photon.Pun;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Zorro.Core;

[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("FreeFly")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.3.0.0")]
[assembly: AssemblyInformationalVersion("1.3.0+10b34f8f1dde0b40b06c71c4c580ae21d6daaffb")]
[assembly: AssemblyProduct("FreeFly")]
[assembly: AssemblyTitle("FreeFly")]
[assembly: AssemblyVersion("1.3.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 FreeFly
{
	internal enum FlightStopReason
	{
		UserToggle,
		FeatureUnavailable,
		CharacterUnavailable,
		WarpStarted,
		PluginDestroyed
	}
	internal sealed class FlightRuntime
	{
		private readonly ModConfig _config;

		private readonly ManualLogSource _logger;

		private readonly FreeFlyInput _input;

		private readonly FreeFlyNotification _notification;

		private readonly Dictionary<Rigidbody, bool> _originalGravity = new Dictionary<Rigidbody, bool>();

		private readonly Dictionary<Collider, bool> _originalColliderState = new Dictionary<Collider, bool>();

		private Character? _flightCharacter;

		private bool _flightActive;

		public bool IsActive => _flightActive;

		public Character? ActiveCharacter => _flightCharacter;

		public FlightRuntime(ModConfig config, ManualLogSource logger, FreeFlyInput input, FreeFlyNotification notification)
		{
			_config = config;
			_logger = logger;
			_input = input;
			_notification = notification;
		}

		public bool TryStart(Character local)
		{
			if (!FreeFlyCharacterUtils.IsUsable(local) || (Object)(object)local.refs.ragdoll == (Object)null)
			{
				return false;
			}
			_flightCharacter = local;
			_originalGravity.Clear();
			_originalColliderState.Clear();
			foreach (Bodypart part in local.refs.ragdoll.partList)
			{
				if ((Object)(object)((part != null) ? part.Rig : null) != (Object)null)
				{
					_originalGravity[part.Rig] = part.Rig.useGravity;
				}
			}
			Collider[] componentsInChildren = ((Component)local.refs.ragdoll).GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null)
				{
					_originalColliderState[val] = val.enabled;
				}
			}
			local.refs.ragdoll.ToggleCollision(false);
			_flightActive = true;
			_notification.Show("Free flight enabled");
			_logger.LogInfo((object)"Free flight enabled.");
			return true;
		}

		public void Stop(FlightStopReason reason, bool notify = true)
		{
			if (!_flightActive && (Object)(object)_flightCharacter == (Object)null)
			{
				return;
			}
			Character flightCharacter = _flightCharacter;
			if ((Object)(object)flightCharacter != (Object)null && (Object)(object)flightCharacter.refs.ragdoll != (Object)null)
			{
				flightCharacter.refs.ragdoll.ToggleCollision(true);
				foreach (KeyValuePair<Collider, bool> item in _originalColliderState)
				{
					if ((Object)(object)item.Key != (Object)null)
					{
						item.Key.enabled = item.Value;
					}
				}
				foreach (Bodypart part in flightCharacter.refs.ragdoll.partList)
				{
					if ((Object)(object)((part != null) ? part.Rig : null) != (Object)null && _originalGravity.TryGetValue(part.Rig, out var value))
					{
						part.Rig.useGravity = value;
					}
				}
				flightCharacter.refs.ragdoll.HaltBodyVelocity(false);
			}
			_originalGravity.Clear();
			_originalColliderState.Clear();
			_flightCharacter = null;
			bool flightActive = _flightActive;
			_flightActive = false;
			if (flightActive)
			{
				if (notify)
				{
					_notification.Show("Free flight disabled");
				}
				_logger.LogDebug((object)("Free flight disabled: " + GetReasonText(reason) + "."));
			}
		}

		public void ApplyPhysics(CharacterMovement movement, bool menuOpen)
		{
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: 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_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: 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_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			if (!_flightActive || (Object)(object)_flightCharacter == (Object)null || (Object)(object)movement != (Object)(object)_flightCharacter.refs.movement)
			{
				return;
			}
			Character flightCharacter = _flightCharacter;
			if (!FreeFlyCharacterUtils.IsUsable(flightCharacter) || flightCharacter.warping)
			{
				Stop(flightCharacter.warping ? FlightStopReason.WarpStarted : FlightStopReason.CharacterUnavailable);
				return;
			}
			CharacterRagdoll ragdoll = flightCharacter.refs.ragdoll;
			foreach (Bodypart part in ragdoll.partList)
			{
				if ((Object)(object)((part != null) ? part.Rig : null) != (Object)null)
				{
					part.Rig.useGravity = false;
				}
			}
			Vector2 movementInput = _input.GetMovementInput(flightCharacter, menuOpen);
			Vector3 lookDirection_Flat = flightCharacter.data.lookDirection_Flat;
			Vector3 lookDirection_Right = flightCharacter.data.lookDirection_Right;
			Vector3 val = lookDirection_Flat * movementInput.y + lookDirection_Right * movementInput.x;
			bool flag = _input.ChordModifierHeld();
			int num;
			if (!_input.IsCrouchHeld(flightCharacter, menuOpen))
			{
				InputAction action_crouchToggle = CharacterInput.action_crouchToggle;
				num = ((action_crouchToggle != null && action_crouchToggle.IsPressed()) ? 1 : 0);
			}
			else
			{
				num = 1;
			}
			bool flag2 = (byte)num != 0;
			float num2 = (flag ? 0f : (_input.IsJumpHeld(flightCharacter, menuOpen) ? 1f : 0f));
			num2 -= (flag ? 0f : (flag2 ? 1f : 0f));
			Vector3 val2 = Vector3.ClampMagnitude(val + Vector3.up * num2, 1f);
			float num3 = FreeFlyMath.ApplySpeedModifiers(_config.SafeBaseSpeed, _input.SpeedUpHeld(), _input.SlowDownHeld(), _config.SafeSpeedUpMultiplier, _config.SafeSlowDownMultiplier);
			Vector3 val3 = val2 * num3 * Time.fixedDeltaTime;
			Vector3 linearVelocity = val2 * num3;
			ragdoll.HaltBodyVelocity(false);
			foreach (Bodypart part2 in ragdoll.partList)
			{
				if ((Object)(object)((part2 != null) ? part2.Rig : null) == (Object)null)
				{
					continue;
				}
				if (part2.Rig.isKinematic)
				{
					if (FreeFlyCharacterUtils.IsFinite(val3) && ((Vector3)(ref val3)).sqrMagnitude > 0f)
					{
						Rigidbody rig = part2.Rig;
						rig.position += val3;
					}
				}
				else
				{
					part2.Rig.linearVelocity = linearVelocity;
				}
			}
			flightCharacter.data.isGrounded = true;
			flightCharacter.data.sinceGrounded = 0f;
			flightCharacter.data.sinceJump = 0f;
		}

		private static string GetReasonText(FlightStopReason reason)
		{
			return reason switch
			{
				FlightStopReason.UserToggle => "toggle pressed", 
				FlightStopReason.FeatureUnavailable => "feature unavailable", 
				FlightStopReason.CharacterUnavailable => "character became unavailable", 
				FlightStopReason.WarpStarted => "character changed or PEAK warp started", 
				FlightStopReason.PluginDestroyed => "plugin destroyed", 
				_ => "unknown reason", 
			};
		}
	}
	internal static class FreeFlyCharacterUtils
	{
		public static bool IsUsable(Character character)
		{
			if ((Object)(object)character == (Object)(object)Character.localCharacter && (Object)(object)character.data != (Object)null && (Object)(object)character.refs.ragdoll != (Object)null)
			{
				return (Object)(object)character.refs.view != (Object)null;
			}
			return false;
		}

		public static bool IsFinite(Vector3 value)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (FreeFlyMath.IsFinite(value.x) && FreeFlyMath.IsFinite(value.y))
			{
				return FreeFlyMath.IsFinite(value.z);
			}
			return false;
		}
	}
	internal sealed class FreeFlyController
	{
		private readonly ModConfig _config;

		private readonly FreeFlyInput _input;

		private readonly FlightRuntime _flight;

		private readonly TeleportDestinationService _destinations;

		private readonly TeleportMenuView _menu;

		private PatchCapabilities _capabilities;

		public FreeFlyController(ModConfig config, FreeFlyInput input, FlightRuntime flight, TeleportDestinationService destinations, TeleportMenuView menu)
		{
			_config = config;
			_input = input;
			_flight = flight;
			_destinations = destinations;
			_menu = menu;
		}

		public void SetCapabilities(PatchCapabilities capabilities)
		{
			_capabilities = capabilities;
			_destinations.SetCapabilities(capabilities);
		}

		public void TickUpdate()
		{
			Character localCharacter = Character.localCharacter;
			if (!_config.Enabled.Value || !_capabilities.FlightPatch || (Object)(object)localCharacter == (Object)null || (Object)(object)localCharacter.data == (Object)null)
			{
				_flight.Stop(FlightStopReason.FeatureUnavailable);
				_menu.Close();
				return;
			}
			if (_flight.IsActive && ((Object)(object)_flight.ActiveCharacter != (Object)(object)localCharacter || localCharacter.warping))
			{
				_flight.Stop(localCharacter.warping ? FlightStopReason.WarpStarted : FlightStopReason.CharacterUnavailable);
			}
			FreeFlyInputSnapshot input = _input.ReadSnapshot();
			if (_menu.IsOpen)
			{
				if (input.MenuToggle)
				{
					_menu.Close();
				}
				else if (!input.FlightToggle)
				{
					_menu.Tick(input);
				}
			}
			else if (input.MenuToggle && _input.CanUseInput())
			{
				_menu.Open();
			}
			else if (input.FlightToggle && _input.CanUseInput())
			{
				if (_flight.IsActive)
				{
					_flight.Stop(FlightStopReason.UserToggle);
				}
				else
				{
					_flight.TryStart(localCharacter);
				}
			}
		}

		public void ApplyFlightPhysics(CharacterMovement movement)
		{
			_flight.ApplyPhysics(movement, _menu.IsOpen);
		}

		public void DrawMenu()
		{
			_menu.Draw();
		}

		public void Shutdown()
		{
			_menu.Shutdown();
			_flight.Stop(FlightStopReason.PluginDestroyed, notify: false);
			_input.Dispose();
		}
	}
	internal sealed class FreeFlyMenuWindow : MenuWindow
	{
		public override bool selectOnOpen => false;
	}
	internal readonly struct FreeFlyInputSnapshot
	{
		public bool MenuToggle { get; }

		public bool FlightToggle { get; }

		public bool Cancel { get; }

		public bool Confirm { get; }

		public bool Up { get; }

		public bool Down { get; }

		public FreeFlyInputSnapshot(bool menuToggle, bool flightToggle, bool cancel, bool confirm, bool up, bool down)
		{
			MenuToggle = menuToggle;
			FlightToggle = flightToggle;
			Cancel = cancel;
			Confirm = confirm;
			Up = up;
			Down = down;
		}
	}
	internal sealed class FreeFlyInput : IDisposable
	{
		private readonly ModConfig _config;

		private readonly ManualLogSource _logger;

		private InputAction? _flightToggleAction;

		private InputAction? _teleportMenuToggleAction;

		private InputAction? _controllerChordModifierAction;

		private InputAction? _speedUpKeyboardAction;

		private InputAction? _slowDownKeyboardAction;

		private InputAction? _speedUpControllerAction;

		private InputAction? _slowDownControllerAction;

		private InputAction? _cancelAction;

		private InputAction? _confirmAction;

		private InputAction? _upAction;

		private InputAction? _downAction;

		public FreeFlyInput(ModConfig config, ManualLogSource logger)
		{
			_config = config;
			_logger = logger;
			BindNavigationActions();
			BindConfiguredActions();
			_config.ToggleFlightKeyboardPath.SettingChanged += OnBindingPathChanged;
			_config.TeleportMenuKeyboardPath.SettingChanged += OnBindingPathChanged;
			_config.ControllerChordModifierPath.SettingChanged += OnBindingPathChanged;
			_config.ControllerFlightTogglePath.SettingChanged += OnBindingPathChanged;
			_config.ControllerTeleportMenuTogglePath.SettingChanged += OnBindingPathChanged;
			_config.SpeedUpKeyboardPath.SettingChanged += OnBindingPathChanged;
			_config.SlowDownKeyboardPath.SettingChanged += OnBindingPathChanged;
			_config.SpeedUpControllerPath.SettingChanged += OnBindingPathChanged;
			_config.SlowDownControllerPath.SettingChanged += OnBindingPathChanged;
		}

		public FreeFlyInputSnapshot ReadSnapshot()
		{
			return new FreeFlyInputSnapshot(WasPressedThisFrame(_teleportMenuToggleAction), WasPressedThisFrame(_flightToggleAction), WasPressedThisFrame(_cancelAction), WasPressedThisFrame(_confirmAction), WasPressedThisFrame(_upAction), WasPressedThisFrame(_downAction));
		}

		public bool SpeedUpHeld()
		{
			if (!IsActionHeld(_speedUpKeyboardAction))
			{
				if (!ChordModifierHeld())
				{
					InputAction? speedUpControllerAction = _speedUpControllerAction;
					if (speedUpControllerAction == null)
					{
						return false;
					}
					return speedUpControllerAction.IsPressed();
				}
				return false;
			}
			return true;
		}

		public bool SlowDownHeld()
		{
			if (!IsActionHeld(_slowDownKeyboardAction))
			{
				if (!ChordModifierHeld())
				{
					InputAction? slowDownControllerAction = _slowDownControllerAction;
					if (slowDownControllerAction == null)
					{
						return false;
					}
					return slowDownControllerAction.IsPressed();
				}
				return false;
			}
			return true;
		}

		public bool ChordModifierHeld()
		{
			InputAction? controllerChordModifierAction = _controllerChordModifierAction;
			if (controllerChordModifierAction == null)
			{
				return false;
			}
			return controllerChordModifierAction.IsPressed();
		}

		public Vector2 GetMovementInput(Character local, bool menuOpen)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			if (!menuOpen)
			{
				return Vector2.ClampMagnitude(local.input.movementInput, 1f);
			}
			InputAction action_move = CharacterInput.action_move;
			Vector2 val = ((action_move != null) ? action_move.ReadValue<Vector2>() : Vector2.zero);
			if (IsActionHeld(CharacterInput.action_moveForward))
			{
				val += Vector2.up;
			}
			if (IsActionHeld(CharacterInput.action_moveBackward))
			{
				val -= Vector2.up;
			}
			if (IsActionHeld(CharacterInput.action_moveRight))
			{
				val += Vector2.right;
			}
			if (IsActionHeld(CharacterInput.action_moveLeft))
			{
				val -= Vector2.right;
			}
			return Vector2.ClampMagnitude(val, 1f);
		}

		public bool IsJumpHeld(Character local, bool menuOpen)
		{
			if (!menuOpen)
			{
				return local.input.jumpIsPressed;
			}
			return IsActionHeld(CharacterInput.action_jump);
		}

		public bool IsCrouchHeld(Character local, bool menuOpen)
		{
			if (!menuOpen)
			{
				return local.input.crouchIsPressed;
			}
			return IsActionHeld(CharacterInput.action_crouch);
		}

		public bool CanUseInput()
		{
			GUIManager instance = GUIManager.instance;
			if (Time.timeScale > 0f && (Object)(object)instance != (Object)null && !instance.windowBlockingInput)
			{
				return !instance.wheelActive;
			}
			return false;
		}

		public void Dispose()
		{
			_config.ToggleFlightKeyboardPath.SettingChanged -= OnBindingPathChanged;
			_config.TeleportMenuKeyboardPath.SettingChanged -= OnBindingPathChanged;
			_config.ControllerChordModifierPath.SettingChanged -= OnBindingPathChanged;
			_config.ControllerFlightTogglePath.SettingChanged -= OnBindingPathChanged;
			_config.ControllerTeleportMenuTogglePath.SettingChanged -= OnBindingPathChanged;
			_config.SpeedUpKeyboardPath.SettingChanged -= OnBindingPathChanged;
			_config.SlowDownKeyboardPath.SettingChanged -= OnBindingPathChanged;
			_config.SpeedUpControllerPath.SettingChanged -= OnBindingPathChanged;
			_config.SlowDownControllerPath.SettingChanged -= OnBindingPathChanged;
			DisposeConfiguredActions();
			DisposeAction(ref _cancelAction);
			DisposeAction(ref _confirmAction);
			DisposeAction(ref _upAction);
			DisposeAction(ref _downAction);
		}

		private void OnBindingPathChanged(object sender, EventArgs eventArgs)
		{
			BindConfiguredActions();
		}

		private void BindConfiguredActions()
		{
			DisposeConfiguredActions();
			string keyboardPath = Normalize(_config.ToggleFlightKeyboardPath.Value);
			string keyboardPath2 = Normalize(_config.TeleportMenuKeyboardPath.Value);
			string text = Normalize(_config.ControllerChordModifierPath.Value);
			string controllerPath = Normalize(_config.ControllerFlightTogglePath.Value);
			string controllerPath2 = Normalize(_config.ControllerTeleportMenuTogglePath.Value);
			string text2 = Normalize(_config.SpeedUpKeyboardPath.Value);
			string text3 = Normalize(_config.SlowDownKeyboardPath.Value);
			string text4 = Normalize(_config.SpeedUpControllerPath.Value);
			string text5 = Normalize(_config.SlowDownControllerPath.Value);
			_controllerChordModifierAction = TryCreateButtonAction("FreeFly Controller Chord Modifier", "controller modifier", text);
			_flightToggleAction = TryCreateToggleAction("FreeFly Flight Toggle", "flight toggle", keyboardPath, controllerPath, text);
			_teleportMenuToggleAction = TryCreateToggleAction("FreeFly Teleport Menu Toggle", "teleport menu toggle", keyboardPath2, controllerPath2, text);
			_speedUpKeyboardAction = TryCreateButtonAction("FreeFly Keyboard Speed Up", "keyboard speed-up", text2);
			_slowDownKeyboardAction = TryCreateButtonAction("FreeFly Keyboard Slow Down", "keyboard slow-down", text3);
			_speedUpControllerAction = TryCreateButtonAction("FreeFly Controller Speed Up", "controller speed-up", text4);
			_slowDownControllerAction = TryCreateButtonAction("FreeFly Controller Slow Down", "controller slow-down", text5);
		}

		private void BindNavigationActions()
		{
			_cancelAction = TryCreateButtonAction("FreeFly Menu Cancel", "menu cancel", "<Keyboard>/escape", "<Gamepad>/buttonEast");
			_confirmAction = TryCreateButtonAction("FreeFly Menu Confirm", "menu confirm", "<Keyboard>/enter", "<Gamepad>/buttonSouth");
			_upAction = TryCreateButtonAction("FreeFly Menu Up", "menu up", "<Keyboard>/upArrow", "<Gamepad>/dpad/up");
			_downAction = TryCreateButtonAction("FreeFly Menu Down", "menu down", "<Keyboard>/downArrow", "<Gamepad>/dpad/down");
		}

		private InputAction? TryCreateToggleAction(string name, string description, string keyboardPath, string controllerPath, string modifierPath)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (keyboardPath.Length == 0 && controllerPath.Length == 0)
			{
				return null;
			}
			InputAction val = null;
			try
			{
				val = new InputAction(name, (InputActionType)1, (string)null, (string)null, (string)null, (string)null);
				if (keyboardPath.Length > 0)
				{
					InputActionSetupExtensions.AddBinding(val, keyboardPath, (string)null, (string)null, (string)null);
				}
				if (controllerPath.Length > 0)
				{
					if (modifierPath.Length == 0)
					{
						InputActionSetupExtensions.AddBinding(val, controllerPath, (string)null, (string)null, (string)null);
					}
					else
					{
						CompositeSyntax val2 = InputActionSetupExtensions.AddCompositeBinding(val, "OneModifier", (string)null, (string)null);
						val2 = ((CompositeSyntax)(ref val2)).With("modifier", modifierPath, (string)null, (string)null);
						((CompositeSyntax)(ref val2)).With("binding", controllerPath, (string)null, (string)null);
					}
				}
				val.Enable();
				return val;
			}
			catch (Exception ex)
			{
				if (val != null)
				{
					val.Dispose();
				}
				_logger.LogWarning((object)("Could not bind the configured " + description + " paths; the action is disabled: " + ex.Message));
				return null;
			}
		}

		private InputAction? TryCreateButtonAction(string name, string description, params string[] paths)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			InputAction val = null;
			try
			{
				val = new InputAction(name, (InputActionType)1, (string)null, (string)null, (string)null, (string)null);
				bool flag = false;
				foreach (string text in paths)
				{
					if (text.Length != 0)
					{
						InputActionSetupExtensions.AddBinding(val, text, (string)null, (string)null, (string)null);
						flag = true;
					}
				}
				if (!flag)
				{
					val.Dispose();
					return null;
				}
				val.Enable();
				return val;
			}
			catch (Exception ex)
			{
				if (val != null)
				{
					val.Dispose();
				}
				_logger.LogWarning((object)("Could not bind the configured " + description + " paths; the action is disabled: " + ex.Message));
				return null;
			}
		}

		private void DisposeConfiguredActions()
		{
			DisposeAction(ref _flightToggleAction);
			DisposeAction(ref _teleportMenuToggleAction);
			DisposeAction(ref _controllerChordModifierAction);
			DisposeAction(ref _speedUpKeyboardAction);
			DisposeAction(ref _slowDownKeyboardAction);
			DisposeAction(ref _speedUpControllerAction);
			DisposeAction(ref _slowDownControllerAction);
		}

		private static void DisposeAction(ref InputAction? action)
		{
			if (action != null)
			{
				action.Disable();
				action.Dispose();
				action = null;
			}
		}

		private static string Normalize(string? path)
		{
			return FreeFlyInputRules.NormalizeBindingPath(path);
		}

		private static bool IsActionHeld(InputAction? action)
		{
			if (action == null)
			{
				return false;
			}
			return action.IsPressed();
		}

		private static bool WasPressedThisFrame(InputAction? action)
		{
			if (action == null)
			{
				return false;
			}
			return action.WasPressedThisFrame();
		}
	}
	internal sealed class FreeFlyNotification : MonoBehaviour
	{
		private TextMeshProUGUI? _label;

		private Material? _labelMaterial;

		private CanvasGroup? _group;

		private Coroutine? _routine;

		public void Show(string message)
		{
			if (EnsureLabel() && !((Object)(object)_label == (Object)null) && !((Object)(object)_group == (Object)null))
			{
				((TMP_Text)_label).text = message;
				((TMP_Text)_label).transform.SetAsLastSibling();
				if (_routine != null)
				{
					((MonoBehaviour)this).StopCoroutine(_routine);
				}
				_routine = ((MonoBehaviour)this).StartCoroutine(ShowRoutine());
			}
		}

		private bool EnsureLabel()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Expected O, but got Unknown
			if ((Object)(object)_label != (Object)null && (Object)(object)_group != (Object)null)
			{
				return true;
			}
			if ((Object)(object)GUIManager.instance == (Object)null || (Object)(object)GUIManager.instance.hudCanvas == (Object)null)
			{
				return false;
			}
			GameObject val = new GameObject("FreeFly Notification", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasGroup),
				typeof(TextMeshProUGUI)
			});
			val.transform.SetParent(((Component)GUIManager.instance.hudCanvas).transform, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 1f);
			component.anchorMax = new Vector2(0.5f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.anchoredPosition = new Vector2(0f, -96f);
			component.sizeDelta = new Vector2(520f, 52f);
			_group = val.GetComponent<CanvasGroup>();
			_group.alpha = 0f;
			_group.blocksRaycasts = false;
			_group.interactable = false;
			_label = val.GetComponent<TextMeshProUGUI>();
			((TMP_Text)_label).alignment = (TextAlignmentOptions)514;
			((TMP_Text)_label).fontSize = 30f;
			TextMeshProUGUI val2 = GUIManager.instance.interactNameText ?? GUIManager.instance.itemPromptMain;
			if ((Object)(object)val2 != (Object)null && (Object)(object)((TMP_Text)val2).font != (Object)null)
			{
				((TMP_Text)_label).font = ((TMP_Text)val2).font;
				((TMP_Text)_label).fontStyle = ((TMP_Text)val2).fontStyle;
				if ((Object)(object)((TMP_Text)val2).fontSharedMaterial != (Object)null)
				{
					_labelMaterial = new Material(((TMP_Text)val2).fontSharedMaterial);
					((TMP_Text)_label).fontSharedMaterial = _labelMaterial;
				}
			}
			((TMP_Text)_label).faceColor = Color32.op_Implicit(Color.white);
			((TMP_Text)_label).outlineColor = Color32.op_Implicit(Color.black);
			((TMP_Text)_label).outlineWidth = 0.08f;
			((Graphic)_label).raycastTarget = false;
			return true;
		}

		private IEnumerator ShowRoutine()
		{
			if (!((Object)(object)_group == (Object)null))
			{
				_group.alpha = 1f;
				yield return (object)new WaitForSecondsRealtime(1.25f);
				float elapsed = 0f;
				while (elapsed < 0.25f && (Object)(object)_group != (Object)null)
				{
					elapsed += Time.unscaledDeltaTime;
					_group.alpha = 1f - Mathf.Clamp01(elapsed / 0.25f);
					yield return null;
				}
				if ((Object)(object)_group != (Object)null)
				{
					_group.alpha = 0f;
				}
				_routine = null;
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_label != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_label).gameObject);
			}
			if ((Object)(object)_labelMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_labelMaterial);
			}
		}
	}
	internal sealed class ModConfig
	{
		private const float DefaultBaseSpeed = 100f;

		private const float DefaultSpeedUpMultiplier = 2f;

		private const float DefaultSlowDownMultiplier = 0.2f;

		private const float DefaultTeleportVerticalOffset = 2f;

		private const float DefaultTeleportBackwardOffset = 1.5f;

		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<string> ToggleFlightKeyboardPath { get; }

		public ConfigEntry<string> TeleportMenuKeyboardPath { get; }

		public ConfigEntry<string> ControllerChordModifierPath { get; }

		public ConfigEntry<string> ControllerFlightTogglePath { get; }

		public ConfigEntry<string> ControllerTeleportMenuTogglePath { get; }

		public ConfigEntry<string> SpeedUpKeyboardPath { get; }

		public ConfigEntry<string> SlowDownKeyboardPath { get; }

		public ConfigEntry<string> SpeedUpControllerPath { get; }

		public ConfigEntry<string> SlowDownControllerPath { get; }

		public ConfigEntry<float> BaseSpeed { get; }

		public ConfigEntry<float> SpeedUpMultiplier { get; }

		public ConfigEntry<float> SlowDownMultiplier { get; }

		public ConfigEntry<float> TeleportVerticalOffset { get; }

		public ConfigEntry<float> TeleportBackwardOffset { get; }

		public float SafeBaseSpeed => SafeRange(BaseSpeed.Value, 1f, 1000f, 100f);

		public float SafeSpeedUpMultiplier => SafeRange(SpeedUpMultiplier.Value, 1f, 10f, 2f);

		public float SafeSlowDownMultiplier => SafeRange(SlowDownMultiplier.Value, 0.05f, 1f, 0.2f);

		public float SafeTeleportVerticalOffset => SafeRange(TeleportVerticalOffset.Value, 0f, 10f, 2f);

		public float SafeTeleportBackwardOffset => SafeRange(TeleportBackwardOffset.Value, 0f, 10f, 1.5f);

		public ModConfig(ConfigFile config)
		{
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Expected O, but got Unknown
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Expected O, but got Unknown
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Expected O, but got Unknown
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Expected O, but got Unknown
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Expected O, but got Unknown
			Enabled = config.Bind<bool>("General", "Enabled", true, "Enable local free flight and teammate teleport.");
			ToggleFlightKeyboardPath = config.Bind<string>("Controls", "Toggle Flight Keyboard Path", "<Keyboard>/f6", "Unity Input System control path used to toggle free flight with a keyboard. Leave empty to disable.");
			TeleportMenuKeyboardPath = config.Bind<string>("Controls", "Teleport Menu Keyboard Path", "<Keyboard>/f7", "Unity Input System control path used to open the teammate teleport menu with a keyboard. Leave empty to disable.");
			ControllerChordModifierPath = config.Bind<string>("Controls", "Controller Chord Modifier Path", "<Gamepad>/select", "Controller button held as the optional modifier for the flight and teleport menu shortcuts. Leave empty for single-button mode. Common paths: <Gamepad>/select = View/Share; <Gamepad>/start = Menu/Options; <Gamepad>/leftShoulder = LB/L1; <Gamepad>/rightShoulder = RB/R1; <Gamepad>/buttonSouth = A/Cross; <Gamepad>/buttonEast = B/Circle; <Gamepad>/buttonWest = X/Square; <Gamepad>/buttonNorth = Y/Triangle; <Gamepad>/leftTrigger = LT/L2; <Gamepad>/rightTrigger = RT/R2; <Gamepad>/leftStickPress and <Gamepad>/rightStickPress; <Gamepad>/dpad/up, <Gamepad>/dpad/down, <Gamepad>/dpad/left, and <Gamepad>/dpad/right. These semantic paths require a device recognized as Gamepad.");
			ControllerFlightTogglePath = config.Bind<string>("Controls", "Controller Flight Toggle Path", "<Gamepad>/leftShoulder", "Controller button pressed with the optional modifier to toggle free flight. Default: <Gamepad>/leftShoulder (Xbox LB / PlayStation L1). Leave empty to disable.");
			ControllerTeleportMenuTogglePath = config.Bind<string>("Controls", "Controller Teleport Menu Toggle Path", "<Gamepad>/rightShoulder", "Controller button pressed with the optional modifier to toggle the teleport menu. Default: <Gamepad>/rightShoulder (Xbox RB / PlayStation R1). Leave empty to disable.");
			SpeedUpKeyboardPath = config.Bind<string>("Controls", "Speed Up Keyboard Path", "<Keyboard>/leftShift", "Unity Input System control path held to temporarily increase flight speed with a keyboard. Leave empty to disable.");
			SlowDownKeyboardPath = config.Bind<string>("Controls", "Slow Down Keyboard Path", "<Keyboard>/leftAlt", "Unity Input System control path held to temporarily decrease flight speed with a keyboard. Leave empty to disable.");
			SpeedUpControllerPath = config.Bind<string>("Controls", "Speed Up Controller Path", "<Gamepad>/rightShoulder", "Unity Input System path held to temporarily increase flight speed. Default: <Gamepad>/rightShoulder (Xbox RB / PlayStation R1). Leave empty to disable.");
			SlowDownControllerPath = config.Bind<string>("Controls", "Slow Down Controller Path", "<Gamepad>/leftShoulder", "Unity Input System path held to temporarily decrease flight speed. Default: <Gamepad>/leftShoulder (Xbox LB / PlayStation L1). Leave empty to disable.");
			BaseSpeed = config.Bind<float>("Movement", "Base Speed", 100f, new ConfigDescription("Base flight speed in meters per second.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 1000f), Array.Empty<object>()));
			SpeedUpMultiplier = config.Bind<float>("Movement", "Speed Up Multiplier", 2f, new ConfigDescription("Multiplier while the configured speed-up key or controller path is held.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
			SlowDownMultiplier = config.Bind<float>("Movement", "Slow Down Multiplier", 0.2f, new ConfigDescription("Multiplier while the configured slow-down key or controller path is held.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>()));
			TeleportVerticalOffset = config.Bind<float>("Teleport", "Vertical Offset", 2f, new ConfigDescription("Height above the selected teammate's center when teleporting.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			TeleportBackwardOffset = config.Bind<float>("Teleport", "Backward Offset", 1.5f, new ConfigDescription("Distance behind the selected teammate when teleporting.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
		}

		private static float SafeRange(float value, float min, float max, float fallback)
		{
			if (float.IsNaN(value) || float.IsInfinity(value))
			{
				return fallback;
			}
			return Mathf.Clamp(value, min, max);
		}
	}
	internal readonly struct PatchCapabilities
	{
		public bool FlightPatch { get; }

		public bool TeleportPatch { get; }

		public PatchCapabilities(bool flightPatch, bool teleportPatch)
		{
			FlightPatch = flightPatch;
			TeleportPatch = teleportPatch;
		}
	}
	internal static class PatchInstaller
	{
		public static PatchCapabilities Install(Harmony harmony, ManualLogSource logger)
		{
			bool flightPatch = TryPatch(harmony, AccessTools.Method(typeof(CharacterMovement), "FixedUpdate", (Type[])null, (Type[])null), AccessTools.Method(typeof(PatchCallbacks), "CharacterMovementFixedPostfix", (Type[])null, (Type[])null), "CharacterMovement.FixedUpdate", logger);
			bool flag = AccessTools.Method(typeof(Character), "WarpPlayerRPC", (Type[])null, (Type[])null) != null;
			if (!flag)
			{
				logger.LogError((object)"PEAK's Character.WarpPlayerRPC was not found; teleport is disabled.");
			}
			return new PatchCapabilities(flightPatch, flag);
		}

		private static bool TryPatch(Harmony harmony, MethodInfo? original, MethodInfo? postfix, string description, ManualLogSource logger)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			if (original == null || postfix == null)
			{
				logger.LogError((object)("Required patch target is missing: " + description + "."));
				return false;
			}
			try
			{
				harmony.Patch((MethodBase)original, (HarmonyMethod)null, new HarmonyMethod(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				return true;
			}
			catch (Exception arg)
			{
				logger.LogError((object)$"Failed to patch {description}: {arg}");
				return false;
			}
		}
	}
	internal static class PatchCallbacks
	{
		public static void CharacterMovementFixedPostfix(CharacterMovement __instance)
		{
			Plugin.Instance?.Controller.ApplyFlightPhysics(__instance);
		}
	}
	[BepInPlugin("com.github.lllei.FreeFly", "FreeFly", "1.3.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.github.lllei.FreeFly";

		public const string PluginName = "FreeFly";

		private FreeFlyNotification? _notification;

		private Harmony? _harmony;

		internal static Plugin? Instance { get; private set; }

		internal FreeFlyController Controller { get; private set; }

		private void Awake()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			Instance = this;
			ModConfig config = new ModConfig(((BaseUnityPlugin)this).Config);
			_notification = ((Component)this).gameObject.AddComponent<FreeFlyNotification>();
			FreeFlyInput input = new FreeFlyInput(config, ((BaseUnityPlugin)this).Logger);
			FlightRuntime flight = new FlightRuntime(config, ((BaseUnityPlugin)this).Logger, input, _notification);
			TeleportDestinationService destinations = new TeleportDestinationService(config, ((BaseUnityPlugin)this).Logger);
			TeleportMenuView menu = new TeleportMenuView(destinations);
			Controller = new FreeFlyController(config, input, flight, destinations, menu);
			_harmony = new Harmony("com.github.lllei.FreeFly");
			PatchCapabilities capabilities = PatchInstaller.Install(_harmony, ((BaseUnityPlugin)this).Logger);
			Controller.SetCapabilities(capabilities);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("FreeFly 1.3.0 loaded. " + $"Flight patch: {capabilities.FlightPatch}; teleport: {capabilities.TeleportPatch}."));
		}

		private void Update()
		{
			Controller?.TickUpdate();
		}

		private void OnGUI()
		{
			Controller?.DrawMenu();
		}

		private void OnDestroy()
		{
			Controller?.Shutdown();
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Instance = null;
		}
	}
	internal readonly struct TeleportOption
	{
		public string Label { get; }

		public Vector3 Position { get; }

		public Transform? Anchor { get; }

		public Character? Character { get; }

		public bool Enabled { get; }

		public TeleportOption(string label, Vector3 position, Transform? anchor, Character? character, bool enabled = true)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			Label = label;
			Position = position;
			Anchor = anchor;
			Character = character;
			Enabled = enabled;
		}
	}
	internal sealed class TeleportDestinationService
	{
		private const float RefreshInterval = 0.5f;

		private readonly ModConfig _config;

		private readonly ManualLogSource _logger;

		private readonly List<TeleportOption> _options = new List<TeleportOption>();

		private Transform? _cachedPeakFlareDestination;

		private Transform? _cachedPeakPortalDestination;

		private Transform? _cachedSoulPillarDestination;

		private float _nextPeakFlareSearchTime;

		private float _nextPeakPortalSearchTime;

		private float _nextSoulPillarSearchTime;

		private float _nextRefreshTime;

		private int _cachedSceneHandle = int.MinValue;

		private Segment? _cachedSegment;

		private bool _hasCachedSegment;

		private PatchCapabilities _capabilities;

		public IReadOnlyList<TeleportOption> Options => _options;

		public TeleportDestinationService(ModConfig config, ManualLogSource logger)
		{
			_config = config;
			_logger = logger;
		}

		public void SetCapabilities(PatchCapabilities capabilities)
		{
			_capabilities = capabilities;
		}

		public void RefreshIfNeeded(bool force = false)
		{
			ObserveWorld();
			if (force || !(Time.unscaledTime < _nextRefreshTime))
			{
				_nextRefreshTime = Time.unscaledTime + 0.5f;
				RefreshTargets();
			}
		}

		public bool TryTeleport(int selectedIndex)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			Character localCharacter = Character.localCharacter;
			if (!_capabilities.TeleportPatch || (Object)(object)localCharacter == (Object)null || !FreeFlyCharacterUtils.IsUsable(localCharacter) || localCharacter.warping || selectedIndex < 0 || selectedIndex >= _options.Count)
			{
				return false;
			}
			TeleportOption teleportOption = _options[selectedIndex];
			if (!teleportOption.Enabled)
			{
				return false;
			}
			Vector3 val = teleportOption.Position;
			Vector3 val2 = (((Object)(object)teleportOption.Anchor != (Object)null) ? teleportOption.Anchor.forward : Vector3.forward);
			if ((Object)(object)teleportOption.Character != (Object)null)
			{
				Character character = teleportOption.Character;
				if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null || (Object)(object)((Component)character).transform == (Object)null)
				{
					return false;
				}
				val = (character.data.dead ? character.GetSpectatePosition() : character.Center);
				val2 = ((Component)character).transform.forward;
			}
			val += Vector3.up * _config.SafeTeleportVerticalOffset;
			val -= val2 * _config.SafeTeleportBackwardOffset;
			if (!FreeFlyCharacterUtils.IsFinite(val))
			{
				return false;
			}
			((MonoBehaviourPun)localCharacter).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val, true });
			return true;
		}

		private void ObserveWorld()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			int num = SceneHandle.op_Implicit(((Scene)(ref activeScene)).handle);
			bool flag = false;
			Segment? val = null;
			try
			{
				if (MapHandler.ExistsAndInitialized)
				{
					flag = true;
					val = MapHandler.CurrentSegmentNumber;
				}
			}
			catch
			{
			}
			bool flag2 = flag != _hasCachedSegment || (flag && val != _cachedSegment);
			if (num != _cachedSceneHandle || flag2)
			{
				_cachedSceneHandle = num;
				_cachedSegment = val;
				_hasCachedSegment = flag;
				_cachedPeakFlareDestination = null;
				_cachedPeakPortalDestination = null;
				_cachedSoulPillarDestination = null;
				_nextPeakFlareSearchTime = 0f;
				_nextPeakPortalSearchTime = 0f;
				_nextSoulPillarSearchTime = 0f;
				_nextRefreshTime = 0f;
			}
		}

		private void RefreshTargets()
		{
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			_options.Clear();
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null)
			{
				return;
			}
			try
			{
				AddStageDestinations();
			}
			catch (Exception ex)
			{
				_logger.LogDebug((object)("Stage teleport destinations are not ready: " + ex.Message));
			}
			try
			{
				List<TeleportOption> list = new List<TeleportOption>();
				List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
				if (allPlayerCharacters != null)
				{
					foreach (Character item in allPlayerCharacters)
					{
						if (!((Object)(object)item == (Object)null) && !((Object)(object)item == (Object)(object)localCharacter) && !((Object)(object)item.data == (Object)null) && item.refs != null)
						{
							string text = (item.data.dead ? "Dead" : (item.data.fullyPassedOut ? "Passed out" : "Alive"));
							list.Add(new TeleportOption("Teammate: " + item.characterName + " [" + text + "]", Vector3.zero, null, item));
						}
					}
				}
				list.Sort((TeleportOption left, TeleportOption right) => string.Compare(left.Label, right.Label, StringComparison.OrdinalIgnoreCase));
				_options.AddRange(list);
			}
			catch (Exception ex2)
			{
				_logger.LogDebug((object)("Teammate teleport destinations are not ready: " + ex2.Message));
			}
		}

		private void AddStageDestinations()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			if (!MapHandler.ExistsAndInitialized)
			{
				return;
			}
			Segment currentSegmentNumber = MapHandler.CurrentSegmentNumber;
			if ((int)currentSegmentNumber == 6)
			{
				AddNadirDestinations();
				return;
			}
			int num;
			int num2;
			if ((int)currentSegmentNumber != 4)
			{
				num = (((int)currentSegmentNumber == 5) ? 1 : 0);
				if (num == 0)
				{
					num2 = currentSegmentNumber + 1;
					goto IL_002d;
				}
			}
			else
			{
				num = 1;
			}
			num2 = 5;
			goto IL_002d;
			IL_002d:
			int num3 = num2;
			bool enabled = IsStageGenerated(currentSegmentNumber);
			Campfire previousCampfire = MapHandler.PreviousCampfire;
			object obj;
			if ((int)currentSegmentNumber != 0)
			{
				obj = ((previousCampfire != null) ? ((Component)previousCampfire).transform : null);
			}
			else
			{
				SpawnPoint localSpawnPoint = SpawnPoint.LocalSpawnPoint;
				obj = ((localSpawnPoint != null) ? ((Component)localSpawnPoint).transform : null);
			}
			Transform val = (Transform)obj;
			if ((Object)(object)val != (Object)null)
			{
				AddStageDestination(position: ((Object)(object)previousCampfire != (Object)null) ? previousCampfire.Center() : val.position, label: $"Stage {num3} start ({GetStageStartName(currentSegmentNumber)})", anchor: val, enabled: enabled);
			}
			if (num != 0)
			{
				Transform peakDestination = GetPeakDestination();
				if ((Object)(object)peakDestination != (Object)null)
				{
					AddStageDestination("Stage 5 end (PEAK)", peakDestination.position, peakDestination, enabled);
				}
			}
			else
			{
				Campfire currentCampfire = MapHandler.CurrentCampfire;
				if ((Object)(object)currentCampfire != (Object)null)
				{
					AddStageDestination($"Stage {num3} end ({GetStageEndName(currentSegmentNumber)})", currentCampfire.Center(), ((Component)currentCampfire).transform, enabled);
				}
			}
		}

		private void AddNadirDestinations()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (VoidBiome.SoulFreedStatus == 1)
			{
				Transform soulPillarDestination = GetSoulPillarDestination();
				if ((Object)(object)soulPillarDestination != (Object)null)
				{
					AddStageDestination("Nadir waypoint (Scoutmaster Soul)", soulPillarDestination.position, soulPillarDestination);
				}
				Transform peakPortalDestination = GetPeakPortalDestination();
				if ((Object)(object)peakPortalDestination != (Object)null)
				{
					AddStageDestination("Nadir end (The Gate)", peakPortalDestination.position, peakPortalDestination);
				}
				return;
			}
			Transform val = null;
			try
			{
				val = MapHandler.CurrentBaseCampSpawnPoint;
			}
			catch
			{
			}
			if ((Object)(object)val != (Object)null)
			{
				AddStageDestination("Nadir start (Spawn)", val.position, val);
			}
			Transform soulPillarDestination2 = GetSoulPillarDestination();
			if ((Object)(object)soulPillarDestination2 != (Object)null)
			{
				AddStageDestination("Nadir waypoint (Scoutmaster Soul)", soulPillarDestination2.position, soulPillarDestination2);
			}
		}

		private Transform? GetSoulPillarDestination()
		{
			if ((Object)(object)_cachedSoulPillarDestination != (Object)null)
			{
				return _cachedSoulPillarDestination;
			}
			if (Time.unscaledTime < _nextSoulPillarSearchTime)
			{
				return null;
			}
			_nextSoulPillarSearchTime = Time.unscaledTime + 1f;
			_cachedSoulPillarDestination = FindDestinationInRoots<ScoutmasterSoulPillar>((GameObject?[])(object)new GameObject[1] { GetNadirSegmentRoot() });
			return _cachedSoulPillarDestination;
		}

		private Transform? GetPeakPortalDestination()
		{
			if ((Object)(object)_cachedPeakPortalDestination != (Object)null)
			{
				return _cachedPeakPortalDestination;
			}
			if (Time.unscaledTime < _nextPeakPortalSearchTime)
			{
				return null;
			}
			_nextPeakPortalSearchTime = Time.unscaledTime + 1f;
			_cachedPeakPortalDestination = FindDestinationInRoots<PeakGatePortal>((GameObject?[])(object)new GameObject[1] { GetNadirSegmentRoot() });
			return _cachedPeakPortalDestination;
		}

		private static Transform? FindDestinationInRoots<T>(params GameObject?[] roots) where T : Component
		{
			Transform val = null;
			foreach (GameObject val2 in roots)
			{
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				T[] componentsInChildren = val2.GetComponentsInChildren<T>(true);
				foreach (T val3 in componentsInChildren)
				{
					if (!((Object)(object)val3 == (Object)null) && !((Object)(object)((Component)val3).transform == (Object)null))
					{
						if (val == null)
						{
							val = ((Component)val3).transform;
						}
						if (((Component)val3).gameObject.activeInHierarchy)
						{
							return ((Component)val3).transform;
						}
					}
				}
			}
			return val;
		}

		private static GameObject? GetNadirSegmentRoot()
		{
			try
			{
				VoidBiome instance = VoidBiome.instance;
				object result;
				if (instance == null)
				{
					result = null;
				}
				else
				{
					MapSegment segment = instance.segment;
					result = ((segment != null) ? segment.segmentParent : null);
				}
				return (GameObject?)result;
			}
			catch
			{
				return null;
			}
		}

		private static GameObject? GetPeakHandlerRoot()
		{
			try
			{
				PeakHandler instance = Singleton<PeakHandler>.Instance;
				return (instance != null) ? ((Component)instance).gameObject : null;
			}
			catch
			{
				return null;
			}
		}

		private void AddStageDestination(string label, Vector3 position, Transform anchor, bool enabled = true)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (FreeFlyCharacterUtils.IsFinite(position))
			{
				_options.Add(new TeleportOption(label, position, anchor, null, enabled));
			}
		}

		private static bool IsStageGenerated(Segment segment)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Invalid comparison between Unknown and I4
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if ((int)segment == 0 || (int)segment == 6)
			{
				return true;
			}
			try
			{
				if (!MapHandler.CurrentMapSegment.segmentParent.activeInHierarchy)
				{
					return false;
				}
				int num = (((int)segment == 5) ? 4 : ((int)segment));
				MountainProgressHandler instance = Singleton<MountainProgressHandler>.Instance;
				return (Object)(object)instance != (Object)null && instance.maxProgressPointReached >= num;
			}
			catch
			{
				return false;
			}
		}

		private static string GetStageStartName(Segment segment)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected I4, but got Unknown
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if ((int)segment == 0)
			{
				return "Spawn";
			}
			try
			{
				return GetBiomeDisplayName(MapHandler.GetBiomeForSegment(segment - 1));
			}
			catch
			{
				return "Previous campfire";
			}
		}

		private static string GetStageEndName(Segment segment)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected I4, but got Unknown
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return GetBiomeDisplayName(MapHandler.GetBiomeForSegment((int)segment));
			}
			catch
			{
				return "Current campfire";
			}
		}

		private unsafe static string GetBiomeDisplayName(BiomeType biome)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			if ((int)biome != 3)
			{
				if ((int)biome != 5)
				{
					if ((int)biome == 8)
					{
						return "Gloom";
					}
					return ((object)(*(BiomeType*)(&biome))/*cast due to .constrained prefix*/).ToString();
				}
				return "PEAK";
			}
			return "Caldera";
		}

		private Transform? GetPeakDestination()
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)_cachedPeakFlareDestination == (Object)null && Time.unscaledTime >= _nextPeakFlareSearchTime)
				{
					_nextPeakFlareSearchTime = Time.unscaledTime + 1f;
					GameObject peakHandlerRoot = GetPeakHandlerRoot();
					object obj = (((Object)(object)peakHandlerRoot != (Object)null) ? ((object)peakHandlerRoot.GetComponentsInChildren<EndgameFlareSpawner>(true)) : ((object)Array.Empty<EndgameFlareSpawner>()));
					float num = float.MinValue;
					EndgameFlareSpawner[] array = (EndgameFlareSpawner[])obj;
					foreach (EndgameFlareSpawner val in array)
					{
						if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).transform == (Object)null))
						{
							Vector3 position = ((Component)val).transform.position;
							if (FreeFlyCharacterUtils.IsFinite(position) && position.y > num)
							{
								num = position.y;
								_cachedPeakFlareDestination = ((Component)val).transform;
							}
						}
					}
				}
				if ((Object)(object)_cachedPeakFlareDestination != (Object)null)
				{
					return _cachedPeakFlareDestination;
				}
				PeakHandler instance = Singleton<PeakHandler>.Instance;
				if ((Object)(object)instance != (Object)null && (Object)(object)instance.flareBox != (Object)null)
				{
					return instance.flareBox.transform;
				}
				MountainProgressHandler instance2 = Singleton<MountainProgressHandler>.Instance;
				if ((Object)(object)instance2 == (Object)null || instance2.progressPoints == null || instance2.progressPoints.Length == 0)
				{
					return null;
				}
				return instance2.progressPoints[instance2.progressPoints.Length - 1]?.transform;
			}
			catch
			{
				return null;
			}
		}
	}
	internal sealed class TeleportMenuView
	{
		private readonly TeleportDestinationService _destinations;

		private GameObject? _inputBlockerObject;

		private FreeFlyMenuWindow? _inputBlockerWindow;

		private GUIStyle? _boxStyle;

		private GUIStyle? _labelStyle;

		private GUIStyle? _buttonStyle;

		private GUISkin? _styleSkin;

		private Vector2 _scrollPosition;

		private int _selectedTarget;

		public bool IsOpen { get; private set; }

		public TeleportMenuView(TeleportDestinationService destinations)
		{
			_destinations = destinations;
		}

		public void Open()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			_destinations.RefreshIfNeeded(force: true);
			_selectedTarget = FreeFlyInputRules.ClampSelection(_selectedTarget, _destinations.Options.Count);
			_scrollPosition = Vector2.zero;
			IsOpen = true;
			CreateInputBlocker();
		}

		public void Tick(FreeFlyInputSnapshot input)
		{
			if (!IsOpen)
			{
				return;
			}
			_destinations.RefreshIfNeeded();
			_selectedTarget = FreeFlyInputRules.ClampSelection(_selectedTarget, _destinations.Options.Count);
			if (input.Cancel)
			{
				Close();
				return;
			}
			if (input.Up)
			{
				_selectedTarget = Mathf.Max(0, _selectedTarget - 1);
			}
			if (input.Down)
			{
				_selectedTarget = Mathf.Min(Mathf.Max(0, _destinations.Options.Count - 1), _selectedTarget + 1);
			}
			if (input.Confirm && _destinations.TryTeleport(_selectedTarget))
			{
				Close();
			}
		}

		public void Draw()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			if (!IsOpen)
			{
				return;
			}
			EnsureStyles();
			float num = Mathf.Min(720f, (float)Screen.width - 40f);
			float num2 = Mathf.Min(620f, (float)Screen.height - 40f);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((float)Screen.width - num) * 0.5f, ((float)Screen.height - num2) * 0.5f, num, num2);
			GUI.Box(val, "FreeFly - Teleport", _boxStyle);
			GUILayout.BeginArea(new Rect(((Rect)(ref val)).x + 24f, ((Rect)(ref val)).y + 64f, ((Rect)(ref val)).width - 48f, ((Rect)(ref val)).height - 88f));
			GUILayout.Label("Select a destination. Dead teammates use their corpse position.", _labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(12f);
			if (_destinations.Options.Count == 0)
			{
				GUILayout.Label("No teleport destination is available.", _labelStyle, Array.Empty<GUILayoutOption>());
			}
			else
			{
				_scrollPosition = GUILayout.BeginScrollView(_scrollPosition, Array.Empty<GUILayoutOption>());
				for (int i = 0; i < _destinations.Options.Count; i++)
				{
					TeleportOption teleportOption = _destinations.Options[i];
					string text = (teleportOption.Enabled ? string.Empty : " [Generating...]");
					string text2 = ((i == _selectedTarget) ? "> " : "  ") + teleportOption.Label + text;
					bool enabled = GUI.enabled;
					GUI.enabled = teleportOption.Enabled;
					if (GUILayout.Button(text2, _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(52f) }))
					{
						_selectedTarget = i;
						if (_destinations.TryTeleport(_selectedTarget))
						{
							Close();
						}
					}
					GUI.enabled = enabled;
				}
				GUILayout.EndScrollView();
			}
			GUILayout.FlexibleSpace();
			GUILayout.Label("Up/Down or D-pad: select    Enter/A: teleport    Escape/B: cancel", _labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.EndArea();
		}

		public void Close()
		{
			IsOpen = false;
			DestroyInputBlocker();
		}

		public void Shutdown()
		{
			Close();
		}

		private void EnsureStyles()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			if (!((Object)(object)_styleSkin == (Object)(object)GUI.skin) || _boxStyle == null || _labelStyle == null || _buttonStyle == null)
			{
				_styleSkin = GUI.skin;
				_boxStyle = new GUIStyle(GUI.skin.box)
				{
					fontSize = 28
				};
				_labelStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 20,
					wordWrap = true
				};
				_buttonStyle = new GUIStyle(GUI.skin.button)
				{
					fontSize = 22
				};
			}
		}

		private void CreateInputBlocker()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			if (!((Object)(object)_inputBlockerObject != (Object)null))
			{
				_inputBlockerObject = new GameObject("FreeFly Teleport Menu Input Blocker");
				_inputBlockerWindow = _inputBlockerObject.AddComponent<FreeFlyMenuWindow>();
				if (!MenuWindow.AllActiveWindows.Contains((MenuWindow)(object)_inputBlockerWindow))
				{
					MenuWindow.AllActiveWindows.Add((MenuWindow)(object)_inputBlockerWindow);
				}
			}
		}

		private void DestroyInputBlocker()
		{
			if ((Object)(object)_inputBlockerWindow != (Object)null)
			{
				MenuWindow.AllActiveWindows.Remove((MenuWindow)(object)_inputBlockerWindow);
			}
			if ((Object)(object)_inputBlockerObject != (Object)null)
			{
				Object.Destroy((Object)(object)_inputBlockerObject);
			}
			_inputBlockerWindow = null;
			_inputBlockerObject = null;
		}
	}
	internal static class BuildInfo
	{
		internal const string Version = "1.3.0";
	}
}
namespace FreeFly.Core
{
	internal static class FreeFlyInputRules
	{
		public static string NormalizeBindingPath(string? path)
		{
			return path?.Trim() ?? string.Empty;
		}

		public static int ClampSelection(int selectedIndex, int optionCount)
		{
			if (optionCount <= 0)
			{
				return 0;
			}
			if (selectedIndex >= 0)
			{
				if (selectedIndex < optionCount)
				{
					return selectedIndex;
				}
				return optionCount - 1;
			}
			return 0;
		}
	}
	internal static class FreeFlyMath
	{
		public static float ApplySpeedModifiers(float baseSpeed, bool speedUp, bool slowDown, float speedUpMultiplier, float slowDownMultiplier)
		{
			if (!IsFinite(baseSpeed) || baseSpeed < 0f || !IsFinite(speedUpMultiplier) || speedUpMultiplier < 0f || !IsFinite(slowDownMultiplier) || slowDownMultiplier < 0f)
			{
				return 0f;
			}
			float num = 1f;
			if (speedUp)
			{
				num *= speedUpMultiplier;
			}
			if (slowDown)
			{
				num *= slowDownMultiplier;
			}
			return baseSpeed * num;
		}

		public static bool IsFinite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}
	}
}