Decompiled source of HitContinue v1.0.2

BepInEx/plugins/Hitcontinue.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("Hitcontinue")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Hitcontinue")]
[assembly: AssemblyTitle("Hitcontinue")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 Hitcontinue
{
	[BepInPlugin("com.clippton.hitcontinue", "Hitcontinue", "1.0.0")]
	public sealed class HitcontinuePlugin : BaseUnityPlugin
	{
		private struct RigidbodyState
		{
			private readonly Rigidbody rb;

			private readonly bool isKinematic;

			private readonly Vector3 velocity;

			private readonly Vector3 angularVelocity;

			public RigidbodyState(Rigidbody rb)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				this.rb = rb;
				isKinematic = rb.isKinematic;
				velocity = rb.velocity;
				angularVelocity = rb.angularVelocity;
			}

			public void Restore()
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)rb == (Object)null))
				{
					rb.isKinematic = isKinematic;
					rb.velocity = velocity;
					rb.angularVelocity = angularVelocity;
				}
			}
		}

		private struct AnimatorState
		{
			private readonly Animator animator;

			private readonly float speed;

			public AnimatorState(Animator animator)
			{
				this.animator = animator;
				speed = animator.speed;
			}

			public void Restore()
			{
				if ((Object)(object)animator != (Object)null)
				{
					animator.speed = speed;
				}
			}
		}

		private struct AgentState
		{
			private readonly NavMeshAgent agent;

			private readonly bool isStopped;

			private readonly Vector3 velocity;

			public AgentState(NavMeshAgent agent)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				this.agent = agent;
				isStopped = agent.isStopped;
				velocity = agent.velocity;
			}

			public void Restore()
			{
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)agent == (Object)null) && agent.isOnNavMesh)
				{
					agent.isStopped = isStopped;
					agent.velocity = velocity;
				}
			}
		}

		[CompilerGenerated]
		private sealed class <CacheWhenPlayerExistsRoutine>d__28 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public HitcontinuePlugin <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <CacheWhenPlayerExistsRoutine>d__28(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Expected O, but got Unknown
				int num = <>1__state;
				HitcontinuePlugin hitcontinuePlugin = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (!hitcontinuePlugin.cacheBuilt)
				{
					hitcontinuePlugin.FindPlayerRoots();
					if (hitcontinuePlugin.playerRoots.Count > 0)
					{
						hitcontinuePlugin.BuildObjectCache();
						hitcontinuePlugin.cacheBuilt = true;
						hitcontinuePlugin.cacheRoutine = null;
						return false;
					}
					<>2__current = (object)new WaitForSecondsRealtime(1f);
					<>1__state = 1;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <StopRoutine>d__33 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public float length;

			public object timeController;

			public bool trueStop;

			public HitcontinuePlugin <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <StopRoutine>d__33(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Expected O, but got Unknown
				int num = <>1__state;
				HitcontinuePlugin hitcontinuePlugin = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSecondsRealtime(length);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					float num2 = (float)currentStopField.GetValue(timeController);
					if (length < num2)
					{
						return false;
					}
					hitstopActive = false;
					Time.timeScale = GetNormalTimeScale(timeController);
					if (trueStop)
					{
						CallSetAllPitch(timeController, 1f);
					}
					currentStopField.SetValue(timeController, 0f);
					hitcontinuePlugin.RestoreObjects();
					return false;
				}
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private const string Guid = "com.clippton.hitcontinue";

		private static HitcontinuePlugin instance;

		private static readonly Harmony harmony = new Harmony("com.clippton.hitcontinue");

		private static ConfigEntry<bool> timeControllerPatchEnabled;

		private static ConfigEntry<bool> shotgunHammerPatchEnabled;

		private static FieldInfo currentStopField;

		private static bool hitstopActive;

		private readonly List<Transform> playerRoots = new List<Transform>();

		private readonly List<Rigidbody> cachedRigidbodies = new List<Rigidbody>();

		private readonly List<Animator> cachedAnimators = new List<Animator>();

		private readonly List<NavMeshAgent> cachedAgents = new List<NavMeshAgent>();

		private readonly List<RigidbodyState> frozenRigidbodies = new List<RigidbodyState>();

		private readonly List<AnimatorState> frozenAnimators = new List<AnimatorState>();

		private readonly List<AgentState> frozenAgents = new List<AgentState>();

		private Coroutine cacheRoutine;

		private bool cacheBuilt;

		private bool frozen;

		private void Awake()
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			instance = this;
			timeControllerPatchEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Hitstop", "TimeControllerPatch", true, "Convert regular TimeController HitStop/TrueStop calls into selective hitstop.");
			shotgunHammerPatchEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Hitstop", "ShotgunHammerPatch", true, "Convert ShotgunHammer TrueStop calls into selective hitstop, even if the general TimeController patch is disabled.");
			Type type = AccessTools.TypeByName("TimeController");
			if (type == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Could not find TimeController.");
				return;
			}
			currentStopField = AccessTools.Field(type, "currentStop");
			if (currentStopField == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Could not find TimeController.currentStop.");
				return;
			}
			harmony.Patch((MethodBase)AccessTools.Method(type, "HitStop", (Type[])null, (Type[])null), new HarmonyMethod(typeof(HitcontinuePlugin), "HitStopPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(type, "TrueStop", (Type[])null, (Type[])null), new HarmonyMethod(typeof(HitcontinuePlugin), "TrueStopPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			PatchGameUpdateMethods();
			SceneManager.sceneLoaded += OnSceneLoaded;
			StartCacheScan();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Hitcontinue loaded.");
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			harmony.UnpatchSelf();
			RestoreObjects();
			StopCacheScan();
			hitstopActive = false;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			RestoreObjects();
			ClearCache();
			cacheBuilt = false;
			hitstopActive = false;
			StartCacheScan();
		}

		private void PatchGameUpdateMethods()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			HarmonyMethod prefix = new HarmonyMethod(typeof(HitcontinuePlugin), "UpdateFreezePrefix", (Type[])null);
			HarmonyMethod prefix2 = new HarmonyMethod(typeof(HitcontinuePlugin), "CoroutineFreezePrefix", (Type[])null);
			int num = 0;
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				if (assembly.GetName().Name != "Assembly-CSharp")
				{
					continue;
				}
				Type[] types;
				try
				{
					types = assembly.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					types = ex.Types;
				}
				Type[] array = types;
				foreach (Type type in array)
				{
					if (type == null)
					{
						continue;
					}
					if (typeof(MonoBehaviour).IsAssignableFrom(type))
					{
						if (typeof(BaseUnityPlugin).IsAssignableFrom(type))
						{
							continue;
						}
						num += PatchUpdateMethod(type, "Update", prefix);
						num += PatchUpdateMethod(type, "FixedUpdate", prefix);
						num += PatchUpdateMethod(type, "LateUpdate", prefix);
					}
					num += PatchCoroutineMethods(type, prefix2);
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Hitcontinue patched " + num + " update/coroutine methods."));
		}

		private int PatchUpdateMethod(Type type, string methodName, HarmonyMethod prefix)
		{
			MethodInfo methodInfo = AccessTools.DeclaredMethod(type, methodName, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				return 0;
			}
			if (methodInfo.IsStatic || methodInfo.GetParameters().Length != 0 || methodInfo.ReturnType != typeof(void))
			{
				return 0;
			}
			try
			{
				harmony.Patch((MethodBase)methodInfo, prefix, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				return 1;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not patch " + type.FullName + "." + methodName + ": " + ex.Message));
				return 0;
			}
		}

		private int PatchCoroutineMethods(Type type, HarmonyMethod prefix)
		{
			if (type == null || !typeof(IEnumerator).IsAssignableFrom(type))
			{
				return 0;
			}
			MethodInfo methodInfo = AccessTools.DeclaredMethod(type, "MoveNext", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo.ReturnType != typeof(bool))
			{
				return 0;
			}
			try
			{
				harmony.Patch((MethodBase)methodInfo, prefix, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				return 1;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not patch coroutine " + type.FullName + ".MoveNext: " + ex.Message));
				return 0;
			}
		}

		private static bool UpdateFreezePrefix(MonoBehaviour __instance)
		{
			if (!hitstopActive || (Object)(object)instance == (Object)null || (Object)(object)__instance == (Object)null)
			{
				return true;
			}
			return !instance.ShouldFreeze(((Component)__instance).gameObject);
		}

		private static bool CoroutineFreezePrefix(object __instance)
		{
			if (!hitstopActive || (Object)(object)instance == (Object)null || __instance == null)
			{
				return true;
			}
			if (!TryGetCoroutineOwner(__instance, out var owner))
			{
				return true;
			}
			if ((Object)(object)owner == (Object)null)
			{
				return true;
			}
			return !instance.ShouldFreeze(((Component)owner).gameObject);
		}

		private static bool TryGetCoroutineOwner(object coroutine, out MonoBehaviour owner)
		{
			owner = null;
			FieldInfo[] fields = coroutine.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (typeof(MonoBehaviour).IsAssignableFrom(fieldInfo.FieldType))
				{
					object? value = fieldInfo.GetValue(coroutine);
					owner = (MonoBehaviour)((value is MonoBehaviour) ? value : null);
					if ((Object)(object)owner != (Object)null)
					{
						return true;
					}
				}
			}
			return false;
		}

		private void StartCacheScan()
		{
			StopCacheScan();
			cacheRoutine = ((MonoBehaviour)this).StartCoroutine(CacheWhenPlayerExistsRoutine());
		}

		private void StopCacheScan()
		{
			if (cacheRoutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(cacheRoutine);
				cacheRoutine = null;
			}
		}

		[IteratorStateMachine(typeof(<CacheWhenPlayerExistsRoutine>d__28))]
		private IEnumerator CacheWhenPlayerExistsRoutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CacheWhenPlayerExistsRoutine>d__28(0)
			{
				<>4__this = this
			};
		}

		private static bool HitStopPrefix(object __instance, float length)
		{
			if ((Object)(object)instance == (Object)null || !timeControllerPatchEnabled.Value)
			{
				return true;
			}
			instance.DoStop(__instance, length, trueStop: false);
			return false;
		}

		private static bool TrueStopPrefix(object __instance, float length)
		{
			if ((Object)(object)instance == (Object)null)
			{
				return true;
			}
			if (!timeControllerPatchEnabled.Value && (!shotgunHammerPatchEnabled.Value || !IsShotgunHammerTrueStopCall()))
			{
				return true;
			}
			instance.DoStop(__instance, length, trueStop: true);
			return false;
		}

		private static bool IsShotgunHammerTrueStopCall()
		{
			StackTrace stackTrace = new StackTrace();
			for (int i = 0; i < stackTrace.FrameCount; i++)
			{
				MethodBase method = stackTrace.GetFrame(i).GetMethod();
				if (!(method == null) && !(method.DeclaringType == null))
				{
					Type declaringType = method.DeclaringType;
					if (declaringType.Name == "ShotgunHammer")
					{
						return true;
					}
					if (declaringType.FullName != null && declaringType.FullName.Contains("ShotgunHammer"))
					{
						return true;
					}
				}
			}
			return false;
		}

		private void DoStop(object timeController, float length, bool trueStop)
		{
			float num = (float)currentStopField.GetValue(timeController);
			if (length <= num)
			{
				return;
			}
			currentStopField.SetValue(timeController, length);
			if (!cacheBuilt)
			{
				FindPlayerRoots();
				if (playerRoots.Count <= 0)
				{
					Time.timeScale = GetNormalTimeScale(timeController);
					return;
				}
				BuildObjectCache();
				cacheBuilt = true;
			}
			if (!frozen)
			{
				FreezeObjects();
			}
			hitstopActive = true;
			Time.timeScale = GetNormalTimeScale(timeController);
			if (trueStop)
			{
				CallSetAllPitch(timeController, 0f);
			}
			((MonoBehaviour)this).StartCoroutine(StopRoutine(timeController, length, trueStop));
		}

		[IteratorStateMachine(typeof(<StopRoutine>d__33))]
		private IEnumerator StopRoutine(object timeController, float length, bool trueStop)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <StopRoutine>d__33(0)
			{
				<>4__this = this,
				timeController = timeController,
				length = length,
				trueStop = trueStop
			};
		}

		private void FindPlayerRoots()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			playerRoots.Clear();
			GameObject[] array = GameObject.FindGameObjectsWithTag("Player");
			foreach (GameObject val in array)
			{
				if (!((Object)(object)val != (Object)null))
				{
					continue;
				}
				Scene scene = val.scene;
				if (((Scene)(ref scene)).IsValid())
				{
					scene = val.scene;
					if (((Scene)(ref scene)).isLoaded)
					{
						playerRoots.Add(val.transform);
					}
				}
			}
		}

		private void BuildObjectCache()
		{
			cachedRigidbodies.Clear();
			cachedAnimators.Clear();
			cachedAgents.Clear();
			Rigidbody[] array = Object.FindObjectsOfType<Rigidbody>();
			foreach (Rigidbody val in array)
			{
				if ((Object)(object)val != (Object)null && ShouldFreeze(((Component)val).gameObject))
				{
					cachedRigidbodies.Add(val);
				}
			}
			Animator[] array2 = Object.FindObjectsOfType<Animator>();
			foreach (Animator val2 in array2)
			{
				if ((Object)(object)val2 != (Object)null && ShouldFreeze(((Component)val2).gameObject))
				{
					cachedAnimators.Add(val2);
				}
			}
			NavMeshAgent[] array3 = Object.FindObjectsOfType<NavMeshAgent>();
			foreach (NavMeshAgent val3 in array3)
			{
				if ((Object)(object)val3 != (Object)null && ShouldFreeze(((Component)val3).gameObject))
				{
					cachedAgents.Add(val3);
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Hitcontinue cache built: " + playerRoots.Count + " player roots, " + cachedRigidbodies.Count + " rigidbodies, " + cachedAnimators.Count + " animators, " + cachedAgents.Count + " nav agents."));
		}

		private void ClearCache()
		{
			playerRoots.Clear();
			cachedRigidbodies.Clear();
			cachedAnimators.Clear();
			cachedAgents.Clear();
		}

		private void FreezeObjects()
		{
			//IL_0038: 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_0108: Unknown result type (might be due to invalid IL or missing references)
			frozen = true;
			foreach (Rigidbody cachedRigidbody in cachedRigidbodies)
			{
				if (!((Object)(object)cachedRigidbody == (Object)null))
				{
					frozenRigidbodies.Add(new RigidbodyState(cachedRigidbody));
					cachedRigidbody.velocity = Vector3.zero;
					cachedRigidbody.angularVelocity = Vector3.zero;
					cachedRigidbody.isKinematic = true;
				}
			}
			foreach (Animator cachedAnimator in cachedAnimators)
			{
				if (!((Object)(object)cachedAnimator == (Object)null))
				{
					frozenAnimators.Add(new AnimatorState(cachedAnimator));
					cachedAnimator.speed = 0f;
				}
			}
			foreach (NavMeshAgent cachedAgent in cachedAgents)
			{
				if (!((Object)(object)cachedAgent == (Object)null))
				{
					frozenAgents.Add(new AgentState(cachedAgent));
					if (cachedAgent.isOnNavMesh)
					{
						cachedAgent.isStopped = true;
						cachedAgent.velocity = Vector3.zero;
					}
				}
			}
		}

		private void RestoreObjects()
		{
			foreach (RigidbodyState frozenRigidbody in frozenRigidbodies)
			{
				frozenRigidbody.Restore();
			}
			foreach (AnimatorState frozenAnimator in frozenAnimators)
			{
				frozenAnimator.Restore();
			}
			foreach (AgentState frozenAgent in frozenAgents)
			{
				frozenAgent.Restore();
			}
			frozenRigidbodies.Clear();
			frozenAnimators.Clear();
			frozenAgents.Clear();
			frozen = false;
		}

		private bool ShouldFreeze(GameObject obj)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)obj != (Object)null)
			{
				Scene scene = obj.scene;
				if (((Scene)(ref scene)).IsValid())
				{
					scene = obj.scene;
					if (((Scene)(ref scene)).isLoaded)
					{
						return !IsPlayerOrChild(obj);
					}
				}
			}
			return false;
		}

		private bool IsPlayerOrChild(GameObject obj)
		{
			Transform val = obj.transform;
			while ((Object)(object)val != (Object)null)
			{
				foreach (Transform playerRoot in playerRoots)
				{
					if ((Object)(object)playerRoot != (Object)null && (Object)(object)val == (Object)(object)playerRoot)
					{
						return true;
					}
				}
				val = val.parent;
			}
			return false;
		}

		private static float GetNormalTimeScale(object timeController)
		{
			float num = (float)AccessTools.Field(timeController.GetType(), "timeScale").GetValue(timeController);
			float num2 = (float)AccessTools.Field(timeController.GetType(), "timeScaleModifier").GetValue(timeController);
			return num * num2;
		}

		private static void CallSetAllPitch(object timeController, float pitch)
		{
			MethodInfo methodInfo = AccessTools.Method(timeController.GetType(), "SetAllPitch", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				methodInfo.Invoke(timeController, new object[1] { pitch });
			}
		}
	}
}