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;
}
}
}
}