using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Landoria.SharedLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Landoria.FirstPerson")] [assembly: AssemblyDescription("Adds first-person view and persistent normal-camera FOV control.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Landoria")] [assembly: AssemblyProduct("Landoria.FirstPerson")] [assembly: AssemblyCopyright("Copyright © 2026 End3rbyte")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("E3AE6231-B01C-4392-AA43-20F1215A876B")] [assembly: AssemblyFileVersion("1.0.3")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")] [assembly: AssemblyVersion("1.0.3.28649")] namespace Landoria.FirstPerson { [HarmonyPatch(typeof(GameCamera), "Awake")] internal static class FirstPersonCameraAwakePatch { private static void Prefix(GameCamera __instance) { FirstPersonMode.CaptureVanillaDistance(__instance); } private static void Postfix(GameCamera __instance) { FirstPersonMode.Apply(__instance); } } [HarmonyPatch(typeof(GameCamera), "UpdateCamera")] internal static class FirstPersonCameraUpdatePatch { private static void Postfix(GameCamera __instance, float ___m_distance) { Player localPlayer = Player.m_localPlayer; bool flag = FirstPersonPolicy.ShouldApplyFirstPerson(FirstPersonMode.Enabled, Object.op_Implicit((Object)(object)localPlayer), Object.op_Implicit((Object)(object)localPlayer) && ((Character)localPlayer).IsDead(), GameCamera.InFreeFly(), ___m_distance); FirstPersonMode.SetActive(flag); FirstPersonMode.ApplyConfiguredFieldOfView(__instance); FirstPersonVisibilityController.SetHidden(localPlayer, flag); if (flag) { FirstPersonViewController.Apply(__instance, localPlayer); FirstPersonHelmetLightController.Apply(__instance, localPlayer); } else { FirstPersonHelmetLightController.Restore(); } } } [HarmonyPatch(typeof(Character), "SetVisible")] internal static class FirstPersonPlayerVisibilityPatch { private static void Prefix(Character __instance, ref bool visible) { if (FirstPersonMode.Active && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { visible = true; } } } [HarmonyPatch(typeof(VisEquipment), "UpdateVisuals")] internal static class FirstPersonVisualVisibilityPatch { private static void Postfix(VisEquipment __instance, GameObject ___m_leftItemInstance, GameObject ___m_rightItemInstance) { Player componentInParent = ((Component)__instance).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)(object)Player.m_localPlayer) { FirstPersonVisibilityController.TrackHeldItems(componentInParent, ___m_leftItemInstance, ___m_rightItemInstance); } if (FirstPersonMode.Active && (Object)(object)componentInParent == (Object)(object)Player.m_localPlayer) { FirstPersonHelmetLightController.Refresh(componentInParent); } } } [HarmonyPatch(typeof(MonoUpdaters), "LateUpdate")] internal static class FirstPersonHelmetLightLateUpdatePatch { private static void Postfix() { FirstPersonHelmetLightController.Apply(GameCamera.instance, Player.m_localPlayer); } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class FirstPersonCommandRegistrationPatch { private static void Postfix() { FirstPersonCommand.Register(); } } [HarmonyPatch(typeof(ConsoleCommand), "RunAction")] internal static class FirstPersonFieldOfViewCommandPatch { private static bool Prefix(ConsoleCommand __instance, ConsoleEventArgs args) { string value = ((args.Length > 1) ? args[1] : null); if (!FirstPersonPolicy.ShouldResetFieldOfView(__instance.Command, args.Length, value)) { float fieldOfView = default(float); bool parsed = args.TryParameterFloat(1, ref fieldOfView); if (!FirstPersonPolicy.ShouldRejectFieldOfView(__instance.Command, args.Length, parsed, fieldOfView)) { return true; } Terminal context = args.Context; if (context != null) { context.AddString(FirstPersonMessages.FieldOfViewAboveMaximum); } return false; } FirstPersonPreference.SetFieldOfView(65f); FirstPersonMode.ApplyConfiguredFieldOfView(GameCamera.instance); return false; } private static void Postfix(ConsoleCommand __instance, ConsoleEventArgs args) { float fieldOfView = default(float); bool parsed = args.TryParameterFloat(1, ref fieldOfView); if (FirstPersonPolicy.ShouldPersistFieldOfView(__instance.Command, args.Length, parsed, fieldOfView)) { FirstPersonPreference.SetFieldOfView(fieldOfView); FirstPersonMode.ApplyConfiguredFieldOfView(GameCamera.instance); } } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class FirstPersonPlayerSpawnPatch { private static void Postfix(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { FirstPersonMode.SetEnabled(FirstPersonPreference.Enabled); FirstPersonMode.ApplyConfiguredFieldOfView(GameCamera.instance); } } } [HarmonyPatch(typeof(ZNet), "OnDestroy")] internal static class FirstPersonDisconnectPatch { private static void Prefix() { FirstPersonHelmetLightController.Restore(); FirstPersonVisibilityController.Restore(); FirstPersonMode.ResetSession(); } } internal static class FirstPersonCommand { internal static void Register() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_001f: Unknown result type (might be due to invalid IL or missing references) new ConsoleCommand("firstperson", string.Empty, new ConsoleEventFailable(Run), false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static object Run(ConsoleEventArgs args) { bool enabled = !FirstPersonMode.Enabled; FirstPersonMode.SetEnabled(enabled); FirstPersonPreference.SetEnabled(enabled); return true; } } internal static class FirstPersonHelmetLightController { private struct LightState { internal Vector3 LocalPosition; internal Quaternion LocalRotation; } private struct FlickerState { internal float Intensity; internal float Movement; } private static readonly Dictionary Lights = new Dictionary(); private static readonly Dictionary Flickers = new Dictionary(); private static Player trackedPlayer; internal static void Apply(GameCamera camera, Player player) { //IL_005e: 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) if (!FirstPersonMode.Active || !Object.op_Implicit((Object)(object)camera) || !Object.op_Implicit((Object)(object)player)) { Restore(); return; } if ((Object)(object)trackedPlayer != (Object)(object)player) { Refresh(player); } foreach (Light key in Lights.Keys) { if (Object.op_Implicit((Object)(object)key)) { ((Component)key).transform.SetPositionAndRotation(((Component)camera).transform.position, ((Component)camera).transform.rotation); } } } internal static void Refresh(Player player) { if (!Object.op_Implicit((Object)(object)player)) { Restore(); return; } if ((Object)(object)trackedPlayer != (Object)(object)player) { Restore(); trackedPlayer = player; } VisEquipment component = ((Component)player).GetComponent(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_helmet)) { CaptureLights(component.m_helmet); CaptureFlickers(component.m_helmet); } } internal static void Restore() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair light in Lights) { if (Object.op_Implicit((Object)(object)light.Key)) { ((Component)light.Key).transform.localPosition = light.Value.LocalPosition; ((Component)light.Key).transform.localRotation = light.Value.LocalRotation; } } foreach (KeyValuePair flicker in Flickers) { if (Object.op_Implicit((Object)(object)flicker.Key)) { flicker.Key.m_flickerIntensity = flicker.Value.Intensity; flicker.Key.m_movement = flicker.Value.Movement; } } Lights.Clear(); Flickers.Clear(); trackedPlayer = null; } private static void CaptureLights(Transform helmet) { //IL_003b: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) Light[] componentsInChildren = ((Component)helmet).GetComponentsInChildren(true); foreach (Light val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && !Lights.ContainsKey(val)) { Lights.Add(val, new LightState { LocalPosition = ((Component)val).transform.localPosition, LocalRotation = ((Component)val).transform.localRotation }); } } } private static void CaptureFlickers(Transform helmet) { LightFlicker[] componentsInChildren = ((Component)helmet).GetComponentsInChildren(true); foreach (LightFlicker val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && !Flickers.ContainsKey(val)) { Flickers.Add(val, new FlickerState { Intensity = val.m_flickerIntensity, Movement = val.m_movement }); } if (Object.op_Implicit((Object)(object)val)) { val.m_flickerIntensity = 0f; val.m_movement = 0f; } } } } internal static class FirstPersonMode { private static float vanillaMinimumDistance; private static bool distanceCaptured; internal static bool Enabled { get; private set; } internal static bool Active { get; private set; } internal static void CaptureVanillaDistance(GameCamera camera) { vanillaMinimumDistance = camera.m_minDistance; distanceCaptured = true; } internal static void Apply(GameCamera camera) { if (Object.op_Implicit((Object)(object)camera)) { camera.m_minDistance = (Enabled ? 0f : vanillaMinimumDistance); } } internal static void SetEnabled(bool enabled) { Enabled = enabled; if (!enabled) { Active = false; } Apply(GameCamera.instance); ApplyConfiguredFieldOfView(GameCamera.instance); } internal static void SetActive(bool active) { Active = active; } internal static void SetFieldOfView(GameCamera camera, float fieldOfView) { if (Object.op_Implicit((Object)(object)camera)) { camera.m_fov = fieldOfView; } } internal static void ApplyConfiguredFieldOfView(GameCamera camera) { SetFieldOfView(camera, FirstPersonPolicy.EffectiveFieldOfView(FirstPersonPreference.FieldOfView, Active)); } internal static void ResetSession() { SetEnabled(enabled: false); } internal static void Reset() { FirstPersonHelmetLightController.Restore(); FirstPersonVisibilityController.Restore(); if (distanceCaptured && Object.op_Implicit((Object)(object)GameCamera.instance)) { GameCamera.instance.m_minDistance = vanillaMinimumDistance; } ResetSession(); Active = false; distanceCaptured = false; } } internal static class FirstPersonMessages { private static readonly ResourceManager Resources = new ResourceManager("Landoria.FirstPerson.FirstPersonMessages", typeof(FirstPersonMessages).Assembly); internal static string FieldOfViewAboveMaximum => string.Format(CultureInfo.CurrentCulture, Resources.GetString("FieldOfViewAboveMaximum", CultureInfo.CurrentUICulture), 85f); } internal static class FirstPersonPreference { internal const float DefaultFieldOfView = 65f; private static ConfigEntry enabled; private static ConfigEntry fieldOfView; internal static bool Enabled => enabled.Value; internal static float FieldOfView => fieldOfView.Value; internal static void Initialize(ConfigFile config) { enabled = config.Bind("Camera", "FirstPersonEnabled", true, "Whether first-person view is enabled at minimum camera zoom."); fieldOfView = config.Bind("Camera", "FieldOfView", 65f, "Field of view shared by first-person, third-person, and free-fly cameras."); SetFieldOfView(fieldOfView.Value); } internal static void SetEnabled(bool value) { enabled.Value = value; } internal static void SetFieldOfView(float value) { fieldOfView.Value = FirstPersonPolicy.ClampFieldOfView(value); } } [BepInPlugin("Landoria.FirstPerson", "Landoria.FirstPerson", "1.0.3")] public sealed class FirstPersonPlugin : LandoriaPlugin { private const string PluginGuid = "Landoria.FirstPerson"; private const string PluginName = "Landoria.FirstPerson"; private const string PluginVersion = "1.0.3"; internal static ModLog Log { get; private set; } private void Awake() { Log = InitializePlugin("Landoria.FirstPerson"); FirstPersonPreference.Initialize(((BaseUnityPlugin)this).Config); FirstPersonCommand.Register(); Log.LogInfo("Landoria.FirstPerson 1.0.3 is loaded."); } private void OnDestroy() { FirstPersonMode.Reset(); Log?.LogInfo("Landoria.FirstPerson 1.0.3 is unloaded."); ShutdownPlugin(); Log = null; } } internal static class FirstPersonPolicy { internal const float DistanceThreshold = 0.001f; internal const float MaximumFieldOfView = 85f; internal const float FirstPersonFieldOfViewOffset = 15f; internal static bool ShouldPersistFieldOfView(string command, int argumentCount, bool parsed, float fieldOfView) { if (command == "fov" && argumentCount > 1 && parsed && fieldOfView > 5f) { return fieldOfView <= 85f; } return false; } internal static bool ShouldRejectFieldOfView(string command, int argumentCount, bool parsed, float fieldOfView) { if (command == "fov" && argumentCount > 1 && parsed) { return fieldOfView > 85f; } return false; } internal static bool ShouldResetFieldOfView(string command, int argumentCount, string value) { if (command == "fov" && argumentCount == 2) { return string.Equals(value, "reset", StringComparison.OrdinalIgnoreCase); } return false; } internal static float ClampFieldOfView(float fieldOfView) { return Math.Min(fieldOfView, 85f); } internal static float EffectiveFieldOfView(float configuredFieldOfView, bool firstPersonActive) { return configuredFieldOfView + (firstPersonActive ? 15f : 0f); } internal static bool ShouldApplyFirstPerson(bool modeEnabled, bool hasLocalPlayer, bool isPlayerDead, bool isFreeFly, float cameraDistance) { if (modeEnabled && hasLocalPlayer && !isPlayerDead && !isFreeFly) { return cameraDistance <= 0.001f; } return false; } } internal static class FirstPersonViewController { internal static void Apply(GameCamera camera, Player player) { //IL_0027: 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) //IL_0033: 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_0039: 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_003f: 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_007c: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_006b: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)camera) && Object.op_Implicit((Object)(object)player) && !((Character)player).IsAttached() && !((Character)player).InCutscene()) { Quaternion rotation = ((Component)camera).transform.rotation; Vector3 forward = ((Component)camera).transform.forward; Vector3 val = Vector3.ProjectOnPlane(forward, Vector3.up); if (((Vector3)(ref val)).sqrMagnitude > Mathf.Epsilon) { ((Character)player).SetLookDir(forward, 0f); ((Component)player).transform.rotation = Quaternion.LookRotation(val, Vector3.up); } ((Component)camera).transform.position = ((Character)player).GetEyePoint(); ((Component)camera).transform.rotation = rotation; } } } internal static class FirstPersonVisibilityController { private static readonly HashSet HiddenRenderers = new HashSet(); private static readonly Dictionary AnimatorModes = new Dictionary(); private static Player hiddenPlayer; private static Player equippedPlayer; private static GameObject leftHandItem; private static GameObject rightHandItem; internal static void TrackHeldItems(Player player, GameObject leftItem, GameObject rightItem) { equippedPlayer = player; leftHandItem = leftItem; rightHandItem = rightItem; if (Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)hiddenPlayer) { HideCurrentVisuals(); } } internal static void SetHidden(Player player, bool hidden) { if (!hidden || !Object.op_Implicit((Object)(object)player)) { Restore(); } else if ((Object)(object)hiddenPlayer != (Object)(object)player) { Restore(); hiddenPlayer = player; HideCurrentVisuals(); } } internal static void Refresh(Player player) { if (Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)hiddenPlayer) { HideCurrentVisuals(); } } internal static void Restore() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) foreach (Renderer hiddenRenderer in HiddenRenderers) { if (Object.op_Implicit((Object)(object)hiddenRenderer)) { hiddenRenderer.forceRenderingOff = false; } } foreach (KeyValuePair animatorMode in AnimatorModes) { if (Object.op_Implicit((Object)(object)animatorMode.Key)) { animatorMode.Key.cullingMode = animatorMode.Value; } } HiddenRenderers.Clear(); AnimatorModes.Clear(); hiddenPlayer = null; } private static void HideCurrentVisuals() { //IL_0076: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = ((Component)hiddenPlayer).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && !val.forceRenderingOff) { val.forceRenderingOff = true; HiddenRenderers.Add(val); } } Animator[] componentsInChildren2 = ((Component)hiddenPlayer).GetComponentsInChildren(true); foreach (Animator val2 in componentsInChildren2) { if (Object.op_Implicit((Object)(object)val2) && !AnimatorModes.ContainsKey(val2)) { AnimatorModes.Add(val2, val2.cullingMode); val2.cullingMode = (AnimatorCullingMode)0; } } if ((Object)(object)hiddenPlayer == (Object)(object)equippedPlayer) { ShowHeldItem(leftHandItem); ShowHeldItem(rightHandItem); } } private static void ShowHeldItem(GameObject item) { if (!Object.op_Implicit((Object)(object)item)) { return; } Renderer[] componentsInChildren = item.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && HiddenRenderers.Remove(val)) { val.forceRenderingOff = false; } } } } } namespace Landoria.SharedLib { public abstract class LandoriaPlugin : BaseUnityPlugin { private Harmony _harmony; private bool _patchesApplied; protected ModLog InitializePlugin(string pluginGuid) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown ModLog modLog = new ModLog(((BaseUnityPlugin)this).Logger); Version version = ((object)this).GetType().Assembly.GetName().Version; modLog.LogInfo($"AssemblyVersion: {version}."); _harmony = new Harmony(pluginGuid); PatchOwnNamespace(modLog); return modLog; } protected void PatchOwnNamespace(ModLog log) { if (_patchesApplied) { log.LogDebug("Harmony patches are already active; skipping registration."); return; } string text = ((object)this).GetType().Namespace; Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { if (type.Namespace == text) { _harmony.CreateClassProcessor(type).Patch(); } } _patchesApplied = true; log.LogDebug("Harmony patches were applied for the plugin namespace."); } protected void ShutdownPlugin() { if (_patchesApplied) { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _patchesApplied = false; } } } public sealed class ModLog { private readonly ManualLogSource _logger; public ModLog(ManualLogSource logger) { _logger = logger; } public void LogFatal(object message) { Write((LogLevel)1, message); } public void LogError(object message) { Write((LogLevel)2, message); } public void LogWarning(object message) { Write((LogLevel)4, message); } public void LogMessage(object message) { Write((LogLevel)8, message); } public void LogInfo(object message) { Write((LogLevel)16, message); } public void LogDebug(object message) { Write((LogLevel)32, message); } public void Log(LogLevel level, object message) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Write(level, message); } private void Write(LogLevel level, object message) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) string arg = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); _logger.Log(level, (object)$"[{arg}] {message}"); } } public static class ServerRole { public static bool IsDedicatedServer { get { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { return ZNet.instance.IsDedicated(); } return false; } } } }