Decompiled source of Sandevistan v1.0.0

plugins/Sandevistan.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.InputSystem;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Sandevistan")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Sandevistan")]
[assembly: AssemblyTitle("Sandevistan")]
[assembly: AssemblyVersion("1.0.0.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 SandevistanMod
{
	[BepInPlugin("breenihilation.ultrakill.sandevistan", "Sandevistan", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "breenihilation.ultrakill.sandevistan";

		public const string PluginName = "Sandevistan";

		public const string PluginVersion = "1.0.0";

		private const string ConfiggyPluginGuid = "Hydraxous.ULTRAKILL.Configgy";

		private Harmony _harmony;

		private static GameObject _runtimeObject;

		private static SandevistanRuntime _runtime;

		private static object _configgyBuilder;

		public static Plugin Instance { get; private set; }

		public static ManualLogSource ModLog { get; private set; }

		public static ConfigEntry<KeyCode> ActivationKey { get; private set; }

		public static ConfigEntry<float> SlowScale { get; private set; }

		public static ConfigEntry<bool> SlowPlayerFalling { get; private set; }

		public static ConfigEntry<bool> SoundEffects { get; private set; }

		public static ConfigEntry<float> SoundVolume { get; private set; }

		public static ConfigEntry<float> WorldAudioPitch { get; private set; }

		public static ConfigEntry<bool> ScreenEffects { get; private set; }

		public static ConfigEntry<bool> PlayerAfterimages { get; private set; }

		public static ConfigEntry<float> AfterimageInterval { get; private set; }

		public static ConfigEntry<float> AfterimageForwardOffset { get; private set; }

		public static ConfigEntry<float> AfterimageRightOffset { get; private set; }

		public static ConfigEntry<float> AfterimageVerticalOffset { get; private set; }

		public static ConfigEntry<float> AfterimageScale { get; private set; }

		public static ConfigEntry<bool> HideCloseAfterimages { get; private set; }

		public void Awake()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Expected O, but got Unknown
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Expected O, but got Unknown
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Expected O, but got Unknown
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Expected O, but got Unknown
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Expected O, but got Unknown
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Expected O, but got Unknown
			//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Expected O, but got Unknown
			Instance = this;
			ModLog = ((BaseUnityPlugin)this).Logger;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			ActivationKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "ActivationKey", (KeyCode)118, "Hotkey for sandevistan toggle.");
			SlowScale = ((BaseUnityPlugin)this).Config.Bind<float>("Sandevistan", "WorldTimeScale", 0.05f, new ConfigDescription("World speed while active. 0.05 is a 95% slowdown.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.02f, 0.8f), Array.Empty<object>()));
			SlowPlayerFalling = ((BaseUnityPlugin)this).Config.Bind<bool>("Sandevistan", "SlowPlayerFalling", false, "Slow down gravity, but only when falling. Ascending, jumping and shi still works at the same speed.");
			SoundEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "SoundEffects", true, "Play a sound effect when activating/disabling Sandevistan.");
			SoundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "SoundVolume", 1f, new ConfigDescription("Sandevistan sound volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			WorldAudioPitch = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "WorldAudioPitch", 0.5f, new ConfigDescription("Changes the pitch of most sounds/music while a sandy is active.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 1f), Array.Empty<object>()));
			ScreenEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "ScreenEffects", true, "Creates a green tint.");
			PlayerAfterimages = ((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "PlayerModelAfterimages", true, "Spawn colored afterimages, similar to the effect of sandevistan from cyberpunk: edgerunners");
			AfterimageInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Effects", "AfterimageInterval", 0.055f, new ConfigDescription("Real seconds between afterimages.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.025f, 0.2f), Array.Empty<object>()));
			AfterimageForwardOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Afterimage Calibration", "ForwardOffset", -0.65f, new ConfigDescription("Change positioning of afterimages.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f), Array.Empty<object>()));
			AfterimageRightOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Afterimage Calibration", "RightOffset", 0.2f, new ConfigDescription("Change positioning of afterimages.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f), Array.Empty<object>()));
			AfterimageVerticalOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Afterimage Calibration", "VerticalOffset", -0.8f, new ConfigDescription("Change positioning of afterimages.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f), Array.Empty<object>()));
			AfterimageScale = ((BaseUnityPlugin)this).Config.Bind<float>("Afterimage Calibration", "Scale", 0.45f, new ConfigDescription("Scale. Size. Dimensions. Proportion. Volume. Bigness. Largeness. Vastness. Whatever other words for  size exist.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 3f), Array.Empty<object>()));
			HideCloseAfterimages = ((BaseUnityPlugin)this).Config.Bind<bool>("Afterimage Calibration", "HideCloseAfterimages", true, "Afterimages near you fade away. So you know, you can actually see sometimes.");
			bool flag = false;
			if (Mathf.Approximately(SlowScale.Value, 0.18f) || Mathf.Approximately(SlowScale.Value, 0.1f))
			{
				SlowScale.Value = 0.05f;
				flag = true;
			}
			if (Mathf.Approximately(SoundVolume.Value, 0.85f))
			{
				SoundVolume.Value = 1f;
				flag = true;
			}
			flag |= SnapFloatSetting(SlowScale, 0.01f);
			flag |= SnapFloatSetting(SoundVolume, 0.05f);
			flag |= SnapFloatSetting(WorldAudioPitch, 0.05f);
			flag |= SnapFloatSetting(AfterimageInterval, 0.005f);
			flag |= SnapFloatSetting(AfterimageForwardOffset, 0.05f);
			flag |= SnapFloatSetting(AfterimageRightOffset, 0.05f);
			flag |= SnapFloatSetting(AfterimageVerticalOffset, 0.05f);
			if (flag | SnapFloatSetting(AfterimageScale, 0.05f))
			{
				((BaseUnityPlugin)this).Config.Save();
			}
			RegisterWithConfiggy();
			try
			{
				SandevistanClock.Initialize(SlowScale.Value);
				SandevistanInput.Initialize();
				_harmony = new Harmony("breenihilation.ultrakill.sandevistan");
				_harmony.PatchAll(typeof(Plugin).Assembly);
				EnsureRuntime();
				SceneManager.sceneLoaded += OnSceneLoaded;
				SlowScale.SettingChanged += OnSlowScaleChanged;
				ActivationKey.SettingChanged += OnActivationKeyChanged;
				((MonoBehaviour)this).StartCoroutine(FindPlayerUntilAttached());
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
				throw;
			}
		}

		private void RegisterWithConfiggy()
		{
			try
			{
				Type type = Type.GetType("Configgy.ConfigBuilder, Configgy", throwOnError: false);
				if (type == null)
				{
					return;
				}
				MethodInfo method = type.GetMethod("RegisterBepInExConfigEntry", BindingFlags.Instance | BindingFlags.Public);
				MethodInfo method2 = type.GetMethod("RegisterElement", BindingFlags.Instance | BindingFlags.Public);
				MethodInfo method3 = type.GetMethod("Rebuild", BindingFlags.Instance | BindingFlags.Public);
				Assembly assembly = type.Assembly;
				Type type2 = assembly.GetType("Configgy.FloatSlider", throwOnError: false);
				Type type3 = assembly.GetType("Configgy.ConfigValueElement", throwOnError: false);
				Type type4 = assembly.GetType("Configgy.ConfiggableAttribute", throwOnError: false);
				MethodInfo methodInfo = assembly.GetType("Configgy.Configuration.AutoGeneration.BepinElement", throwOnError: false)?.GetMethod("WrapUntyped", BindingFlags.Static | BindingFlags.Public);
				MethodInfo methodInfo2 = null;
				if (type3 != null)
				{
					MethodInfo[] methods = type3.GetMethods(BindingFlags.Static | BindingFlags.Public);
					foreach (MethodInfo methodInfo3 in methods)
					{
						if (methodInfo3.Name == "Create" && methodInfo3.IsGenericMethodDefinition && methodInfo3.GetParameters().Length == 1)
						{
							methodInfo2 = methodInfo3;
							break;
						}
					}
				}
				MethodInfo methodInfo4 = type4?.GetMethod("SetOwner", BindingFlags.Instance | BindingFlags.Public);
				if (method == null || method3 == null)
				{
					throw new MissingMethodException("Configgy 1.0.7 ConfigBuilder registration API was not found.");
				}
				_configgyBuilder = Activator.CreateInstance(type, "Configgy.Generated.Sandevistan", "Sandevistan");
				int num = 0;
				foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in ((BaseUnityPlugin)this).Config)
				{
					ConfigEntryBase value = item.Value;
					float num2 = ConfiggyStepFor(value);
					AcceptableValueRange<float> val = value.Description.AcceptableValues as AcceptableValueRange<float>;
					if (method2 != null && type4 != null && methodInfo != null && methodInfo4 != null && methodInfo2 != null)
					{
						try
						{
							object obj = ((!(num2 > 0f) || val == null || !(type2 != null)) ? methodInfo2.MakeGenericMethod(value.SettingType).Invoke(null, new object[1] { value.DefaultValue }) : Activator.CreateInstance(type2, (float)value.DefaultValue, val.MinValue, val.MaxValue, num2));
							object obj2 = Activator.CreateInstance(type4, ConfiggyCategoryFor(value), ConfiggyDisplayNameFor(value), ConfiggyOrderFor(value), value.Description.Description);
							methodInfo4.Invoke(obj2, new object[1] { _configgyBuilder });
							object obj3 = methodInfo.Invoke(null, new object[2] { value, obj });
							method2.Invoke(_configgyBuilder, new object[2] { obj2, obj3 });
						}
						catch (Exception)
						{
							method.Invoke(_configgyBuilder, new object[1] { value });
						}
					}
					else
					{
						method.Invoke(_configgyBuilder, new object[1] { value });
					}
					num++;
				}
				method3.Invoke(_configgyBuilder, null);
			}
			catch (TargetInvocationException ex2)
			{
				Exception? obj4 = ex2.InnerException ?? ex2;
				((BaseUnityPlugin)this).Logger.LogError((object)("Configgy registration failed: " + obj4));
			}
			catch (Exception ex3)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Configgy registration failed: " + ex3));
			}
		}

		private static string ConfiggyCategoryFor(ConfigEntryBase entry)
		{
			switch (entry.Definition.Key)
			{
			case "PlayerModelAfterimages":
			case "AfterimageInterval":
			case "ForwardOffset":
			case "RightOffset":
			case "VerticalOffset":
			case "Scale":
			case "HideCloseAfterimages":
				return "Afterimage Tuning";
			default:
				return "General";
			}
		}

		private static int ConfiggyOrderFor(ConfigEntryBase entry)
		{
			return entry.Definition.Key switch
			{
				"ActivationKey" => 0, 
				"WorldTimeScale" => 1, 
				"SlowPlayerFalling" => 2, 
				"SoundEffects" => 3, 
				"SoundVolume" => 4, 
				"WorldAudioPitch" => 5, 
				"ScreenEffects" => 6, 
				"PlayerModelAfterimages" => 0, 
				"AfterimageInterval" => 1, 
				"ForwardOffset" => 2, 
				"RightOffset" => 3, 
				"VerticalOffset" => 4, 
				"Scale" => 5, 
				"HideCloseAfterimages" => 6, 
				_ => 100, 
			};
		}

		private static string ConfiggyDisplayNameFor(ConfigEntryBase entry)
		{
			return entry.Definition.Key switch
			{
				"ActivationKey" => "Activation Key", 
				"WorldTimeScale" => "World Time Scale", 
				"SlowPlayerFalling" => "Slow falling", 
				"SoundEffects" => "Sound Effects", 
				"SoundVolume" => "Sound Volume", 
				"WorldAudioPitch" => "Audio Speed/Pitch", 
				"ScreenEffects" => "Screen Effects", 
				"PlayerModelAfterimages" => "Afterimages", 
				"AfterimageInterval" => "Afterimage Interval", 
				"ForwardOffset" => "Forward Offset", 
				"RightOffset" => "Right Offset", 
				"VerticalOffset" => "Vertical Offset", 
				"Scale" => "Scale", 
				"HideCloseAfterimages" => "Hide close afterimages", 
				_ => entry.Definition.Key, 
			};
		}

		private static float ConfiggyStepFor(ConfigEntryBase entry)
		{
			if (entry == null || entry.SettingType != typeof(float))
			{
				return 0f;
			}
			switch (entry.Definition.Key)
			{
			case "WorldTimeScale":
				return 0.01f;
			case "SoundVolume":
				return 0.05f;
			case "WorldAudioPitch":
				return 0.05f;
			case "AfterimageInterval":
				return 0.005f;
			case "VerticalOffset":
			case "RightOffset":
			case "ForwardOffset":
			case "Scale":
				return 0.05f;
			default:
				return 0.01f;
			}
		}

		private static bool SnapFloatSetting(ConfigEntry<float> entry, float step)
		{
			if (entry == null || step <= 0f)
			{
				return false;
			}
			float num = Mathf.Round(entry.Value / step) * step;
			if (Mathf.Approximately(entry.Value, num))
			{
				return false;
			}
			entry.Value = num;
			return true;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if (SandevistanClock.Active)
			{
				SandevistanClock.SetActive(active: false, "scene change");
			}
			((MonoBehaviour)this).StartCoroutine(FindPlayerUntilAttached());
		}

		public void Update()
		{
			SandevistanInput.Poll("Plugin.Update");
			SandevistanClock.MaintainWorldTime();
		}

		public void LateUpdate()
		{
			SandevistanClock.MaintainWorldTime();
		}

		private void OnSlowScaleChanged(object sender, EventArgs args)
		{
			SandevistanClock.SetSlowScale(SlowScale.Value);
		}

		private void OnActivationKeyChanged(object sender, EventArgs args)
		{
			SandevistanInput.Initialize();
			((BaseUnityPlugin)this).Config.Save();
		}

		internal static void NotifyStateChanged(bool active)
		{
			if ((Object)(object)_runtime != (Object)null)
			{
				_runtime.OnSandevistanStateChanged(active);
			}
		}

		internal static void EnsureRuntime()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (!((Object)(object)_runtime != (Object)null))
			{
				_runtimeObject = new GameObject("Sandevistan Runtime");
				Object.DontDestroyOnLoad((Object)(object)_runtimeObject);
				_runtime = _runtimeObject.AddComponent<SandevistanRuntime>();
				_runtime.Initialize();
			}
		}

		private IEnumerator FindPlayerUntilAttached()
		{
			NewMovement val = default(NewMovement);
			for (int i = 0; i < 600; i++)
			{
				if (MonoSingleton<NewMovement>.TryGetInstance(ref val) && (Object)(object)val != (Object)null)
				{
					SandevistanPlayer.Attach(val);
					break;
				}
				yield return null;
			}
		}

		public void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
		}
	}
	public static class SandevistanClock
	{
		private static float _playerTime;

		private static int _playerTimeFrame = -1;

		private static float _normalTimeScale = 1f;

		private static float _normalFixedDelta = 0.02f;

		private static float _gameScale = 1f;

		private static bool _initialized;

		public static bool Active { get; private set; }

		public static float SlowScale { get; private set; } = 0.05f;

		public static float EffectiveWorldScale { get; private set; } = 1f;

		public static bool PlayerUsesUnscaledTime
		{
			get
			{
				if (Active)
				{
					return !GamePaused;
				}
				return false;
			}
		}

		public static float PlayerDeltaTime
		{
			get
			{
				if (!PlayerUsesUnscaledTime)
				{
					return Time.deltaTime;
				}
				return Time.unscaledDeltaTime;
			}
		}

		public static float PlayerFixedDeltaTime
		{
			get
			{
				if (!PlayerUsesUnscaledTime)
				{
					return Time.fixedDeltaTime;
				}
				return _normalFixedDelta;
			}
		}

		public static float PlayerTimeScale
		{
			get
			{
				if (!PlayerUsesUnscaledTime)
				{
					return Time.timeScale;
				}
				return 1f;
			}
		}

		public static float NormalFixedDelta => _normalFixedDelta;

		public static float PlayerTime
		{
			get
			{
				if (_playerTimeFrame != Time.frameCount)
				{
					if (_playerTimeFrame < 0)
					{
						_playerTime = Time.time;
					}
					else
					{
						_playerTime += (PlayerUsesUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime);
					}
					_playerTimeFrame = Time.frameCount;
				}
				return _playerTime;
			}
		}

		public static bool CanToggle
		{
			get
			{
				NewMovement movement = default(NewMovement);
				MonoSingleton<NewMovement>.TryGetInstance(ref movement);
				return CanToggleWith(movement);
			}
		}

		private static bool GamePaused
		{
			get
			{
				try
				{
					return (Object)(object)MonoSingleton<OptionsManager>.Instance != (Object)null && MonoSingleton<OptionsManager>.Instance.paused;
				}
				catch
				{
					return false;
				}
			}
		}

		public static float ReadPlayerTimeSince(TimeSince value)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return PlayerTime - value.time;
		}

		public static TimeSince CreatePlayerTimeSince(float elapsed)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			return new TimeSince
			{
				time = PlayerTime - elapsed
			};
		}

		public static void InvokePlayer(MonoBehaviour behaviour, string methodName, float delay)
		{
			if (!((Object)(object)behaviour == (Object)null) && (!PlayerUsesUnscaledTime || !SandevistanPlayerInvokes.Schedule(behaviour, methodName, delay)))
			{
				behaviour.Invoke(methodName, delay);
			}
		}

		public static void AddPlayerForce(Rigidbody rigidbody, Vector3 force)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rigidbody == (Object)null))
			{
				if (!PlayerUsesUnscaledTime)
				{
					rigidbody.AddForce(force);
				}
				else
				{
					rigidbody.velocity += force * (_normalFixedDelta / Mathf.Max(rigidbody.mass, 0.001f));
				}
			}
		}

		public static void AddPlayerForce(Rigidbody rigidbody, Vector3 force, ForceMode mode)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected I4, but got Unknown
			//IL_0012: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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_0081: 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_0059: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rigidbody == (Object)null))
			{
				if (!PlayerUsesUnscaledTime)
				{
					rigidbody.AddForce(force, mode);
					return;
				}
				Vector3 val = (Vector3)((int)mode switch
				{
					0 => force * (_normalFixedDelta / Mathf.Max(rigidbody.mass, 0.001f)), 
					5 => force * _normalFixedDelta, 
					1 => force / Mathf.Max(rigidbody.mass, 0.001f), 
					2 => force, 
					_ => Vector3.zero, 
				});
				rigidbody.velocity += val;
			}
		}

		public static bool CanToggleWith(NewMovement movement)
		{
			if (!_initialized || GamePaused)
			{
				return false;
			}
			if (!Active && Time.timeScale <= 0f)
			{
				return false;
			}
			if ((Object)(object)movement != (Object)null)
			{
				return !movement.dead;
			}
			return false;
		}

		public static void Initialize(float slowScale)
		{
			SlowScale = Mathf.Clamp(slowScale, 0.02f, 0.8f);
			_normalFixedDelta = ((Time.fixedDeltaTime > 0f) ? Time.fixedDeltaTime : 0.02f);
			_normalTimeScale = ((Time.timeScale > 0f) ? Time.timeScale : 1f);
			_gameScale = _normalTimeScale;
			_initialized = true;
		}

		public static void SetSlowScale(float slowScale)
		{
			float slowScale2 = SlowScale;
			SlowScale = Mathf.Clamp(slowScale, 0.02f, 0.8f);
			if (Active && !Mathf.Approximately(slowScale2, SlowScale))
			{
				SandevistanVelocity.ChangeScale(slowScale2, SlowScale);
				Apply(_gameScale * SlowScale);
			}
		}

		public static void ToggleFromInput(string source)
		{
			SetActive(!Active, source);
		}

		public static void SetActive(bool active, string source)
		{
			if (_initialized && Active != active)
			{
				if (active)
				{
					_normalTimeScale = ((Time.timeScale > 0f) ? Time.timeScale : 1f);
					_normalFixedDelta = ((Time.fixedDeltaTime > 0f) ? Time.fixedDeltaTime : 0.02f);
					_gameScale = _normalTimeScale;
					Active = true;
					SandevistanVelocity.BeginActivation();
					MaintainWorldTime();
					Plugin.NotifyStateChanged(active: true);
				}
				else
				{
					SandevistanVelocity.Deactivate();
					Active = false;
					EffectiveWorldScale = _gameScale;
					Time.timeScale = _gameScale;
					Time.fixedDeltaTime = _normalFixedDelta;
					Plugin.NotifyStateChanged(active: false);
				}
			}
		}

		public static void CaptureAndApplyGameTime()
		{
			if (Active && !GamePaused)
			{
				float num = Mathf.Max(0f, Time.timeScale);
				if (Mathf.Abs(num - EffectiveWorldScale) >= 0.0001f)
				{
					_gameScale = num;
				}
				Apply(_gameScale * SlowScale);
			}
		}

		public static void MaintainWorldTime()
		{
			if (Active && !GamePaused)
			{
				Apply(_gameScale * SlowScale);
			}
		}

		private static void Apply(float scale)
		{
			EffectiveWorldScale = Mathf.Clamp(scale, 0f, 1f);
			Time.timeScale = EffectiveWorldScale;
			Time.fixedDeltaTime = _normalFixedDelta * Mathf.Max(EffectiveWorldScale, 0.001f);
		}
	}
	public static class SandevistanVelocity
	{
		private static NewMovement _movement;

		private static bool _physicalVelocity;

		private static int _logicalDepth;

		private static bool _reportedGravityCompensation;

		private static bool _stabilizingActivation;

		private static bool _activationSnapshotCaptured;

		private static bool _activationFixedBatchSeen;

		private static Vector3 _activationPosition;

		private static Quaternion _activationRotation;

		private static Vector3 _activationLogicalVelocity;

		public static bool StabilizingActivation => _stabilizingActivation;

		public static void Bind(NewMovement movement)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_movement != (Object)(object)movement)
			{
				if (_physicalVelocity && (Object)(object)_movement != (Object)null && (Object)(object)_movement.rb != (Object)null)
				{
					Rigidbody rb = _movement.rb;
					rb.velocity *= SandevistanClock.SlowScale;
				}
				_physicalVelocity = false;
				_logicalDepth = 0;
				_reportedGravityCompensation = false;
			}
			_movement = movement;
		}

		public static void ChangeScale(float oldScale, float newScale)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (_physicalVelocity && !((Object)(object)_movement == (Object)null) && !((Object)(object)_movement.rb == (Object)null) && !(newScale <= 0f))
			{
				Rigidbody rb = _movement.rb;
				rb.velocity *= oldScale / newScale;
			}
		}

		public static void Unbind(NewMovement movement)
		{
			if ((Object)(object)_movement == (Object)(object)movement)
			{
				Deactivate();
				_movement = null;
			}
		}

		public static void Activate()
		{
			//IL_0032: 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)
			if (!_physicalVelocity && !((Object)(object)_movement == (Object)null) && !((Object)(object)_movement.rb == (Object)null))
			{
				Rigidbody rb = _movement.rb;
				rb.velocity /= SandevistanClock.SlowScale;
				_physicalVelocity = true;
			}
		}

		public static void BeginActivation()
		{
			_stabilizingActivation = true;
			_activationSnapshotCaptured = false;
			_activationFixedBatchSeen = false;
		}

		public static void Deactivate()
		{
			//IL_0031: 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)
			if (_physicalVelocity && (Object)(object)_movement != (Object)null && (Object)(object)_movement.rb != (Object)null)
			{
				Rigidbody rb = _movement.rb;
				rb.velocity *= SandevistanClock.SlowScale;
			}
			_physicalVelocity = false;
			_logicalDepth = 0;
			_stabilizingActivation = false;
			_activationSnapshotCaptured = false;
			_activationFixedBatchSeen = false;
		}

		public static void FinishActivationStabilization(NewMovement movement)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (_stabilizingActivation && _activationSnapshotCaptured && _activationFixedBatchSeen && !((Object)(object)movement == (Object)null) && !((Object)(object)movement.rb == (Object)null))
			{
				Bind(movement);
				movement.rb.position = _activationPosition;
				movement.rb.rotation = _activationRotation;
				((Component)movement).transform.position = _activationPosition;
				((Component)movement).transform.rotation = _activationRotation;
				movement.rb.velocity = _activationLogicalVelocity;
				_physicalVelocity = false;
				_stabilizingActivation = false;
				_activationSnapshotCaptured = false;
				_activationFixedBatchSeen = false;
			}
		}

		public static void EnterPlayerCode(NewMovement movement)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			if (SandevistanClock.Active)
			{
				Bind(movement);
				if (_logicalDepth++ == 0 && _physicalVelocity && (Object)(object)_movement != (Object)null && (Object)(object)_movement.rb != (Object)null)
				{
					Rigidbody rb = _movement.rb;
					rb.velocity *= SandevistanClock.SlowScale;
					_physicalVelocity = false;
				}
			}
		}

		public static void ExitPlayerCode()
		{
			//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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			if (_logicalDepth <= 0)
			{
				return;
			}
			_logicalDepth--;
			if (_logicalDepth != 0)
			{
				return;
			}
			if (_stabilizingActivation)
			{
				if (!_activationSnapshotCaptured && (Object)(object)_movement != (Object)null && (Object)(object)_movement.rb != (Object)null)
				{
					_activationPosition = ((Component)_movement).transform.position;
					_activationRotation = ((Component)_movement).transform.rotation;
					_activationLogicalVelocity = _movement.rb.velocity;
					_activationSnapshotCaptured = true;
				}
			}
			else
			{
				Activate();
			}
		}

		public static void ExitPlayerFixedCode()
		{
			if (_logicalDepth <= 0)
			{
				return;
			}
			_logicalDepth--;
			if (_logicalDepth == 0)
			{
				if (_stabilizingActivation)
				{
					_activationFixedBatchSeen = true;
				}
				else
				{
					Activate();
				}
			}
		}

		public static Vector3 ReadLogicalPlayerVelocity(Rigidbody rigidbody)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)rigidbody == (Object)null)
			{
				return Vector3.zero;
			}
			Vector3 val = rigidbody.velocity;
			if (SandevistanClock.Active && _physicalVelocity && (Object)(object)_movement != (Object)null && (Object)(object)_movement.rb == (Object)(object)rigidbody)
			{
				val *= SandevistanClock.SlowScale;
			}
			return val;
		}

		public static void ApplyGravityCompensation(NewMovement movement)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			if (SandevistanClock.Active && !_stabilizingActivation && !((Object)(object)movement == (Object)null) && !((Object)(object)movement.rb == (Object)null) && PhysicsExtensions.GetGravityMode(movement.rb) && _logicalDepth > 0)
			{
				float slowScale = SandevistanClock.SlowScale;
				Vector3 gravityVector = PhysicsExtensions.GetGravityVector(movement.rb);
				bool flag = ((Vector3)(ref gravityVector)).sqrMagnitude > 0.0001f && Vector3.Dot(movement.rb.velocity, gravityVector) > 0f;
				float num = ((Plugin.SlowPlayerFalling != null && Plugin.SlowPlayerFalling.Value && flag) ? slowScale : 1f);
				Vector3 val = gravityVector * SandevistanClock.NormalFixedDelta * (num - slowScale * slowScale);
				Rigidbody rb = movement.rb;
				rb.velocity += val;
				if (!_reportedGravityCompensation && ((Vector3)(ref val)).sqrMagnitude > 0f)
				{
					_reportedGravityCompensation = true;
				}
			}
		}
	}
	[DefaultExecutionOrder(10001)]
	public sealed class SandevistanExplosionFlash : MonoBehaviour
	{
		private static readonly FieldInfo WhiteExplosionField = AccessTools.Field(typeof(Explosion), "whiteExplosion");

		private static readonly FieldInfo RendererField = AccessTools.Field(typeof(Explosion), "mr");

		private static readonly FieldInfo OriginalMaterialField = AccessTools.Field(typeof(Explosion), "originalMaterial");

		private Explosion _explosion;

		private float _born;

		public void Awake()
		{
			_explosion = ((Component)this).GetComponent<Explosion>();
			_born = Time.unscaledTime;
		}

		public void Update()
		{
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			if (Time.unscaledTime - _born < 0.1f)
			{
				return;
			}
			if (SandevistanClock.Active && (Object)(object)_explosion != (Object)null && WhiteExplosionField != null && RendererField != null && OriginalMaterialField != null && (bool)WhiteExplosionField.GetValue(_explosion))
			{
				object? value = RendererField.GetValue(_explosion);
				MeshRenderer val = (MeshRenderer)((value is MeshRenderer) ? value : null);
				object? value2 = OriginalMaterialField.GetValue(_explosion);
				Material val2 = (Material)((value2 is Material) ? value2 : null);
				WhiteExplosionField.SetValue(_explosion, false);
				if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null)
				{
					((Renderer)val).material = new Material(val2);
				}
			}
			Object.Destroy((Object)(object)this);
		}
	}
	internal static class SandevistanInput
	{
		private static InputAction _vAction;

		private static Timer _nativeVTimer;

		private static int _nativeVWasDown;

		private static int _nativeVPressPending;

		private static int _physicalVPressConsumed;

		private static int _managedInputLive;

		private static bool _nativeInputFailureReported;

		private static KeyCode ConfiguredKey
		{
			get
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				if (Plugin.ActivationKey != null)
				{
					return Plugin.ActivationKey.Value;
				}
				return (KeyCode)118;
			}
		}

		public unsafe static void Initialize()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			Shutdown();
			KeyCode configuredKey = ConfiguredKey;
			_nativeVTimer = new Timer(PollNativeV, null, 0, 8);
			try
			{
				string text = ToInputSystemPath(configuredKey);
				if (!string.IsNullOrEmpty(text))
				{
					_vAction = new InputAction("Sandevistan", (InputActionType)1, text, (string)null, (string)null, (string)null);
					_vAction.performed += OnVPerformed;
					_vAction.canceled += OnVCanceled;
					_vAction.Enable();
				}
				InputSystem.onAfterUpdate += OnAfterInputUpdate;
			}
			catch (Exception ex)
			{
				ManualLogSource modLog = Plugin.ModLog;
				if (modLog != null)
				{
					modLog.LogError((object)("Could not create the Sandevistan input action for " + ((object)(*(KeyCode*)(&configuredKey))/*cast due to .constrained prefix*/).ToString() + ": " + ex));
				}
			}
		}

		public static void Shutdown()
		{
			if (_nativeVTimer != null)
			{
				_nativeVTimer.Dispose();
				_nativeVTimer = null;
			}
			Interlocked.Exchange(ref _nativeVWasDown, 0);
			Interlocked.Exchange(ref _nativeVPressPending, 0);
			Interlocked.Exchange(ref _physicalVPressConsumed, 0);
			Interlocked.Exchange(ref _managedInputLive, 0);
			try
			{
				InputSystem.onAfterUpdate -= OnAfterInputUpdate;
				if (_vAction != null)
				{
					_vAction.performed -= OnVPerformed;
					_vAction.canceled -= OnVCanceled;
					_vAction.Disable();
					_vAction.Dispose();
				}
			}
			catch
			{
			}
			_vAction = null;
		}

		private static void OnVPerformed(CallbackContext context)
		{
			Interlocked.Exchange(ref _managedInputLive, 1);
			Interlocked.Exchange(ref _nativeVPressPending, 0);
			if (Interlocked.CompareExchange(ref _physicalVPressConsumed, 1, 0) == 0)
			{
				ToggleDetected("global Unity InputAction callback", ResolveMovement());
			}
		}

		private static void OnVCanceled(CallbackContext context)
		{
			Interlocked.Exchange(ref _physicalVPressConsumed, 0);
			Interlocked.Exchange(ref _nativeVPressPending, 0);
		}

		private static void OnAfterInputUpdate()
		{
			Interlocked.Exchange(ref _managedInputLive, 1);
			Interlocked.Exchange(ref _nativeVPressPending, 0);
		}

		[DllImport("user32.dll")]
		private static extern short GetAsyncKeyState(int virtualKey);

		private static void PollNativeV(object state)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (Interlocked.CompareExchange(ref _managedInputLive, 0, 0) != 0)
				{
					return;
				}
				int num = ToVirtualKey(ConfiguredKey);
				if (num != 0)
				{
					bool flag = (GetAsyncKeyState(num) & 0x8000) != 0;
					bool flag2 = Interlocked.Exchange(ref _nativeVWasDown, flag ? 1 : 0) != 0;
					if (!flag)
					{
						Interlocked.Exchange(ref _physicalVPressConsumed, 0);
					}
					else if (!flag2 && Interlocked.CompareExchange(ref _physicalVPressConsumed, 0, 0) == 0)
					{
						Interlocked.Exchange(ref _nativeVPressPending, 1);
					}
				}
			}
			catch (Exception ex)
			{
				ReportBackendFailure(ref _nativeInputFailureReported, "Win32 GetAsyncKeyState", ex);
			}
		}

		private static bool ConsumeNativeV(string source, NewMovement movement)
		{
			if (Interlocked.Exchange(ref _nativeVPressPending, 0) == 0)
			{
				return false;
			}
			if (Interlocked.CompareExchange(ref _physicalVPressConsumed, 1, 0) != 0)
			{
				return false;
			}
			ToggleDetected("Win32 GetAsyncKeyState in " + source, movement ?? ResolveMovement());
			return true;
		}

		public unsafe static void Poll(string source, NewMovement movement = null)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)movement != (Object)null)
			{
				ReportGameplayReady(movement);
			}
			KeyCode configuredKey = ConfiguredKey;
			if ((int)configuredKey != 0)
			{
				if (Input.GetKeyUp(configuredKey))
				{
					Interlocked.Exchange(ref _physicalVPressConsumed, 0);
				}
				if (Input.GetKeyDown(configuredKey) && Interlocked.CompareExchange(ref _physicalVPressConsumed, 1, 0) == 0)
				{
					Interlocked.Exchange(ref _nativeVPressPending, 0);
					ToggleDetected("Unity legacy input for " + ((object)(*(KeyCode*)(&configuredKey))/*cast due to .constrained prefix*/).ToString(), movement ?? ResolveMovement());
				}
			}
			ConsumeNativeV(source, movement);
		}

		private static NewMovement ResolveMovement()
		{
			NewMovement val = default(NewMovement);
			if (MonoSingleton<NewMovement>.TryGetInstance(ref val) && (Object)(object)val != (Object)null)
			{
				return val;
			}
			try
			{
				return Object.FindObjectOfType<NewMovement>();
			}
			catch
			{
				return null;
			}
		}

		private static void ToggleDetected(string source, NewMovement movement)
		{
			if ((Object)(object)movement != (Object)null)
			{
				Plugin.EnsureRuntime();
			}
			if (SandevistanClock.CanToggleWith(movement))
			{
				SandevistanClock.ToggleFromInput(source);
			}
		}

		private static void ReportGameplayReady(NewMovement movement)
		{
			Plugin.EnsureRuntime();
			SandevistanPlayer.Attach(movement);
		}

		private static void ReportBackendFailure(ref bool reported, string backend, Exception ex)
		{
			if (!reported)
			{
				reported = true;
				ManualLogSource modLog = Plugin.ModLog;
				if (modLog != null)
				{
					modLog.LogError((object)(backend + " input backend failed: " + ex.Message));
				}
			}
		}

		private unsafe static string ToInputSystemPath(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Invalid comparison between Unknown and I4
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Invalid comparison between Unknown and I4
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Invalid comparison between Unknown and I4
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Invalid comparison between Unknown and I4
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected I4, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Invalid comparison between Unknown and I4
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Invalid comparison between Unknown and I4
			//IL_005d: 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_0065: Expected I4, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Invalid comparison between Unknown and I4
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Invalid comparison between Unknown and I4
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: 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_0091: Expected I4, but got Unknown
			//IL_00f0: 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_0128: Expected I4, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Invalid comparison between Unknown and I4
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Invalid comparison between Unknown and I4
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected I4, but got Unknown
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Invalid comparison between Unknown and I4
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Invalid comparison between Unknown and I4
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Invalid comparison between Unknown and I4
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected I4, but got Unknown
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Invalid comparison between Unknown and I4
			if ((int)key >= 97 && (int)key <= 122)
			{
				return "<Keyboard>/" + ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant();
			}
			if ((int)key >= 48 && (int)key <= 57)
			{
				return "<Keyboard>/" + (key - 48);
			}
			if ((int)key >= 256 && (int)key <= 265)
			{
				return "<Keyboard>/numpad" + (key - 256);
			}
			if ((int)key >= 282 && (int)key <= 296)
			{
				return "<Keyboard>/f" + (key - 282 + 1);
			}
			if ((int)key <= 27)
			{
				if ((int)key <= 8)
				{
					if ((int)key == 0)
					{
						return null;
					}
					if ((int)key == 8)
					{
						return "<Keyboard>/backspace";
					}
				}
				else
				{
					if ((int)key == 9)
					{
						return "<Keyboard>/tab";
					}
					if ((int)key == 13)
					{
						return "<Keyboard>/enter";
					}
					if ((int)key == 27)
					{
						return "<Keyboard>/escape";
					}
				}
			}
			else if ((int)key <= 127)
			{
				if ((int)key == 32)
				{
					return "<Keyboard>/space";
				}
				if ((int)key == 127)
				{
					return "<Keyboard>/delete";
				}
			}
			else
			{
				switch (key - 271)
				{
				default:
					switch (key - 303)
					{
					case 1:
						return "<Keyboard>/leftShift";
					case 0:
						return "<Keyboard>/rightShift";
					case 3:
						return "<Keyboard>/leftCtrl";
					case 2:
						return "<Keyboard>/rightCtrl";
					case 5:
						return "<Keyboard>/leftAlt";
					case 4:
						return "<Keyboard>/rightAlt";
					}
					switch (key - 323)
					{
					case 0:
						return "<Mouse>/leftButton";
					case 1:
						return "<Mouse>/rightButton";
					case 2:
						return "<Mouse>/middleButton";
					}
					break;
				case 0:
					return "<Keyboard>/numpadEnter";
				case 6:
					return "<Keyboard>/insert";
				case 7:
					return "<Keyboard>/home";
				case 8:
					return "<Keyboard>/end";
				case 9:
					return "<Keyboard>/pageUp";
				case 10:
					return "<Keyboard>/pageDown";
				case 2:
					return "<Keyboard>/upArrow";
				case 3:
					return "<Keyboard>/downArrow";
				case 5:
					return "<Keyboard>/leftArrow";
				case 4:
					return "<Keyboard>/rightArrow";
				case 1:
					break;
				}
			}
			return "<Keyboard>/" + char.ToLowerInvariant(((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString()[0]) + ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString().Substring(1);
		}

		private static int ToVirtualKey(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected I4, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Invalid comparison between Unknown and I4
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Invalid comparison between Unknown and I4
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			//IL_0028: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected I4, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected I4, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Invalid comparison between Unknown and I4
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Invalid comparison between Unknown and I4
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Invalid comparison between Unknown and I4
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected I4, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Invalid comparison between Unknown and I4
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Invalid comparison between Unknown and I4
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Invalid comparison between Unknown and I4
			if (((int)key >= 97 && (int)key <= 122) || ((int)key >= 48 && (int)key <= 57))
			{
				return (int)key;
			}
			if ((int)key >= 282 && (int)key <= 296)
			{
				return 112 + key - 282;
			}
			if ((int)key <= 27)
			{
				if ((int)key <= 9)
				{
					if ((int)key == 8)
					{
						return 8;
					}
					if ((int)key == 9)
					{
						return 9;
					}
				}
				else
				{
					if ((int)key == 13)
					{
						return 13;
					}
					if ((int)key == 27)
					{
						return 27;
					}
				}
			}
			else if ((int)key <= 127)
			{
				if ((int)key == 32)
				{
					return 32;
				}
				if ((int)key == 127)
				{
					return 46;
				}
			}
			else
			{
				switch (key - 273)
				{
				case 4:
					return 45;
				case 5:
					return 36;
				case 6:
					return 35;
				case 7:
					return 33;
				case 8:
					return 34;
				case 0:
					return 38;
				case 1:
					return 40;
				case 3:
					return 37;
				case 2:
					return 39;
				}
				switch (key - 303)
				{
				case 0:
				case 1:
					return 16;
				case 2:
				case 3:
					return 17;
				case 4:
				case 5:
					return 18;
				}
			}
			return 0;
		}
	}
	[HarmonyPatch(typeof(NewMovement), "Awake")]
	public static class NewMovementAwakePatch
	{
		[HarmonyPostfix]
		public static void Postfix(NewMovement __instance)
		{
			SandevistanPlayer.Attach(__instance);
		}
	}
	[HarmonyPatch(typeof(NewMovement), "Start")]
	public static class NewMovementStartPatch
	{
		[HarmonyPostfix]
		public static void Postfix(NewMovement __instance)
		{
			SandevistanPlayer.Attach(__instance);
		}
	}
	[HarmonyPatch]
	public static class TimeControllerScalePatch
	{
		public static IEnumerable<MethodBase> TargetMethods()
		{
			HashSet<string> names = new HashSet<string> { "ContinueTime", "FixedUpdate", "HitStop", "InitializeValues", "RestoreTime", "TrueStop", "Update" };
			foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(typeof(TimeController)))
			{
				if (names.Contains(declaredMethod.Name))
				{
					yield return declaredMethod;
				}
			}
		}

		[HarmonyPostfix]
		public static void Postfix(TimeController __instance, MethodBase __originalMethod)
		{
			SandevistanInput.Poll("TimeController Harmony patch");
			SandevistanClock.CaptureAndApplyGameTime();
			if (SandevistanClock.Active && (__originalMethod.Name == "InitializeValues" || __originalMethod.Name == "FixedUpdate" || __originalMethod.Name == "TrueStop" || __originalMethod.Name == "ContinueTime"))
			{
				SandevistanAudioPitch.ApplyGamePitchMultiplier(__instance);
			}
		}
	}
	public static class SandevistanAudioPitch
	{
		private static readonly FieldInfo AudioMixersField = AccessTools.Field(typeof(TimeController), "audmix");

		public static void ApplyGamePitchMultiplier(TimeController controller)
		{
			if ((Object)(object)controller == (Object)null || AudioMixersField == null || Plugin.WorldAudioPitch == null || !(AudioMixersField.GetValue(controller) is AudioMixer[] array))
			{
				return;
			}
			float num = Mathf.Clamp(Plugin.WorldAudioPitch.Value, 0.25f, 1f);
			AudioMixer[] array2 = array;
			float num2 = default(float);
			foreach (AudioMixer val in array2)
			{
				if (!((Object)(object)val == (Object)null))
				{
					if (!val.GetFloat("allPitch", ref num2))
					{
						num2 = 1f;
					}
					val.SetFloat("allPitch", num2 * num);
				}
			}
		}

		public static void SetImmediate(bool active)
		{
			TimeController val = default(TimeController);
			if (MonoSingleton<TimeController>.TryGetInstance(ref val) && !((Object)(object)val == (Object)null))
			{
				val.SetAllPitch((active && Plugin.WorldAudioPitch != null) ? Mathf.Clamp(Plugin.WorldAudioPitch.Value, 0.25f, 1f) : 1f);
			}
		}
	}
	[HarmonyPatch(typeof(NewMovement), "Update")]
	public static class PlayerVelocityUpdatePatch
	{
		[HarmonyPrefix]
		public static void Prefix(NewMovement __instance)
		{
			SandevistanVelocity.FinishActivationStabilization(__instance);
			SandevistanInput.Poll("NewMovement.Update Harmony patch", __instance);
			SandevistanVelocity.EnterPlayerCode(__instance);
		}

		[HarmonyFinalizer]
		public static Exception Finalizer(Exception __exception)
		{
			SandevistanVelocity.ExitPlayerCode();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(NewMovement), "FixedUpdate")]
	public static class PlayerVelocityFixedUpdatePatch
	{
		[HarmonyPrefix]
		public static void Prefix(NewMovement __instance)
		{
			SandevistanVelocity.EnterPlayerCode(__instance);
		}

		[HarmonyFinalizer]
		public static Exception Finalizer(NewMovement __instance, Exception __exception)
		{
			SandevistanVelocity.ApplyGravityCompensation(__instance);
			SandevistanVelocity.ExitPlayerFixedCode();
			return __exception;
		}
	}
	[HarmonyPatch]
	public static class PlayerMovementForcePatch
	{
		public static IEnumerable<MethodBase> TargetMethods()
		{
			foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(typeof(NewMovement)))
			{
				if (declaredMethod.Name == "Jump" || declaredMethod.Name == "WallJump" || declaredMethod.Name == "Launch" || declaredMethod.Name == "LaunchUp" || declaredMethod.Name == "LaunchFromPoint" || declaredMethod.Name == "LaunchFromPointAtSpeed")
				{
					yield return declaredMethod;
				}
			}
		}

		[HarmonyPrefix]
		public static void Prefix(NewMovement __instance)
		{
			SandevistanVelocity.EnterPlayerCode(__instance);
		}

		[HarmonyFinalizer]
		public static Exception Finalizer(Exception __exception)
		{
			SandevistanVelocity.ExitPlayerCode();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Explosion), "Collide")]
	public static class PlayerExplosionVelocityReadPatch
	{
		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			FieldInfo objB = AccessTools.Field(typeof(NewMovement), "rb");
			MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(Rigidbody), "velocity");
			MethodInfo operand = AccessTools.Method(typeof(SandevistanVelocity), "ReadLogicalPlayerVelocity", (Type[])null, (Type[])null);
			int num = 0;
			for (int i = 0; i < list.Count; i++)
			{
				if (i > 0 && CodeInstructionExtensions.Calls(list[i], methodInfo) && list[i - 1].opcode == OpCodes.Ldfld && object.Equals(list[i - 1].operand, objB))
				{
					list[i] = ReplaceInstruction(list[i], OpCodes.Call, operand);
					num++;
				}
			}
			return list;
		}

		private static CodeInstruction ReplaceInstruction(CodeInstruction original, OpCode opcode, object operand)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			CodeInstruction val = new CodeInstruction(opcode, operand);
			val.labels.AddRange(original.labels);
			val.blocks.AddRange(original.blocks);
			return val;
		}
	}
	[HarmonyPatch]
	public static class EnemyPlayerVelocityReadPatch
	{
		public static IEnumerable<MethodBase> TargetMethods()
		{
			foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(typeof(PlayerTracker)))
			{
				if (declaredMethod.Name == "GetPlayerVelocity" || declaredMethod.Name == "PredictPlayerPosition")
				{
					yield return declaredMethod;
				}
			}
			foreach (MethodInfo declaredMethod2 in AccessTools.GetDeclaredMethods(typeof(EnemyTarget)))
			{
				if (declaredMethod2.Name == "GetVelocity")
				{
					yield return declaredMethod2;
				}
			}
			foreach (MethodInfo declaredMethod3 in AccessTools.GetDeclaredMethods(typeof(V2)))
			{
				if (declaredMethod3.Name == "LateUpdate")
				{
					yield return declaredMethod3;
				}
			}
		}

		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
		{
			MethodInfo velocityGetter = AccessTools.PropertyGetter(typeof(Rigidbody), "velocity");
			MethodInfo logicalGetter = AccessTools.Method(typeof(SandevistanVelocity), "ReadLogicalPlayerVelocity", (Type[])null, (Type[])null);
			int replacements = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, velocityGetter))
				{
					CodeInstruction val = new CodeInstruction(OpCodes.Call, (object)logicalGetter);
					val.labels.AddRange(instruction.labels);
					val.blocks.AddRange(instruction.blocks);
					replacements++;
					yield return val;
				}
				else
				{
					yield return instruction;
				}
			}
		}
	}
	[HarmonyPatch(typeof(V2), "LateUpdate")]
	public static class V2AimRotationPatch
	{
		public sealed class AimSnapshot
		{
			public Transform[] Targets;

			public Quaternion[] Rotations;
		}

		private static readonly FieldInfo AimAtTarget = AccessTools.Field(typeof(V2), "aimAtTarget");

		private static readonly Dictionary<int, AimSnapshot> Snapshots = new Dictionary<int, AimSnapshot>();

		[HarmonyPrefix]
		public static void Prefix(V2 __instance, ref AimSnapshot __state)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			if (!SandevistanClock.Active || AimAtTarget == null || !(AimAtTarget.GetValue(__instance) is Transform[] array) || array.Length == 0)
			{
				return;
			}
			int instanceID = ((Object)__instance).GetInstanceID();
			if (!Snapshots.TryGetValue(instanceID, out __state))
			{
				__state = new AimSnapshot();
				Snapshots[instanceID] = __state;
			}
			__state.Targets = array;
			if (__state.Rotations == null || __state.Rotations.Length != array.Length)
			{
				__state.Rotations = (Quaternion[])(object)new Quaternion[array.Length];
			}
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i] != (Object)null)
				{
					__state.Rotations[i] = array[i].rotation;
				}
			}
		}

		[HarmonyPostfix]
		public static void Postfix(AimSnapshot __state)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (__state == null || !SandevistanClock.Active)
			{
				return;
			}
			float num = 1080f * Mathf.Max(0f, Time.deltaTime);
			for (int i = 0; i < __state.Targets.Length; i++)
			{
				Transform val = __state.Targets[i];
				if ((Object)(object)val != (Object)null)
				{
					val.rotation = Quaternion.RotateTowards(__state.Rotations[i], val.rotation, num);
				}
			}
		}
	}
	[HarmonyPatch(typeof(V2), "Update")]
	public static class V2BodyRotationPatch
	{
		[HarmonyPrefix]
		public static void Prefix(V2 __instance, ref Quaternion __state)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (SandevistanClock.Active && (Object)(object)__instance != (Object)null)
			{
				__state = ((Component)__instance).transform.rotation;
			}
		}

		[HarmonyPostfix]
		public static void Postfix(V2 __instance, Quaternion __state)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			if (SandevistanClock.Active && !((Object)(object)__instance == (Object)null))
			{
				Quaternion rotation = ((Component)__instance).transform.rotation;
				float num = 720f * Mathf.Max(0f, Time.deltaTime);
				if (Quaternion.Angle(__state, rotation) > num)
				{
					((Component)__instance).transform.rotation = Quaternion.RotateTowards(__state, rotation, num);
				}
			}
		}
	}
	[HarmonyPatch]
	public static class PlayerVelocityViewPatch
	{
		public static IEnumerable<MethodBase> TargetMethods()
		{
			string[] array = new string[3] { "CameraController:LateUpdate", "WalkingBob:Update", "PlayerAnimations:LateUpdate" };
			string[] array2 = array;
			foreach (string text in array2)
			{
				string[] split = text.Split(new char[1] { ':' });
				Type type = AccessTools.TypeByName(split[0]);
				if (type == null)
				{
					continue;
				}
				foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type))
				{
					if (declaredMethod.Name == split[1])
					{
						yield return declaredMethod;
					}
				}
			}
		}

		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
		{
			MethodInfo velocityGetter = AccessTools.PropertyGetter(typeof(Rigidbody), "velocity");
			MethodInfo logicalGetter = AccessTools.Method(typeof(SandevistanVelocity), "ReadLogicalPlayerVelocity", (Type[])null, (Type[])null);
			int replacements = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, velocityGetter))
				{
					replacements++;
					CodeInstruction val = new CodeInstruction(OpCodes.Call, (object)logicalGetter);
					val.labels.AddRange(instruction.labels);
					val.blocks.AddRange(instruction.blocks);
					yield return val;
				}
				else
				{
					yield return instruction;
				}
			}
		}
	}
	[HarmonyPatch]
	public static class PunchAnimatorClockPatch
	{
		public static IEnumerable<MethodBase> TargetMethods()
		{
			string[] array = new string[3] { "PunchStart", "ActiveStart", "OnEnable" };
			foreach (string text in array)
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Punch), text, (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					yield return methodInfo;
				}
			}
		}

		[HarmonyPostfix]
		public static void Postfix(Punch __instance)
		{
			if (SandevistanClock.Active && !((Object)(object)__instance == (Object)null))
			{
				Animator component = ((Component)__instance).GetComponent<Animator>();
				if ((Object)(object)component != (Object)null)
				{
					SandevistanPlayerAnimator.Ensure(component);
				}
			}
		}
	}
	[HarmonyPatch]
	public static class WeaponSwitchAnimatorPatch
	{
		public static IEnumerable<MethodBase> TargetMethods()
		{
			foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(typeof(GunControl)))
			{
				if (declaredMethod.Name == "SwitchWeapon" || declaredMethod.Name == "ForceWeapon" || declaredMethod.Name == "YesWeapon")
				{
					yield return declaredMethod;
				}
			}
		}

		[HarmonyPostfix]
		public static void Postfix(GunControl __instance)
		{
			NewMovement val = default(NewMovement);
			if (SandevistanClock.Active && MonoSingleton<NewMovement>.TryGetInstance(ref val) && !((Object)(object)val == (Object)null))
			{
				SandevistanVisuals component = ((Component)val).GetComponent<SandevistanVisuals>();
				if ((Object)(object)component != (Object)null)
				{
					component.RefreshWeaponAnimators(__instance);
				}
			}
		}

		[HarmonyPrefix]
		public static void Prefix()
		{
			PreparePlayerAnimatorsBeforeEnable();
		}

		internal static void PreparePlayerAnimatorsBeforeEnable()
		{
			NewMovement val = default(NewMovement);
			if (SandevistanClock.Active && MonoSingleton<NewMovement>.TryGetInstance(ref val) && !((Object)(object)val == (Object)null))
			{
				SandevistanVisuals component = ((Component)val).GetComponent<SandevistanVisuals>();
				if ((Object)(object)component != (Object)null)
				{
					component.PreparePlayerAnimatorsForEnable();
				}
			}
		}
	}
	[HarmonyPatch]
	public static class FistPreEnableAnimatorPatch
	{
		public static IEnumerable<MethodBase> TargetMethods()
		{
			Type typeFromHandle = typeof(FistControl);
			HashSet<string> names = new HashSet<string> { "ArmChange", "YesFist", "ResetFists", "CheckFist" };
			foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(typeFromHandle))
			{
				if (names.Contains(declaredMethod.Name))
				{
					yield return declaredMethod;
				}
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(Punch), "OnEnable", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				yield return methodInfo;
			}
		}

		[HarmonyPrefix]
		public static void Prefix()
		{
			WeaponSwitchAnimatorPatch.PreparePlayerAnimatorsBeforeEnable();
		}
	}
	[HarmonyPatch]
	public static class ShotgunPreEnableAnimatorPatch
	{
		public static IEnumerable<MethodBase> TargetMethods()
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(Shotgun), "OnEnable", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				yield return methodInfo;
			}
			Type type = AccessTools.TypeByName("ShotgunHammer");
			MethodInfo methodInfo2 = ((type == null) ? null : AccessTools.Method(type, "OnEnable", (Type[])null, (Type[])null));
			if (methodInfo2 != null)
			{
				yield return methodInfo2;
			}
		}

		[HarmonyPrefix]
		public static void Prefix(Component __instance)
		{
			if (!SandevistanClock.Active || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			WeaponSwitchAnimatorPatch.PreparePlayerAnimatorsBeforeEnable();
			Animator[] componentsInChildren = __instance.GetComponentsInChildren<Animator>(true);
			foreach (Animator val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					SandevistanPlayerAnimator.Ensure(val);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Explosion), "Start")]
	public static class ExplosionFlashRealTimePatch
	{
		[HarmonyPostfix]
		public static void Postfix(Explosion __instance)
		{
			if ((Object)(object)__instance != (Object)null && (Object)(object)((Component)__instance).GetComponent<SandevistanExplosionFlash>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<SandevistanExplosionFlash>();
			}
		}
	}
	[HarmonyPatch]
	public static class PlayerTimeTranspilers
	{
		public static IEnumerable<MethodBase> TargetMethods()
		{
			string[] array = new string[67]
			{
				"NewMovement:Update", "NewMovement:FixedUpdate", "NewMovement:Move", "NewMovement:Jump", "NewMovement:WallJump", "NewMovement:Dodge", "NewMovement:TrySSJ", "NewMovement:Cling", "NewMovement:HandleSlideState", "NewMovement:TryFloorSnap",
				"NewMovement:Launch", "NewMovement:LaunchUp", "NewMovement:LaunchFromPoint", "NewMovement:LaunchFromPointAtSpeed", "CameraController:LateUpdate", "PlayerAnimations:LateUpdate", "GunControl:Update", "FistControl:Update", "Punch:Update", "WalkingBob:Update",
				"WeaponCharges:Update", "WeaponCharges:Charge", "Revolver:Update", "Revolver:LateUpdate", "Shotgun:Start", "Shotgun:OnEnable", "Shotgun:OnDisable", "Shotgun:Update", "Shotgun:UpdateMeter", "ShotgunHammer:OnEnable",
				"ShotgunHammer:Update", "ShotgunHammer:FixedUpdate", "ShotgunHammer:ThrowNade", "ShotgunHammer:Pump", "ShotgunHammer:UpdateMeter", "ShotgunHammer:LateUpdate", "Nailgun:Update", "Nailgun:FixedUpdate", "Nailgun:UpdateZapHud", "Nailgun:RefreshHeatSinkFill",
				"RocketLauncher:Start", "RocketLauncher:OnEnable", "RocketLauncher:OnDisable", "RocketLauncher:Update", "RocketLauncher:FixedUpdate", "RocketLauncher:FreezeRockets", "Chainsaw:Start", "Chainsaw:Update", "Chainsaw:FixedUpdate", "Chainsaw:GetPunched",
				"NewMovement:HandleInputs", "HookArm:Update", "HookArm:FixedUpdate", "HookArm:SemiBlockCheck", "HookArm:UpdateLineRendererPositions", "ClimbStep:FixedUpdate", "GroundCheck:UpdateState", "StaminaMeter:Update", "HurtZone:FixedUpdate", "Noclip:UpdateTick",
				"Sandbox.Arm.SandboxArm:Update", "NewMovement:Parry", "TimeController:ParryFlash", "ParryFlash:Update", "FlashImage:Update", "HealthBar:Update", "ScreenBlood:Update"
			};
			HashSet<MethodBase> yielded = new HashSet<MethodBase>();
			string[] array2 = array;
			foreach (string text in array2)
			{
				string[] split = text.Split(new char[1] { ':' });
				Type type = AccessTools.TypeByName(split[0]);
				if (type == null)
				{
					continue;
				}
				foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type))
				{
					if (declaredMethod.Name == split[1] && yielded.Add(declaredMethod))
					{
						yield return declaredMethod;
					}
				}
			}
			string[] array3 = new string[13]
			{
				"GunControl", "FistControl", "Punch", "WalkingBob", "WeaponCharges", "Revolver", "Shotgun", "ShotgunHammer", "Nailgun", "RocketLauncher",
				"Railcannon", "Chainsaw", "HookArm"
			};
			array2 = array3;
			for (int i = 0; i < array2.Length; i++)
			{
				Type type2 = AccessTools.TypeByName(array2[i]);
				if (type2 == null)
				{
					continue;
				}
				foreach (MethodBase patchableMethod in GetPatchableMethods(type2))
				{
					if (yielded.Add(patchableMethod))
					{
						yield return patchableMethod;
					}
				}
			}
		}

		private static IEnumerable<MethodBase> GetPatchableMethods(Type type)
		{
			MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (!methodInfo.IsAbstract && !methodInfo.ContainsGenericParameters && methodInfo.GetMethodBody() != null)
				{
					yield return methodInfo;
				}
			}
			Type[] nestedTypes = type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic);
			foreach (Type type2 in nestedTypes)
			{
				foreach (MethodBase patchableMethod in GetPatchableMethods(type2))
				{
					yield return patchableMethod;
				}
			}
		}

		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
		{
			MethodInfo deltaTime = AccessTools.PropertyGetter(typeof(Time), "deltaTime");
			MethodInfo fixedDeltaTime = AccessTools.PropertyGetter(typeof(Time), "fixedDeltaTime");
			MethodInfo timeScale = AccessTools.PropertyGetter(typeof(Time), "timeScale");
			MethodInfo playerDeltaTime = AccessTools.PropertyGetter(typeof(SandevistanClock), "PlayerDeltaTime");
			MethodInfo playerFixedDeltaTime = AccessTools.PropertyGetter(typeof(SandevistanClock), "PlayerFixedDeltaTime");
			MethodInfo playerTimeScale = AccessTools.PropertyGetter(typeof(SandevistanClock), "PlayerTimeScale");
			MethodInfo readTimeSince = AccessTools.Method(typeof(TimeSince), "op_Implicit", new Type[1] { typeof(TimeSince) }, (Type[])null);
			MethodInfo createTimeSince = AccessTools.Method(typeof(TimeSince), "op_Implicit", new Type[1] { typeof(float) }, (Type[])null);
			MethodInfo readPlayerTimeSince = AccessTools.Method(typeof(SandevistanClock), "ReadPlayerTimeSince", (Type[])null, (Type[])null);
			MethodInfo createPlayerTimeSince = AccessTools.Method(typeof(SandevistanClock), "CreatePlayerTimeSince", (Type[])null, (Type[])null);
			ConstructorInfo waitForSeconds = AccessTools.Constructor(typeof(WaitForSeconds), new Type[1] { typeof(float) }, false);
			ConstructorInfo waitForPlayerSeconds = AccessTools.Constructor(typeof(WaitForPlayerSeconds), new Type[1] { typeof(float) }, false);
			MethodInfo invoke = AccessTools.Method(typeof(MonoBehaviour), "Invoke", new Type[2]
			{
				typeof(string),
				typeof(float)
			}, (Type[])null);
			MethodInfo invokePlayer = AccessTools.Method(typeof(SandevistanClock), "InvokePlayer", (Type[])null, (Type[])null);
			MethodInfo addForce = AccessTools.Method(typeof(Rigidbody), "AddForce", new Type[1] { typeof(Vector3) }, (Type[])null);
			MethodInfo addPlayerForce = AccessTools.Method(typeof(SandevistanClock), "AddPlayerForce", new Type[2]
			{
				typeof(Rigidbody),
				typeof(Vector3)
			}, (Type[])null);
			MethodInfo addForceMode = AccessTools.Method(typeof(Rigidbody), "AddForce", new Type[2]
			{
				typeof(Vector3),
				typeof(ForceMode)
			}, (Type[])null);
			MethodInfo addPlayerForceMode = AccessTools.Method(typeof(SandevistanClock), "AddPlayerForce", new Type[3]
			{
				typeof(Rigidbody),
				typeof(Vector3),
				typeof(ForceMode)
			}, (Type[])null);
			bool jumpForceMethod = __originalMethod.DeclaringType == typeof(NewMovement) && (__originalMethod.Name == "Jump" || __originalMethod.Name == "WallJump");
			bool launchForceMethod = __originalMethod.DeclaringType == typeof(NewMovement) && (__originalMethod.Name == "Launch" || __originalMethod.Name == "LaunchUp" || __originalMethod.Name == "LaunchFromPoint" || __originalMethod.Name == "LaunchFromPointAtSpeed");
			Type type = typeof(float).MakeByRefType();
			Type type2 = typeof(Vector3).MakeByRefType();
			MethodInfo smoothAngle4 = AccessTools.Method(typeof(Mathf), "SmoothDampAngle", new Type[4]
			{
				typeof(float),
				typeof(float),
				type,
				typeof(float)
			}, (Type[])null);
			MethodInfo smoothAngle5 = AccessTools.Method(typeof(Mathf), "SmoothDampAngle", new Type[5]
			{
				typeof(float),
				typeof(float),
				type,
				typeof(float),
				typeof(float)
			}, (Type[])null);
			MethodInfo smoothAngle6 = AccessTools.Method(typeof(Mathf), "SmoothDampAngle", new Type[6]
			{
				typeof(float),
				typeof(float),
				type,
				typeof(float),
				typeof(float),
				typeof(float)
			}, (Type[])null);
			MethodInfo smooth4 = AccessTools.Method(typeof(Mathf), "SmoothDamp", new Type[4]
			{
				typeof(float),
				typeof(float),
				type,
				typeof(float)
			}, (Type[])null);
			MethodInfo smooth5 = AccessTools.Method(typeof(Mathf), "SmoothDamp", new Type[5]
			{
				typeof(float),
				typeof(float),
				type,
				typeof(float),
				typeof(float)
			}, (Type[])null);
			MethodInfo smooth6 = AccessTools.Method(typeof(Mathf), "SmoothDamp", new Type[6]
			{
				typeof(float),
				typeof(float),
				type,
				typeof(float),
				typeof(float),
				typeof(float)
			}, (Type[])null);
			MethodInfo vectorSmooth4 = AccessTools.Method(typeof(Vector3), "SmoothDamp", new Type[4]
			{
				typeof(Vector3),
				typeof(Vector3),
				type2,
				typeof(float)
			}, (Type[])null);
			MethodInfo vectorSmooth5 = AccessTools.Method(typeof(Vector3), "SmoothDamp", new Type[5]
			{
				typeof(Vector3),
				typeof(Vector3),
				type2,
				typeof(float),
				typeof(float)
			}, (Type[])null);
			MethodInfo vectorSmooth6 = AccessTools.Method(typeof(Vector3), "SmoothDamp", new Type[6]
			{
				typeof(Vector3),
				typeof(Vector3),
				type2,
				typeof(float),
				typeof(float),
				typeof(float)
			}, (Type[])null);
			int replacements = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				MethodInfo methodInfo = null;
				if (CodeInstructionExtensions.Calls(instruction, deltaTime))
				{
					methodInfo = playerDeltaTime;
				}
				else if (CodeInstructionExtensions.Calls(instruction, fixedDeltaTime))
				{
					methodInfo = playerFixedDeltaTime;
				}
				else if (CodeInstructionExtensions.Calls(instruction, timeScale))
				{
					methodInfo = playerTimeScale;
				}
				if (methodInfo != null)
				{
					replacements++;
					yield return ReplaceInstruction(instruction, OpCodes.Call, methodInfo);
				}
				else if (CodeInstructionExtensions.Calls(instruction, readTimeSince) || CodeInstructionExtensions.Calls(instruction, createTimeSince))
				{
					replacements++;
					yield return ReplaceInstruction(instruction, OpCodes.Call, CodeInstructionExtensions.Calls(instruction, readTimeSince) ? readPlayerTimeSince : createPlayerTimeSince);
				}
				else if (instruction.opcode == OpCodes.Newobj && object.Equals(instruction.operand, waitForSeconds))
				{
					replacements++;
					yield return ReplaceInstruction(instruction, OpCodes.Newobj, waitForPlayerSeconds);
				}
				else if (CodeInstructionExtensions.Calls(instruction, invoke))
				{
					replacements++;
					yield return ReplaceInstruction(instruction, OpCodes.Call, invokePlayer);
				}
				else if (jumpForceMethod && CodeInstructionExtensions.Calls(instruction, addForce))
				{
					replacements++;
					yield return ReplaceInstruction(instruction, OpCodes.Call, addPlayerForce);
				}
				else if (launchForceMethod && CodeInstructionExtensions.Calls(instruction, addForceMode))
				{
					replacements++;
					yield return ReplaceInstruction(instruction, OpCodes.Call, addPlayerForceMode);
				}
				else if (CodeInstructionExtensions.Calls(instruction, smoothAngle4) || CodeInstructionExtensions.Calls(instruction, smooth4) || CodeInstructionExtensions.Calls(instruction, vectorSmooth4))
				{
					replacements++;
					CodeInstruction val = new CodeInstruction(OpCodes.Ldc_R4, (object)float.PositiveInfinity);
					CopyMetadata(instruction, val);
					yield return val;
					yield return new CodeInstruction(OpCodes.Call, (object)playerDeltaTime);
					yield return new CodeInstruction(OpCodes.Call, (object)(CodeInstructionExtensions.Calls(instruction, smoothAngle4) ? smoothAngle6 : (CodeInstructionExtensions.Calls(instruction, smooth4) ? smooth6 : vectorSmooth6)));
				}
				else if (CodeInstructionExtensions.Calls(instruction, smoothAngle5) || CodeInstructionExtensions.Calls(instruction, smooth5) || CodeInstructionExtensions.Calls(instruction, vectorSmooth5))
				{
					replacements++;
					CodeInstruction val2 = new CodeInstruction(OpCodes.Call, (object)playerDeltaTime);
					CopyMetadata(instruction, val2);
					yield return val2;
					yield return new CodeInstruction(OpCodes.Call, (object)(CodeInstructionExtensions.Calls(instruction, smoothAngle5) ? smoothAngle6 : (CodeInstructionExtensions.Calls(instruction, smooth5) ? smooth6 : vectorSmooth6)));
				}
				else
				{
					yield return instruction;
				}
			}
		}

		private static CodeInstruction ReplaceInstruction(CodeInstruction source, OpCode opcode, object operand)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			CodeInstruction val = new CodeInstruction(opcode, operand);
			CopyMetadata(source, val);
			return val;
		}

		private static void CopyMetadata(CodeInstruction source, CodeInstruction destination)
		{
			destination.labels.AddRange(source.labels);
			destination.blocks.AddRange(source.blocks);
		}
	}
	public sealed class WaitForPlayerSeconds : CustomYieldInstruction
	{
		private float _remaining;

		public override bool keepWaiting
		{
			get
			{
				_remaining -= SandevistanClock.PlayerDeltaTime;
				return _remaining > 0f;
			}
		}

		public WaitForPlayerSeconds(float seconds)
		{
			_remaining = seconds;
		}
	}
	[DefaultExecutionOrder(30000)]
	public sealed class SandevistanPlayerAnimator : MonoBehaviour
	{
		private Animator _animator;

		private AnimatorUpdateMode _normalUpdateMode;

		private AnimatorCullingMode _normalCullingMode;

		private float _normalSpeed;

		private bool _captured;

		private bool _applied;

		public static SandevistanPlayerAnimator Ensure(Animator animator)
		{
			if ((Object)(object)animator == (Object)null)
			{
				return null;
			}
			SandevistanPlayerAnimator sandevistanPlayerAnimator = ((Component)animator).GetComponent<SandevistanPlayerAnimator>();
			if ((Object)(object)sandevistanPlayerAnimator == (Object)null)
			{
				sandevistanPlayerAnimator = ((Component)animator).gameObject.AddComponent<SandevistanPlayerAnimator>();
			}
			sandevistanPlayerAnimator.Capture(animator);
			sandevistanPlayerAnimator.ApplyNow();
			return sandevistanPlayerAnimator;
		}

		public void Awake()
		{
			Capture(((Component)this).GetComponent<Animator>());
		}

		public void OnEnable()
		{
			ApplyNow();
		}

		public void Update()
		{
			ApplyNow();
		}

		public void LateUpdate()
		{
			ApplyNow();
		}

		private void Capture(Animator animator)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)animator == (Object)null))
			{
				_animator = animator;
				if (!_captured || !_applied)
				{
					_normalUpdateMode = animator.updateMode;
					_normalCullingMode = animator.cullingMode;
					_normalSpeed = animator.speed;
					_captured = true;
				}
			}
		}

		public void ApplyNow()
		{
			if (_captured && !((Object)(object)_animator == (Object)null))
			{
				if (SandevistanClock.Active)
				{
					float speed = CompensatedSpeed(_normalSpeed);
					_animator.updateMode = (AnimatorUpdateMode)0;
					_animator.cullingMode = (AnimatorCullingMode)0;
					_animator.speed = speed;
					_applied = true;
				}
				else
				{
					Restore();
				}
			}
		}

		public void Restore()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (_captured && !((Object)(object)_animator == (Object)null) && _applied)
			{
				_animator.updateMode = _normalUpdateMode;
				_animator.cullingMode = _normalCullingMode;
				_animator.speed = _normalSpeed;
				_applied = false;
			}
		}

		public static float CompensatedSpeed(float authoredSpeed)
		{
			float num = Mathf.Max(SandevistanClock.EffectiveWorldScale, 0.001f);
			return authoredSpeed / num;
		}
	}
	public static class SandevistanPlayerInvokes
	{
		private sealed class PendingInvoke
		{
			public MonoBehaviour Target;

			public MethodInfo Method;

			public string MethodName;

			public float Remaining;
		}

		private static readonly List<PendingInvoke> Pending = new List<PendingInvoke>();

		private static int _lastTickFrame = -1;

		public static bool IsPlayerOwned(MonoBehaviour behaviour)
		{
			if ((Object)(object)behaviour == (Object)null)
			{
				return false;
			}
			NewMovement val = default(NewMovement);
			if (MonoSingleton<NewMovement>.TryGetInstance(ref val) && (Object)(object)val != (Object)null)
			{
				Transform transform = ((Component)val).transform;
				Transform transform2 = ((Component)behaviour).transform;
				if ((Object)(object)transform2 == (Object)(object)transform || transform2.IsChildOf(transform))
				{
					return true;
				}
			}
			GunControl val2 = default(GunControl);
			if (MonoSingleton<GunControl>.TryGetInstance(ref val2) && (Object)(object)val2 != (Object)null && ((Object)(object)((Component)behaviour).transform == (Object)(object)((Component)val2).transform || ((Component)behaviour).transform.IsChildOf(((Component)val2).transform)))
			{
				return true;
			}
			FistControl val3 = default(FistControl);
			if (MonoSingleton<FistControl>.TryGetInstance(ref val3) && (Object)(object)val3 != (Object)null)
			{
				if (!((Object)(object)((Component)behaviour).transform == (Object)(object)((Component)val3).transform))
				{
					return ((Component)behaviour).transform.IsChildOf(((Component)val3).transform);
				}
				return true;
			}
			return false;
		}

		public static bool Schedule(MonoBehaviour target, string methodName, float delay)
		{
			if ((Object)(object)target == (Object)null || string.IsNullOrEmpty(methodName))
			{
				return false;
			}
			MethodInfo methodInfo = AccessTools.Method(((object)target).GetType(), methodName, Type.EmptyTypes, (Type[])null);
			if (methodInfo == null)
			{
				return false;
			}
			Pending.Add(new PendingInvoke
			{
				Target = target,
				Method = methodInfo,
				MethodName = methodName,
				Remaining = Mathf.Max(0f, delay)
			});
			return true;
		}

		public static void Cancel(MonoBehaviour target, string methodName = null)
		{
			for (int num = Pending.Count - 1; num >= 0; num--)
			{
				PendingInvoke pendingInvoke = Pending[num];
				if ((Object)(object)pendingInvoke.Target == (Object)(object)target && (methodName == null || pendingInvoke.MethodName == methodName))
				{
					Pending.RemoveAt(num);
				}
			}
		}

		public static bool IsScheduled(MonoBehaviour target, string methodName)
		{
			for (int i = 0; i < Pending.Count; i++)
			{
				if ((Object)(object)Pending[i].Target == (Object)(object)target && Pending[i].MethodName == methodName)
				{
					return true;
				}
			}
			return false;
		}

		public static void Tick()
		{
			if (_lastTickFrame == Time.frameCount)
			{
				return;
			}
			_lastTickFrame = Time.frameCount;
			float playerDeltaTime = SandevistanClock.PlayerDeltaTime;
			for (int num = Pending.Count - 1; num >= 0; num--)
			{
				PendingInvoke pendingInvoke = Pending[num];
				if ((Object)(object)pendingInvoke.Target == (Object)null)
				{
					Pending.RemoveAt(num);
				}
				else
				{
					pendingInvoke.Remaining -= playerDeltaTime;
					if (!(pendingInvoke.Remaining > 0f))
					{
						Pending.RemoveAt(num);
						try
						{
							pendingInvoke.Method.Invoke(pendingInvoke.Target, null);
						}
						catch (TargetInvocationException ex)
						{
							ManualLogSource modLog = Plugin.ModLog;
							if (modLog != null)
							{
								modLog.LogError((object)("Player Invoke failed: " + ((object)pendingInvoke.Target).GetType().Name + "." + pendingInvoke.MethodName + ": " + (ex.InnerException ?? ex)));
							}
						}
						catch (Exception ex2)
						{
							ManualLogSource modLog2 = Plugin.ModLog;
							if (modLog2 != null)
							{
								modLog2.LogError((object)("Player Invoke failed: " + ex2));
							}
						}
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(MonoBehaviour), "Invoke", new Type[]
	{
		typeof(string),
		typeof(float)
	})]
	public static class PlayerOwnedInvokePatch
	{
		[HarmonyPrefix]
		public static bool Prefix(MonoBehaviour __instance, string methodName, float time)
		{
			if (!SandevistanClock.Active || !SandevistanPlayerInvokes.IsPlayerOwned(__instance))
			{
				return true;
			}
			return !SandevistanPlayerInvokes.Schedule(__instance, methodName, time);
		}
	}
	[HarmonyPatch(typeof(MonoBehaviour), "CancelInvoke", new Type[] { typeof(string) })]
	public static class PlayerOwnedCancelNamedInvokePatch
	{
		[HarmonyPrefix]
		public static void Prefix(MonoBehaviour __instance, string methodName)
		{
			SandevistanPlayerInvokes.Cancel(__instance, methodName);
		}
	}
	[HarmonyPatch(typeof(MonoBehaviour), "CancelInvoke", new Type[] { })]
	public static class PlayerOwnedCancelAllInvokesPatch
	{
		[HarmonyPrefix]
		public static void Prefix(MonoBehaviour __instance)
		{
			SandevistanPlayerInvokes.Cancel(__instance);
		}
	}
	[HarmonyPatch(typeof(MonoBehaviour), "IsInvoking", new Type[] { typeof(string) })]
	public static class PlayerOwnedIsInvokingPatch
	{
		[HarmonyPostfix]
		public static void Postfix(MonoBehaviour __instance, string methodName, ref bool __result)
		{
			if (!__result)
			{
				__result = SandevistanPlayerInvokes.IsScheduled(__instance, methodName);
			}
		}
	}
	public class SandevistanRuntime : MonoBehaviour
	{
		private const int SampleRate = 44100;

		private AudioSource _effectSource;

		private AudioClip _activateClip;

		private AudioClip _deactivateClip;

		private bool _initialized;

		private AudioMixerGroup _routedSfxGroup;

		public void Initialize()
		{
			if (!_initialized)
			{
				_effectSource = ((Component)this).gameObject.AddComponent<AudioSource>();
				ConfigureSource(_effectSource);
				_activateClip = LoadEmbeddedPcmWav("SandevistanMod.Audio.EdgeEnter.wav", "EdgeEnter") ?? CreateActivationClip();
				_deactivateClip = LoadEmbeddedPcmWav("SandevistanMod.Audio.EdgeExit.wav", "EdgeExit") ?? CreateDeactivationClip();
				Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
				SceneManager.sceneLoaded += OnSceneLoaded;
				_initialized = true;
			}
		}

		private void Update()
		{
			SandevistanInput.Poll("persistent runtime Update");
			SandevistanClock.MaintainWorldTime();
			SandevistanPlayerInvokes.Tick();
		}

		private void LateUpdate()
		{
			SandevistanClock.MaintainWorldTime();
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if (SandevistanClock.Active)
			{
				SandevistanClock.SetActive(active: false, "scene change");
			}
			((MonoBehaviour)this).StartCoroutine(FindPlayer());
		}

		private IEnumerator FindPlayer()
		{
			NewMovement val = default(NewMovement);
			for (int i = 0; i < 1200; i++)
			{
				if (MonoSingleton<NewMovement>.TryGetInstance(ref val) && (Object)(object)val != (Object)null)
				{
					SandevistanPlayer.Attach(val);
					break;
				}
				yield return null;
			}
		}

		private static void ConfigureSource(AudioSource source)
		{
			source.playOnAwake = false;
			source.spatialBlend = 0f;
			source.dopplerLevel = 0f;
			source.bypassReverbZones = true;
		}

		public void OnSandevistanStateChanged(bool active)
		{
			if (!_initialized)
			{
				return;
			}
			SandevistanAudioPitch.SetImmediate(active);
			if (!Plugin.SoundEffects.Value)
			{
				_effectSource.Stop();
				return;
			}
			float num = Mathf.Clamp01(Plugin.SoundVolume.Value);
			RouteToGameSfxMixer();
			_effectSource.volume = num * 0.8f;
			_effectSource.Stop();
			if (active)
			{
				_effectSource.clip = _activateClip;
				_effectSource.Play();
			}
			else
			{
				_effectSource.clip = _deactivateClip;
				_effectSource.Play();
			}
		}

		private void RouteToGameSfxMixer()
		{
			if ((Object)(object)_routedSfxGroup != (Object)null)
			{
				_effectSource.outputAudioMixerGroup = _routedSfxGroup;
			}
			else
			{
				NewMovement val = default(NewMovement);
				if (!MonoSingleton<NewMovement>.TryGetInstance(ref val) || (Object)(object)val == (Object)null)
				{
					return;
				}
				AudioMixerGroup val2 = null;
				AudioSource[] componentsInChildren = ((Component)val).GetComponentsInChildren<AudioSource>(true);
				foreach (AudioSource val3 in componentsInChildren)
				{
					if ((Object)(object)val3 != (Object)null && (Object)(object)val3.outputAudioMixerGroup != (Object)null)
					{
						val2 = val3.outputAudioMixerGroup;
						break;
					}
				}
				if ((Object)(object)val2 == (Object)null)
				{
					return;
				}
				AudioMixer audioMixer = val2.audioMixer;
				if ((Object)(object)audioMixer != (Object)null)
				{
					AudioMixerGroup[] array = audioMixer.FindMatchingGroups(string.Empty);
					AudioMixerGroup val4 = null;
					int num = 0;
					AudioMixerGroup[] array2 = array;
					foreach (AudioMixerGroup val5 in array2)
					{
						if (!((Object)(object)val5 == (Object)null))
						{
							string text = ((Object)val5).name ?? string.Empty;
							int num2 = ((text.Equals("SFX", StringComparison.OrdinalIgnoreCase) || text.Equals("Sound Effects", StringComparison.OrdinalIgnoreCase)) ? 3 : ((text.IndexOf("sound effect", StringComparison.OrdinalIgnoreCase) >= 0) ? 2 : ((text.IndexOf("sfx", StringComparison.OrdinalIgnoreCase) >= 0) ? 1 : 0)));
							if (num2 > num)
							{
								val4 = val5;
								num = num2;
							}
						}
					}
					if ((Object)(object)val4 != (Object)null)
					{
						val2 = val4;
					}
				}
				_routedSfxGroup = val2;
				_effectSource.outputAudioMixerGroup = val2;
			}
		}

		private static AudioClip LoadEmbeddedPcmWav(string resourceName, string clipName)
		{
			try
			{
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
				if (stream == null)
				{
					throw new InvalidDataException("Embedded resource was not found: " + resourceName);
				}
				using BinaryReader binaryReader = new BinaryReader(stream);
				if (ReadFourCc(binaryReader) != "RIFF")
				{
					throw new InvalidDataException("Missing RIFF header.");
				}
				binaryReader.ReadUInt32();
				if (ReadFourCc(binaryReader) != "WAVE")
				{
					throw new InvalidDataException("Missing WAVE header.");
				}
				ushort num = 0;
				ushort num2 = 0;
				uint num3 = 0u;
				ushort num4 = 0;
				byte[] array = null;
				while (stream.Position + 8 <= stream.Length)
				{
					string text = ReadFourCc(binaryReader);
					uint num5 = binaryReader.ReadUInt32();
					long num6 = stream.Position + num5;
					if (text == "fmt ")
					{
						num = binaryReader.ReadUInt16();
						num2 = binaryReader.ReadUInt16();
						num3 = binaryReader.ReadUInt32();
						binaryReader.ReadUInt32();
						binaryReader.ReadUInt16();
						num4 = binaryReader.ReadUInt16();
					}
					else if (text == "data")
					{
						array = binaryReader.ReadBytes((int)num5);
					}
					stream.Position = num6 + (num5 & 1);
				}
				if (num != 1 || (num4 != 16 && num4 != 32) || num2 == 0 || num3 == 0 || array == null)
				{
					throw new InvalidDataException("Only PCM16 and PCM32 WAV audio is supported.");
				}
				int num7 = num4 / 8;
				float[] array2 = new float[array.Length / num7];
				float num8 = 0f;
				for (int i = 0; i < array2.Length; i++)
				{
					int num9 = i * num7;
					if (num4 == 16)
					{
						array2[i] = (float)(short)(array[num9] | (array[num9 + 1] << 8)) / 32768f;
					}
					else
					{
						int num10 = array[num9] | (array[num9 + 1] << 8) | (array[num9 + 2] << 16) | (array[num9 + 3] << 24);
						array2[i] = (float)num10 / 2.1474836E+09f;
					}
					num8 = Mathf.Max(num8, Mathf.Abs(array2[i]));
				}
				float num11 = ((num8 > 0.0001f) ? Mathf.Min(4f, 0.98f / num8) : 1f);
				for (int j = 0; j < array2.Length; j++)
				{
					array2[j] = Mathf.Clamp(array2[j] * num11, -1f, 1f);
				}
				int num12 = array2.Length / num2;
				AudioClip obj = AudioClip.Create(clipName, num12, (int)num2, (int)num3, false);
				obj.SetData(array2, 0);
				return obj;
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static string ReadFourCc(BinaryReader reader)
		{
			return Encoding.ASCII.GetString(reader.ReadBytes(4));
		}

		private static AudioClip CreateActivationClip()
		{
			Random random = new Random(2077);
			float phase = 0f;
			return CreateClip("Sandevistan Activate", 0.72f, delegate(float t)
			{
				float num = Mathf.Clamp01(t / 0.018f);
				float num2 = Mathf.Clamp01((0.72f - t) / 0.2f);
				float num3 = num * num2;
				float num4 = Mathf.Lerp(85f, 1850f, t * t / 0.5184f);
				phase += (float)Math.PI * 2f * num4 / 44100f;
				float num5 = Mathf.Sin(phase) * 0.42f + Mathf.Sin(phase * 0.503f) * 0.22f;
				float num6 = ((float)random.NextDouble() * 2f - 1f) * (0.19f * (1f - t / 0.72f));
				float num7 = Mathf.Sin((float)Math.PI * 62f * t) * 0.12f;
				return Mathf.Clamp((num5 + num6 + num7) * num3, -1f, 1f);
			});
		}

		private static AudioClip CreateDeactivationClip()
		{
			Random random = new Random(77);
			float phase = 0f;
			return CreateClip("Sandevistan Deactivate", 0.52f, delegate(float t)
			{
				float num = t / 0.52f;
				float num2 = Mathf.Lerp(1250f, 62f, Mathf.Sqrt(num));
				phase += (float)Math.PI * 2f * num2 / 44100f;
				float num3 = Mathf.Clamp01(t / 0.012f) * (1f - num);
				float num4 = ((float)random.NextDouble() * 2f - 1f) * 0.13f;
				return Mathf.Clamp((Mathf.Sin(phase) * 0.48f + Mathf.Sin(phase * 1.99f) * 0.13f + num4) * num3, -1f, 1f);
			});
		}

		private static AudioClip CreateClip(string name, float duration, Func<float, float> sample)
		{
			int num = Mathf.CeilToInt(duration * 44100f);
			float[] array = new float[num];
			for (int i = 0; i < num; i++)
			{
				array[i] = sample((float)i / 44100f);
			}
			AudioClip obj = AudioClip.Create(name, num, 1, 44100, false);
			obj.SetData(array, 0);
			return obj;
		}

		public void Shutdown()
		{
			if (_initialized)
			{
				SceneManager.sceneLoaded -= OnSceneLoaded;
				if ((Object)(object)_activateClip != (Object)null)
				{
					Object.Destroy((Object)(object)_activateClip);
				}
				if ((Object)(object)_deactivateClip != (Object)null)
				{
					Object.Destroy((Object)(object)_deactivateClip);
				}
				_initialized = false;
			}
		}

		public void OnDestroy()
		{
			Shutdown();
		}
	}
	public class SandevistanPlayer : MonoBehaviour
	{
		private SandevistanVisuals _visuals;

		public NewMovement Movement { get; private set; }

		public static SandevistanPlayer Attach(NewMovement movement)
		{
			if ((Object)(object)movement == (Object)null)
			{
				return null;
			}
			SandevistanPlayer sandevistanPlayer = ((Component)movement).GetComponent<SandevistanPlayer>();
			if ((Object)(object)sandevistanPlayer == (Object)null)
			{
				sandevistanPlayer = ((Component)movement).gameObject.AddComponent<SandevistanPlayer>();
			}
			sandevistanPlayer.Bind(movement);
			return sandevistanPlayer;
		}

		public void Bind(NewMovement movement)
		{
			Movement = movement;
			SandevistanVelocity.Bind(movement);
			if ((Object)(object)_visuals == (Object)null)
			{
				_visuals = ((Component)this).gameObject.GetComponent<SandevistanVisuals>() ?? ((Component)this).gameObject.AddComponent<SandevistanVisuals>();
			}
		}

		public void Awake()
		{
			Movement = ((Component)this).GetComponent<NewMovement>();
		}

		public void Start()
		{
			Bind(((Object)(object)Movement != (Object)null) ? Movement : ((Component)this).GetComponent<NewMovement>());
		}

		public void Update()
		{
			if ((Object)(object)Movement != (Object)null && Movement.dead && SandevistanClock.Active)
			{
				SandevistanClock.SetActive(active: false, "player death");
			}
		}

		public void OnDestroy()
		{
			SandevistanVelocity.Unbind(Movement);
		}
	}
	[DefaultExecutionOrder(10000)]
	public class SandevistanVisuals : MonoBehaviour
	{
		private sealed class Ghost
		{
			public GameObject Object;

			public Material Material;

			public Material[] Materials;

			public Renderer[] Renderers;

			public Mesh OwnedMesh;

			public Color Color;

			public bool IsBody;

			public Vector3 BasePosition;

			public Quaternion BaseRotation;
		}

		private const int GhostLayer = 31;

		private static readonly Color ActiveWorldMultiply = new Color(0.48f, 1f, 0.78f, 1f);

		private static readonly Color ActiveWorldAdd = new Color(0.01f, 0.06f, 0.025f, 0f);

		private static readonly FieldInfo PlayerWeaponsField = AccessTools.Field(typeof(PlayerAnimations), "weapons");

		private static readonly FieldInfo PlayerAltWeaponsField = AccessTools.Field(typeof(PlayerAnimations), "altweapons");

		private static readonly FieldInfo GunControlAllWeaponsField = AccessTools.Field(typeof(GunControl), "allWeapons");

		private static readonly FieldInfo GunControlCurrentWeaponField = AccessTools.Field(typeof(GunControl), "currentWeapon");

		private const float GhostHueStep = 1f / 72f;

		private readonly List<Ghost> _ghosts = new List<Ghost>();

		private readonly HashSet<SandevistanPlayerAnimator> _animato