using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Unity.Netcode;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("fov")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("fov")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("7ac834db-85a7-474e-b917-0007ede04ca2")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace LC_Fov;
[BepInPlugin("DSL.LC_Fov", "LC Fov", "1.0.0")]
public class LCFovBase : BaseUnityPlugin
{
public const string ModGuid = "DSL.LC_Fov";
public const string ModName = "LC Fov";
public const string ModVer = "1.0.0";
private readonly Harmony _harmony = new Harmony("DSL.LC_Fov");
private static LCFovBase _instance;
public static ManualLogSource Log;
public static ConfigEntry<float> CfgFov;
public static ConfigEntry<float> CfgSprintFov;
public static ConfigEntry<bool> CfgHideVisor;
private void Awake()
{
if ((Object)(object)_instance == (Object)null)
{
_instance = this;
}
Log = ((BaseUnityPlugin)this).Logger;
Log.LogInfo((object)"Starting LC FOV…");
CfgFov = ((BaseUnityPlugin)this).Config.Bind<float>("General", "fov", 90f, "Vertical FOV. Clamped 66–130.");
CfgSprintFov = ((BaseUnityPlugin)this).Config.Bind<float>("General", "sprintFov", 1.25f, "Sprint FOV multiplier. Clamped 1.0–1.5.");
CfgHideVisor = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "hideVisor", true, "If true, hides the first-person visor.");
PlayerControllerBPatches.newTargetFovBase = Mathf.Clamp(CfgFov.Value, 66f, 130f);
PlayerControllerBPatches.sprintFovMultiplier = Mathf.Clamp(CfgSprintFov.Value, 1f, 1.5f);
PlayerControllerBPatches.hideVisor = CfgHideVisor.Value;
PlayerControllerBPatches.RecalculateVisorScale();
_harmony.PatchAll(typeof(PlayerControllerBPatches));
_harmony.PatchAll(typeof(HUDManagerPatches));
Log.LogInfo((object)"LC FOV loaded.");
}
public static void SetHideVisor(bool value)
{
PlayerControllerBPatches.hideVisor = value;
_instance.ConfigHideVisorAndSave(value);
PlayerControllerBPatches.RecalculateVisorScale();
}
public static void SetFov(float v)
{
float value = (PlayerControllerBPatches.newTargetFovBase = Mathf.Clamp(v, 66f, 130f));
_instance.ConfigSetFovAndSave(value);
PlayerControllerBPatches.snapFovChange = true;
PlayerControllerBPatches.RecalculateVisorScale();
}
private void ConfigHideVisorAndSave(bool value)
{
CfgHideVisor.Value = value;
((BaseUnityPlugin)this).Config.Save();
}
private void ConfigSetFovAndSave(float value)
{
CfgFov.Value = value;
((BaseUnityPlugin)this).Config.Save();
}
}
public static class PlayerControllerBPatches
{
public static float newTargetFovBase = 90f;
public static float sprintFovMultiplier = 1.25f;
public static bool snapFovChange = false;
public static bool hideVisor = true;
private static Vector3 visorScale;
private static float lastAppliedFovForScale = -999f;
private static readonly Vector3 VisorScaleBottom = new Vector3(0.68f, 0.8f, 0.95f);
private static readonly Vector3 VisorScaleTop = new Vector3(0.68f, 0.35f, 0.99f);
private const float TopRefFov = 130f;
private const float LerpCurveMix = 0.6f;
private static float _prefixCamFov = 0f;
[HarmonyPatch(typeof(PlayerControllerB), "Awake")]
[HarmonyPostfix]
private static void PlayerAwake_Postfix(PlayerControllerB __instance)
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
if (!FilterOut(__instance) && (Object)(object)__instance.localVisor != (Object)null)
{
__instance.localVisor.localScale = visorScale;
}
}
[HarmonyPatch(typeof(PlayerControllerB), "Update")]
[HarmonyPrefix]
[HarmonyPriority(500)]
private static void Update_Prefix(PlayerControllerB __instance)
{
//IL_0046: 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)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
if (!FilterOut(__instance))
{
_prefixCamFov = (((Object)(object)__instance.gameplayCamera != (Object)null) ? __instance.gameplayCamera.fieldOfView : newTargetFovBase);
if ((Object)(object)__instance.localVisor != (Object)null && __instance.localVisor.localScale != visorScale)
{
__instance.localVisor.localScale = visorScale;
}
}
}
[HarmonyPatch(typeof(PlayerControllerB), "Update")]
[HarmonyPostfix]
[HarmonyPriority(300)]
private static void Update_Postfix(PlayerControllerB __instance)
{
if (FilterOut(__instance))
{
return;
}
float num = newTargetFovBase;
if (__instance.inTerminalMenu)
{
num = 60f;
}
else if (__instance.IsInspectingItem)
{
num = 46f;
}
else if (__instance.isSprinting)
{
num *= sprintFovMultiplier;
}
if ((Object)(object)__instance.gameplayCamera != (Object)null)
{
__instance.gameplayCamera.fieldOfView = Mathf.Lerp(_prefixCamFov, num, 8f * Time.deltaTime);
if (snapFovChange)
{
__instance.gameplayCamera.fieldOfView = num;
_prefixCamFov = num;
snapFovChange = false;
}
}
}
[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
[HarmonyPostfix]
[HarmonyPriority(300)]
private static void LateUpdate_Postfix(PlayerControllerB __instance)
{
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
if (!FilterOut(__instance) && !((Object)(object)__instance.localVisor == (Object)null) && newTargetFovBase > 66f)
{
Transform localVisor = __instance.localVisor;
localVisor.position += __instance.localVisor.rotation * new Vector3(0f, 0f, -0.06f);
}
}
public static void RecalculateVisorScale()
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
if (hideVisor)
{
visorScale = Vector3.zero;
lastAppliedFovForScale = newTargetFovBase;
}
else if (!(Math.Abs(newTargetFovBase - lastAppliedFovForScale) < 0.01f))
{
lastAppliedFovForScale = newTargetFovBase;
if (newTargetFovBase <= 66f)
{
visorScale = new Vector3(0.36f, 0.49f, 0.49f);
return;
}
float num = Mathf.InverseLerp(66f, 130f, newTargetFovBase);
float num2 = Mathf.Sin(num * (float)Math.PI * 0.5f);
float num3 = Mathf.Lerp(num, num2, 0.6f);
visorScale = Vector3.LerpUnclamped(VisorScaleBottom, VisorScaleTop, num3);
}
}
private static bool FilterOut(PlayerControllerB p)
{
return (Object)(object)p == (Object)null || !((NetworkBehaviour)p).IsOwner || !p.isPlayerControlled || (((NetworkBehaviour)p).IsServer && !p.isHostPlayerObject && !p.isTestingPlayer);
}
}
public static class HUDManagerPatches
{
[HarmonyPatch(typeof(HUDManager), "SubmitChat_performed")]
[HarmonyPrefix]
public static bool SubmitChat_Prefix(HUDManager __instance)
{
string text = __instance.chatTextField.text?.Trim() ?? string.Empty;
if (string.IsNullOrEmpty(text))
{
return true;
}
if (text.StartsWith("/fov", StringComparison.OrdinalIgnoreCase))
{
string[] array = text.Split(new char[1] { ' ' });
if (array.Length > 1 && float.TryParse(array[1], out var result) && !float.IsNaN(result))
{
LCFovBase.SetFov(result);
AddChat(__instance, $"FOV set to {Mathf.Clamp(result, 66f, 130f):0.#}");
}
else
{
AddChat(__instance, "Usage: /fov <66–130>");
}
ClearChatBox(__instance);
return false;
}
if (text.StartsWith("/visor", StringComparison.OrdinalIgnoreCase))
{
string text2 = ((text.Length > 6) ? text.Substring(6).Trim().ToLowerInvariant() : "toggle");
bool? flag = null;
switch (text2)
{
case "on":
flag = true;
break;
case "off":
flag = false;
break;
default:
AddChat(__instance, "Usage: /visor on | off | toggle");
ClearChatBox(__instance);
return false;
case "toggle":
break;
}
if (flag.HasValue)
{
LCFovBase.SetHideVisor(!flag.Value);
AddChat(__instance, flag.Value ? "Visor: ON (visible)" : "Visor: OFF (hidden)");
}
else
{
bool hideVisor = PlayerControllerBPatches.hideVisor;
LCFovBase.SetHideVisor(!hideVisor);
AddChat(__instance, (!hideVisor) ? "Visor: OFF (hidden)" : "Visor: ON (visible)");
}
ClearChatBox(__instance);
return false;
}
return true;
}
private static void AddChat(HUDManager hud, string msg)
{
try
{
Traverse.Create((object)hud).Method("AddChatMessage", new object[2] { msg, "" }).GetValue();
}
catch
{
ManualLogSource log = LCFovBase.Log;
if (log != null)
{
log.LogMessage((object)msg);
}
}
}
private static void ClearChatBox(HUDManager hud)
{
hud.localPlayer = GameNetworkManager.Instance.localPlayerController;
hud.localPlayer.isTypingChat = false;
hud.chatTextField.text = "";
if ((Object)(object)hud.typingIndicator != (Object)null)
{
((Behaviour)hud.typingIndicator).enabled = false;
}
}
}