Decompiled source of FirstPersonGB v1.2.3

Mods/FirstPersonGB.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using FirstPersonGB;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Reflection;
using MelonLoader;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(FirstPersonGBMod), "FirstPersonGB", "1.2.1", "KMK And Zooks", null)]
[assembly: MelonGame("Boneloaf", "Gang Beasts")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("FirstPersonGB")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("First Person for GB")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("FirstPersonGB")]
[assembly: AssemblyTitle("FirstPersonGB")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 FirstPersonGB
{
	public class FirstPersonGBMod : MelonMod
	{
		private bool isFirstPerson;

		private bool wantsFirstPerson;

		private string currentSceneName = "";

		private float sceneLoadTimer;

		private float audioScanTimer;

		private float retrySearchTimer;

		private Transform playerHead;

		private Camera mainCamera;

		private Transform mainCamTransform;

		private float originalFOV;

		private float originalNearClip;

		private float pitch;

		private float yaw;

		private readonly float mouseSensitivity = 0.16f;

		private readonly float controllerSensitivity = 145f;

		private readonly float positionSmoothSpeed = 48f;

		private bool justToggled;

		private Dictionary<Renderer, bool> hiddenRenderers = new Dictionary<Renderer, bool>();

		private Dictionary<SkinnedMeshRenderer, bool> originalUpdateOffscreen = new Dictionary<SkinnedMeshRenderer, bool>();

		private Dictionary<SkinnedMeshRenderer, Bounds> originalMeshBounds = new Dictionary<SkinnedMeshRenderer, Bounds>();

		private List<MonoBehaviour> disabledScripts = new List<MonoBehaviour>();

		private static readonly string[] headKeywords = new string[40]
		{
			"actor_head_collider", "actor_head_skinnedMesh", "helper_voiceBox", "head", "skull", "face", "eye", "eyeball", "pupil", "iris",
			"eyelid", "eyebrow", "brow", "mouth", "lip", "teeth", "tooth", "tongue", "jaw", "chin",
			"nose", "ear", "hair", "wig", "hat", "cap", "helmet", "helm", "hardhat", "hood",
			"beanie", "mask", "visor", "glasses", "goggles", "beard", "mustache", "stache", "collar", "neck"
		};

		public override void OnInitializeMelon()
		{
			MelonLogger.Msg("FirstPersonGB v1.2.1 P Loaded (Optimized).");
			MelonLogger.Msg("Toggle Key: K (Keyboard) or Right-Stick-Click (Controller).");
		}

		public override void OnUpdate()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Scene activeScene = SceneManager.GetActiveScene();
				string name = ((Scene)(ref activeScene)).name;
				if (currentSceneName != name)
				{
					MelonLogger.Msg($"[Scene Management] Loading Scene Change: '{currentSceneName}' -> '{name}'");
					currentSceneName = name;
					if (isFirstPerson)
					{
						ForceDisableFirstPerson();
					}
					if (wantsFirstPerson)
					{
						sceneLoadTimer = 1.5f;
					}
				}
				if (sceneLoadTimer > 0f)
				{
					sceneLoadTimer -= Time.deltaTime;
					if (sceneLoadTimer <= 0f && wantsFirstPerson)
					{
						TryEnableFirstPerson();
					}
				}
				if (wantsFirstPerson && !isFirstPerson && sceneLoadTimer <= 0f)
				{
					retrySearchTimer += Time.deltaTime;
					if (retrySearchTimer >= 0.25f)
					{
						retrySearchTimer = 0f;
						TryEnableFirstPerson();
					}
				}
				audioScanTimer += Time.deltaTime;
				if (audioScanTimer >= 1.5f)
				{
					audioScanTimer = 0f;
					ScanAndBoostWarpAudio();
				}
				bool flag = false;
				if (Keyboard.current != null && ((ButtonControl)Keyboard.current.kKey).wasPressedThisFrame)
				{
					flag = true;
				}
				if (Gamepad.current != null && Gamepad.current.rightStickButton.wasPressedThisFrame)
				{
					flag = true;
				}
				if (flag)
				{
					if (!isFirstPerson)
					{
						wantsFirstPerson = true;
						TryEnableFirstPerson();
					}
					else
					{
						wantsFirstPerson = false;
						ForceDisableFirstPerson();
					}
				}
				if (isFirstPerson && ((Object)(object)playerHead == (Object)null || !((Component)playerHead).gameObject.activeInHierarchy))
				{
					MelonLogger.Warning("[FP Safety] Target Lost. Reverting to Third Person.");
					ForceDisableFirstPerson();
					if (wantsFirstPerson)
					{
						retrySearchTimer = 0f;
					}
				}
			}
			catch (Exception value)
			{
				MelonLogger.Error($"[OnUpdate Error] Exception: {value}");
			}
		}

		public override void OnFixedUpdate()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (isFirstPerson && (Object)(object)mainCamTransform != (Object)null)
			{
				mainCamTransform.rotation = Quaternion.Euler(pitch, yaw, 0f);
			}
		}

		public override void OnLateUpdate()
		{
			if (isFirstPerson)
			{
				UpdateVisualCamera();
			}
		}

		private void ScanAndBoostWarpAudio()
		{
			try
			{
				AudioSource[] array = Il2CppArrayBase<AudioSource>.op_Implicit(Object.FindObjectsOfType<AudioSource>());
				int num = array.Length;
				for (int i = 0; i < num; i++)
				{
					AudioSource val = array[i];
					if (!((Object)(object)val == (Object)null) && !((Object)(object)val.clip == (Object)null) && ((Object)val.clip).name.IndexOf("Warp 1", StringComparison.OrdinalIgnoreCase) >= 0 && val.volume < 1f)
					{
						val.volume = 1f;
						MelonLogger.Msg($"[Audio Match] Boosted '{((Object)val.clip).name}' on [{((Object)((Component)val).gameObject).name}] to 100% volume.");
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[Audio Error] Scan registry failure: " + ex.Message);
			}
		}

		private void TryEnableFirstPerson()
		{
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				mainCamera = Camera.main;
				if ((Object)(object)mainCamera == (Object)null)
				{
					MelonLogger.Error("[FP Mode] Main Camera is null!");
					return;
				}
				mainCamTransform = ((Component)mainCamera).transform;
				SmartFindLocalPlayer();
				if (!((Object)(object)playerHead == (Object)null))
				{
					MelonLogger.Msg("[FP Mode] Found local actor head '" + ((Object)playerHead).name + "'. Mounting camera...");
					originalFOV = mainCamera.fieldOfView;
					originalNearClip = mainCamera.nearClipPlane;
					mainCamera.fieldOfView = 125f;
					mainCamera.nearClipPlane = 0.01f;
					disabledScripts.Clear();
					Transform parent = mainCamTransform;
					while ((Object)(object)parent != (Object)null)
					{
						DisableTrackingScripts(((Component)parent).gameObject);
						parent = parent.parent;
					}
					Quaternion rotation = playerHead.rotation;
					Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles;
					yaw = eulerAngles.y;
					pitch = eulerAngles.x;
					Cursor.lockState = (CursorLockMode)1;
					Cursor.visible = false;
					ApplyHighlyOptimizedRendering();
					isFirstPerson = true;
					justToggled = true;
					MelonLogger.Msg("[FP Mode] Mounted successfully.");
				}
			}
			catch (Exception value)
			{
				MelonLogger.Error($"[FP Mode Error] Activation failure: {value}");
			}
		}

		private void ForceDisableFirstPerson()
		{
			try
			{
				isFirstPerson = false;
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
				RestoreVisibility();
				if ((Object)(object)mainCamera != (Object)null)
				{
					mainCamera.fieldOfView = originalFOV;
					mainCamera.nearClipPlane = originalNearClip;
					int count = disabledScripts.Count;
					for (int i = 0; i < count; i++)
					{
						if ((Object)(object)disabledScripts[i] != (Object)null)
						{
							((Behaviour)disabledScripts[i]).enabled = true;
						}
					}
				}
				disabledScripts.Clear();
				playerHead = null;
				mainCamTransform = null;
				MelonLogger.Msg("[FP Mode] Restored system back to Third Person.");
			}
			catch (Exception value)
			{
				MelonLogger.Error($"[FP Mode Error] Restoration failure: {value}");
			}
		}

		private void DisableTrackingScripts(GameObject obj)
		{
			MonoBehaviour[] array = Il2CppArrayBase<MonoBehaviour>.op_Implicit(obj.GetComponents<MonoBehaviour>());
			int num = array.Length;
			for (int i = 0; i < num; i++)
			{
				MonoBehaviour val = array[i];
				if (!((Object)(object)val == (Object)null))
				{
					string text = ((MemberInfo)((Object)val).GetIl2CppType()).Name.ToLower();
					if (!text.Contains("postprocess") && !text.Contains("volume") && !text.Contains("amplify") && !text.Contains("layer") && !text.Contains("audio") && ((Behaviour)val).enabled)
					{
						((Behaviour)val).enabled = false;
						disabledScripts.Add(val);
						MelonLogger.Msg($"[FP Camera] Disabled camera scripts: {((Object)val).GetIl2CppType().FullName} on [{((Object)obj).name}]");
					}
				}
			}
		}

		private void SmartFindLocalPlayer()
		{
			playerHead = null;
			try
			{
				Component[] array = Il2CppArrayBase<Component>.op_Implicit(Object.FindObjectsOfType<Component>());
				Component val = null;
				int num = array.Length;
				for (int i = 0; i < num; i++)
				{
					Component val2 = array[i];
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					string name = ((MemberInfo)((Object)val2).GetIl2CppType()).Name;
					if (!(name == "Actor") && !(name == "ActorCore") && !name.EndsWith(".Actor"))
					{
						continue;
					}
					Type type = ((object)val2).GetType();
					PropertyInfo propertyInfo = type.GetProperty("IsAI") ?? type.GetProperty("isAI");
					if (propertyInfo != null)
					{
						try
						{
							if ((bool)propertyInfo.GetValue(val2, null))
							{
								continue;
							}
						}
						catch
						{
						}
					}
					PropertyInfo propertyInfo2 = type.GetProperty("isLocalPlayer") ?? type.GetProperty("IsLocal") ?? type.GetProperty("IsLocalPlayer");
					if (!(propertyInfo2 != null))
					{
						continue;
					}
					try
					{
						if ((bool)propertyInfo2.GetValue(val2, null))
						{
							val = val2;
							break;
						}
					}
					catch
					{
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					Rigidbody[] array2 = Il2CppArrayBase<Rigidbody>.op_Implicit(((Component)val.transform.root).GetComponentsInChildren<Rigidbody>(true));
					int num2 = array2.Length;
					for (int j = 0; j < num2; j++)
					{
						Rigidbody val3 = array2[j];
						if ((Object)(object)val3 != (Object)null && ((Object)((Component)val3).gameObject).name.Equals("actor_head_collider", StringComparison.OrdinalIgnoreCase))
						{
							playerHead = ((Component)val3).transform;
							return;
						}
					}
				}
				Rigidbody[] array3 = Il2CppArrayBase<Rigidbody>.op_Implicit(Object.FindObjectsOfType<Rigidbody>());
				int num3 = array3.Length;
				for (int k = 0; k < num3; k++)
				{
					Rigidbody val4 = array3[k];
					if (!((Object)(object)val4 == (Object)null) && ((Object)((Component)val4).gameObject).name.Equals("actor_head_collider", StringComparison.OrdinalIgnoreCase))
					{
						Transform root = ((Component)val4).transform.root;
						if (((Object)root).name.IndexOf("[PlayerID: 0]", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)root).name.IndexOf("PlayerID: 0", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							playerHead = ((Component)val4).transform;
							break;
						}
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[SmartFind Error] Local Player discovery failed: " + ex.Message);
			}
		}

		private void ApplyHighlyOptimizedRendering()
		{
			//IL_00a2: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			hiddenRenderers.Clear();
			originalUpdateOffscreen.Clear();
			originalMeshBounds.Clear();
			if ((Object)(object)playerHead == (Object)null)
			{
				return;
			}
			Renderer[] array = Il2CppArrayBase<Renderer>.op_Implicit(((Component)playerHead.root).GetComponentsInChildren<Renderer>(true));
			int num = array.Length;
			for (int i = 0; i < num; i++)
			{
				Renderer val = array[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				bool flag = false;
				string name = ((Object)((Component)val).gameObject).name;
				SkinnedMeshRenderer val2 = ((Il2CppObjectBase)val).TryCast<SkinnedMeshRenderer>();
				if ((Object)(object)val2 != (Object)null)
				{
					originalUpdateOffscreen[val2] = val2.updateWhenOffscreen;
					originalMeshBounds[val2] = ((Renderer)val2).localBounds;
					val2.updateWhenOffscreen = true;
					((Renderer)val2).localBounds = new Bounds(Vector3.zero, Vector3.one * 50f);
				}
				if (IsHeadRelated(name))
				{
					flag = true;
				}
				if (!flag)
				{
					Transform parent = ((Component)val).transform.parent;
					while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)playerHead.root)
					{
						if (IsHeadRelated(((Object)parent).name))
						{
							flag = true;
							break;
						}
						parent = parent.parent;
					}
				}
				if (!flag && (Object)(object)val2 != (Object)null && (Object)(object)val2.sharedMesh != (Object)null && IsHeadRelated(((Object)val2.sharedMesh).name))
				{
					flag = true;
				}
				if (flag)
				{
					hiddenRenderers[val] = val.enabled;
					val.enabled = false;
					MelonLogger.Msg("[Renderer Manager] Completely Hid Head Component: [" + name + "]");
				}
			}
		}

		private bool IsHeadRelated(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			int num = headKeywords.Length;
			for (int i = 0; i < num; i++)
			{
				if (name.IndexOf(headKeywords[i], StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private void RestoreVisibility()
		{
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				foreach (KeyValuePair<Renderer, bool> hiddenRenderer in hiddenRenderers)
				{
					if ((Object)(object)hiddenRenderer.Key != (Object)null)
					{
						hiddenRenderer.Key.enabled = hiddenRenderer.Value;
					}
				}
				hiddenRenderers.Clear();
				foreach (KeyValuePair<SkinnedMeshRenderer, bool> item in originalUpdateOffscreen)
				{
					if ((Object)(object)item.Key != (Object)null)
					{
						item.Key.updateWhenOffscreen = item.Value;
					}
				}
				originalUpdateOffscreen.Clear();
				foreach (KeyValuePair<SkinnedMeshRenderer, Bounds> originalMeshBound in originalMeshBounds)
				{
					if ((Object)(object)originalMeshBound.Key != (Object)null)
					{
						((Renderer)originalMeshBound.Key).localBounds = originalMeshBound.Value;
					}
				}
				originalMeshBounds.Clear();
				MelonLogger.Msg("[FP Mode] Meshes and visibility states completely restored.");
			}
			catch (Exception value)
			{
				MelonLogger.Error($"[Restoration Error] Reverting pipeline states failed: {value}");
			}
		}

		private void UpdateVisualCamera()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			if (!isFirstPerson || (Object)(object)mainCamTransform == (Object)null || (Object)(object)playerHead == (Object)null)
			{
				return;
			}
			Vector3 val = playerHead.up * 0.48f + playerHead.forward * 0.07f;
			Vector3 val2 = playerHead.position + val;
			if (Mouse.current != null)
			{
				Vector2 val3 = ((InputControl<Vector2>)(object)((Pointer)Mouse.current).delta).ReadValue();
				yaw += val3.x * mouseSensitivity;
				pitch -= val3.y * mouseSensitivity;
			}
			if (Gamepad.current != null)
			{
				Vector2 val4 = ((InputControl<Vector2>)(object)Gamepad.current.rightStick).ReadValue();
				if (((Vector2)(ref val4)).sqrMagnitude > 0.005f)
				{
					yaw += val4.x * controllerSensitivity * Time.deltaTime;
					pitch -= val4.y * controllerSensitivity * Time.deltaTime;
				}
			}
			pitch = Mathf.Clamp(pitch, -85f, 85f);
			Quaternion rotation = Quaternion.Euler(pitch, yaw, 0f);
			if (pitch > 0f)
			{
				float num = Mathf.InverseLerp(0f, 85f, pitch);
				val2 += mainCamTransform.forward * (num * 0.18f);
			}
			if (justToggled)
			{
				mainCamTransform.position = val2;
				mainCamTransform.rotation = rotation;
				justToggled = false;
			}
			else
			{
				mainCamTransform.position = Vector3.Lerp(mainCamTransform.position, val2, Time.deltaTime * positionSmoothSpeed);
				mainCamTransform.rotation = rotation;
			}
		}
	}
}