Decompiled source of ScrollToFirstPerson v1.1.0

ScrollToFirstPerson.dll

Decompiled 2 weeks ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ScrollToFirstPerson;

[BepInPlugin("com.burks.scrolltofirstperson", "Scroll To First Person", "1.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class ScrollToFirstPersonPlugin : BaseUnityPlugin
{
	public const string GUID = "com.burks.scrolltofirstperson";

	public const string NAME = "Scroll To First Person";

	public const string VERSION = "1.1.0";

	public static ManualLogSource Log;

	public static ConfigEntry<bool> Enabled;

	public static ConfigEntry<bool> FaceLook;

	public static ConfigEntry<bool> FaceLookOnlyFirstPerson;

	public static bool VPlusReady;

	public static ConfigEntry<float> Cooldown;

	private void Awake()
	{
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Invalid comparison between Unknown and I4
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Scroll in past the closest zoom to enter Valheim Plus first person; scroll out to leave it.");
		Cooldown = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SwitchCooldownSeconds", 0.3f, "Minimum time between switches, so one long spin of the wheel does not flip back and forth.");
		FaceLook = ((BaseUnityPlugin)this).Config.Bind<bool>("FaceLookDirection", "Enabled", true, "Your character always turns to face the way the camera is looking, instead of the way you are walking.");
		FaceLookOnlyFirstPerson = ((BaseUnityPlugin)this).Config.Bind<bool>("FaceLookDirection", "OnlyInFirstPerson", false, "If true, only do this while Valheim Plus first person is active; third person behaves as normal.");
		if ((int)SystemInfo.graphicsDeviceType != 4)
		{
			Harmony val = new Harmony("com.burks.scrolltofirstperson");
			VPlusReady = VPlus.Init();
			if (VPlusReady)
			{
				val.CreateClassProcessor(typeof(CameraPatch)).Patch();
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Valheim Plus first-person code was not found in the form this mod expects; scroll switching is off.");
			}
			val.CreateClassProcessor(typeof(FacePatch)).Patch();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Scroll To First Person 1.1.0 loaded.");
		}
	}
}
public static class VPlus
{
	private static FieldInfo _isFirstPerson;

	private static FieldInfo _saved3rd;

	private static FieldInfo _savedFps;

	private static FieldInfo _zoomSens;

	private static FieldInfo _minDist;

	private static FieldInfo _maxDist;

	private static MethodInfo _setupFP;

	private static PropertyInfo _current;

	private static PropertyInfo _firstPerson;

	private static PropertyInfo _isEnabled;

	private static float _enabledCheckedAt = -999f;

	private static bool _enabledCached;

	private static readonly FieldRef<Character, Transform> Head = AccessTools.FieldRefAccess<Character, Transform>("m_head");

	public static bool IsFirstPerson => (bool)_isFirstPerson.GetValue(null);

	public static bool Init()
	{
		try
		{
			Type type = AccessTools.TypeByName("ValheimPlus.FirstPerson.VPlusFirstPerson");
			if (type == null)
			{
				return false;
			}
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			Type nestedType = type.GetNestedType("DynamicPerson", bindingAttr);
			Type nestedType2 = type.GetNestedType("CameraConstants", bindingAttr);
			Type nestedType3 = type.GetNestedType("GameCamera_Update_Patch", bindingAttr);
			if (nestedType == null || nestedType2 == null || nestedType3 == null)
			{
				return false;
			}
			_isFirstPerson = nestedType.GetField("isFirstPerson", bindingAttr);
			_saved3rd = nestedType.GetField("noVPFP_3rdOffset", bindingAttr);
			_savedFps = nestedType.GetField("noVPFP_fpsOffset", bindingAttr);
			_zoomSens = nestedType2.GetField("zoomSens", bindingAttr);
			_minDist = nestedType2.GetField("minDistance", bindingAttr);
			_maxDist = nestedType2.GetField("maxDistance", bindingAttr);
			_setupFP = nestedType3.GetMethod("SetupFP", bindingAttr);
			Type type2 = AccessTools.TypeByName("ValheimPlus.Configurations.Configuration");
			if (type2 != null)
			{
				_current = type2.GetProperty("Current", bindingAttr);
				_firstPerson = type2.GetProperty("FirstPerson", bindingAttr);
				if (_firstPerson != null)
				{
					_isEnabled = _firstPerson.PropertyType.GetProperty("IsEnabled", bindingAttr);
				}
			}
			return _isFirstPerson != null && _saved3rd != null && _savedFps != null && _zoomSens != null && _minDist != null && _maxDist != null && _setupFP != null && _current != null && _firstPerson != null && _isEnabled != null;
		}
		catch (Exception ex)
		{
			ScrollToFirstPersonPlugin.Log.LogWarning((object)("Could not hook into Valheim Plus: " + ex.Message));
			return false;
		}
	}

	public static bool FeatureEnabled()
	{
		if (Time.unscaledTime - _enabledCheckedAt < 1f)
		{
			return _enabledCached;
		}
		_enabledCheckedAt = Time.unscaledTime;
		try
		{
			object value = _current.GetValue(null, null);
			object obj = ((value != null) ? _firstPerson.GetValue(value, null) : null);
			_enabledCached = obj != null && (bool)_isEnabled.GetValue(obj, null);
		}
		catch
		{
			_enabledCached = false;
		}
		return _enabledCached;
	}

	public static void Enter(GameCamera cam, Player player)
	{
		_isFirstPerson.SetValue(null, true);
		object[] parameters = new object[2] { cam, player };
		_setupFP.Invoke(null, parameters);
	}

	public static void Exit(GameCamera cam, Player player)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		_isFirstPerson.SetValue(null, false);
		cam.m_3rdOffset = (Vector3)_saved3rd.GetValue(null);
		cam.m_fpsOffset = (Vector3)_savedFps.GetValue(null);
		cam.m_minDistance = (float)_minDist.GetValue(null);
		cam.m_maxDistance = (float)_maxDist.GetValue(null);
		cam.m_zoomSens = (float)_zoomSens.GetValue(null);
		cam.m_fov = 65f;
		Transform val = Head.Invoke((Character)(object)player);
		if ((Object)(object)val != (Object)null)
		{
			val.localScale = Vector3.one;
		}
		if ((Object)(object)((Character)player).m_eye != (Object)null)
		{
			((Character)player).m_eye.localScale = Vector3.one;
		}
	}
}
[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
public static class CameraPatch
{
	private static readonly FieldRef<GameCamera, float> Distance = AccessTools.FieldRefAccess<GameCamera, float>("m_distance");

	private static readonly FieldRef<GameCamera, bool> FreeFly = AccessTools.FieldRefAccess<GameCamera, bool>("m_freeFly");

	private static float _lastSwitch = -999f;

	private static bool _failed;

	[HarmonyPrefix]
	public static void Prefix(GameCamera __instance)
	{
		if (_failed || !ScrollToFirstPersonPlugin.Enabled.Value)
		{
			return;
		}
		try
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || FreeFly.Invoke(__instance) || !VPlus.FeatureEnabled())
			{
				return;
			}
			float mouseScrollWheel = ZInput.GetMouseScrollWheel();
			if (mouseScrollWheel == 0f || Time.unscaledTime - _lastSwitch < Mathf.Max(0f, ScrollToFirstPersonPlugin.Cooldown.Value) || ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) || Console.IsVisible() || InventoryGui.IsVisible() || StoreGui.IsVisible() || Menu.IsVisible() || Minimap.IsOpen() || Hud.IsPieceSelectionVisible() || Hud.InRadial() || ((Character)localPlayer).InCutscene() || ((Character)localPlayer).InPlaceMode())
			{
				return;
			}
			if (!VPlus.IsFirstPerson)
			{
				if (mouseScrollWheel > 0f && Distance.Invoke(__instance) <= __instance.m_minDistance + 0.01f)
				{
					VPlus.Enter(__instance, localPlayer);
					_lastSwitch = Time.unscaledTime;
				}
			}
			else if (mouseScrollWheel < 0f)
			{
				VPlus.Exit(__instance, localPlayer);
				Distance.Invoke(__instance) = __instance.m_minDistance;
				_lastSwitch = Time.unscaledTime;
			}
		}
		catch (Exception ex)
		{
			_failed = true;
			ScrollToFirstPersonPlugin.Log.LogWarning((object)("Scroll switching disabled after an error: " + ex));
		}
	}
}
[HarmonyPatch(typeof(Player), "AlwaysRotateCamera")]
public static class FacePatch
{
	[HarmonyPostfix]
	public static void Postfix(Player __instance, ref bool __result)
	{
		if (__result)
		{
			return;
		}
		try
		{
			if (ScrollToFirstPersonPlugin.FaceLook.Value && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Character)__instance).InEmote() && !((Character)__instance).IsAttached() && (!ScrollToFirstPersonPlugin.FaceLookOnlyFirstPerson.Value || (ScrollToFirstPersonPlugin.VPlusReady && VPlus.IsFirstPerson)))
			{
				__result = true;
			}
		}
		catch
		{
		}
	}
}