Decompiled source of SteadyHelm v1.0.0

SteadyHelm.dll

Decompiled a month ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("SteadyHelm")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+fff128389933172fc3a2aa07de470d09976fb9b6")]
[assembly: AssemblyProduct("SteadyHelm")]
[assembly: AssemblyTitle("SteadyHelm")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 SteadyHelm
{
	[HarmonyPatch]
	internal static class Autopilot
	{
		private sealed class Pid
		{
			private readonly double _kp;

			private readonly double _ki;

			private readonly double _kd;

			private readonly float _min;

			private readonly float _max;

			private double _integral;

			private double _lastError;

			private bool _primed;

			internal Pid(double kp, double ki, double kd, float min, float max)
			{
				_kp = kp;
				_ki = ki;
				_kd = kd;
				_min = min;
				_max = max;
			}

			internal void Reset()
			{
				_integral = 0.0;
				_lastError = 0.0;
				_primed = false;
			}

			internal float Update(double error, double dt)
			{
				if (dt <= 0.0)
				{
					return 0f;
				}
				_integral = Clamp(_integral + error * dt);
				double num = (_primed ? ((error - _lastError) / dt) : 0.0);
				_lastError = error;
				_primed = true;
				return (float)(0.0 - Clamp(_kp * error + _ki * _integral + _kd * num));
			}

			private double Clamp(double value)
			{
				if (!(value < (double)_min))
				{
					if (!(value > (double)_max))
					{
						return value;
					}
					return _max;
				}
				return _min;
			}
		}

		internal static bool Active;

		private static readonly Pid Rudder = new Pid(3.0, 0.003, 6.0, -1f, 1f);

		private static Vector3 _course;

		private static Ship _helm;

		private static bool _steeringByHand;

		internal static void TrackHelm(Ship ship)
		{
			if (!((Object)(object)ship == (Object)(object)_helm))
			{
				_helm = ship;
				_steeringByHand = false;
				if ((Object)(object)ship != (Object)null)
				{
					HoldCurrentCourse(ship);
				}
			}
		}

		internal static void HoldCurrentCourse(Ship ship)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			SetCourse(((Component)ship).transform.forward);
		}

		internal static void SetCourse(Vector3 direction)
		{
			//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)
			direction.y = 0f;
			if (!(((Vector3)(ref direction)).sqrMagnitude < 0.0001f))
			{
				_course = ((Vector3)(ref direction)).normalized;
				Rudder.Reset();
			}
		}

		[HarmonyPatch(typeof(Ship), "ApplyControlls")]
		[HarmonyPrefix]
		private static void Steer(Ship __instance, ref Vector3 dir, Rigidbody ___m_body)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Invalid comparison between Unknown and I4
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Invalid comparison between Unknown and I4
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || (Object)(object)__instance != (Object)(object)_helm || (Object)(object)___m_body == (Object)null)
			{
				return;
			}
			if (Mathf.Abs(dir.x) > 0.01f)
			{
				_steeringByHand = true;
				return;
			}
			if (_steeringByHand)
			{
				_steeringByHand = false;
				HoldCurrentCourse(__instance);
			}
			Speed speedSetting = __instance.GetSpeedSetting();
			float speed = __instance.GetSpeed();
			bool flag = ((int)speedSetting == 1 && speed > 0f) || ((int)speedSetting != 1 && speed < 0f);
			dir.x = (flag ? (0f - Mathf.Clamp(__instance.GetRudderValue(), -1f, 1f)) : Rudder.Update(CourseError(__instance, _course, ___m_body.angularVelocity.y), Time.fixedDeltaTime));
		}

		private static float CourseError(Ship ship, Vector3 course, float yawRate)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_0032: 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)
			Vector3 forward = ((Component)ship).transform.forward;
			forward.y = 0f;
			float num = Vector3.SignedAngle(forward, course, Vector3.up);
			if ((int)ship.GetSpeedSetting() == 1)
			{
				yawRate = 0f - yawRate;
				num = 0f - Vector3.SignedAngle(-forward, course, Vector3.up);
				if (Mathf.Abs(num) > 90f)
				{
					num += ((num < 0f) ? 180f : (-180f));
				}
			}
			return yawRate - num / 40f;
		}
	}
	internal static class GameAccess
	{
		private static readonly Func<Minimap, Vector3, Vector3> ScreenToWorld = AccessTools.MethodDelegate<Func<Minimap, Vector3, Vector3>>(AccessTools.Method(typeof(Minimap), "ScreenToWorldPoint", new Type[1] { typeof(Vector3) }, (Type[])null), (object)null, true);

		internal static bool SelfTest(out string problem)
		{
			try
			{
				RuntimeHelpers.RunClassConstructor(typeof(GameAccess).TypeHandle);
				problem = null;
				return ScreenToWorld != null;
			}
			catch (Exception ex)
			{
				problem = ex.Message;
				return false;
			}
		}

		internal static bool TryScreenToWorldPoint(Minimap map, Vector3 screen, out Vector3 world)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			world = default(Vector3);
			if (ScreenToWorld == null)
			{
				return false;
			}
			world = ScreenToWorld(map, screen);
			return true;
		}
	}
	[HarmonyPatch]
	internal static class MapCourse
	{
		internal static bool Armed;

		[HarmonyPatch(typeof(Minimap), "Start")]
		[HarmonyPostfix]
		private static void Hook(Minimap __instance)
		{
			if ((Object)(object)__instance.m_mapImageLarge == (Object)null)
			{
				return;
			}
			UIInputHandler component = ((Component)__instance.m_mapImageLarge).GetComponent<UIInputHandler>();
			if ((Object)(object)component == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Large map has no input handler; setting a course on the map is off this run.");
				return;
			}
			Minimap map = __instance;
			component.m_onLeftUp = (Action<UIInputHandler>)Delegate.Combine(component.m_onLeftUp, (Action<UIInputHandler>)delegate
			{
				OnMapClick(map);
			});
		}

		private static void OnMapClick(Minimap map)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: 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)
			if (!Armed || (Object)(object)map == (Object)null)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			Ship val = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetControlledShip() : null);
			if (!((Object)(object)val == (Object)null) && GameAccess.TryScreenToWorldPoint(map, UnityInput.Current.mousePosition, out var world))
			{
				Autopilot.SetCourse(world - ((Component)val).transform.position);
				if (!Autopilot.Active)
				{
					Autopilot.Active = true;
				}
				Plugin.Say("Course set");
			}
		}
	}
	internal enum SteeringMode
	{
		Manual,
		Automatic
	}
	[BepInPlugin("matheba.steadyhelm", "SteadyHelm", "1.0.0")]
	[BepInProcess("valheim.exe")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		internal static ConfigEntry<SteeringMode> StartMode;

		internal static ConfigEntry<bool> ShowMessages;

		internal static ConfigEntry<KeyboardShortcut> AimKey;

		internal static ConfigEntry<KeyboardShortcut> SwitchModeKey;

		internal static ConfigEntry<KeyboardShortcut> MapCourseKey;

		internal static ConfigEntry<KeyboardShortcut> CameraKey;

		internal static ConfigEntry<bool> MoveShipHud;

		internal static ConfigEntry<int> ShipHudHorizontal;

		internal static ConfigEntry<int> ShipHudVertical;

		private readonly Harmony _harmony = new Harmony("matheba.steadyhelm");

		private void Awake()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Expected O, but got Unknown
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			StartMode = ((BaseUnityPlugin)this).Config.Bind<SteeringMode>("1 - General", "Steering mode on start", SteeringMode.Automatic, "Automatic: the helm holds the course you aim at. Manual: the normal game.");
			ShowMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Show messages", true, "Centre-screen messages when you switch mode, set a course on the map or change camera.");
			AimKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("2 - Keys", "Aim course", new KeyboardShortcut((KeyCode)324, Array.Empty<KeyCode>()), "In automatic mode, hold this and look where you want to go. The ship turns there and keeps that course after you let go.");
			SwitchModeKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("2 - Keys", "Switch steering mode", new KeyboardShortcut((KeyCode)304, Array.Empty<KeyCode>()), "Switches between automatic and manual while you are at the helm.");
			MapCourseKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("2 - Keys", "Set course on map", new KeyboardShortcut((KeyCode)306, Array.Empty<KeyCode>()), "Hold this and click a spot on the large map to point the ship at it. Turns automatic mode on.");
			CameraKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("2 - Keys", "Cycle ship camera", new KeyboardShortcut((KeyCode)118, Array.Empty<KeyCode>()), "Cycles the camera between normal, the bow and high overhead while you steer.");
			MoveShipHud = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Ship HUD", "Move ship HUD", true, "Moves the sail and rudder panel to the position below. Off leaves it where the game puts it.");
			ShipHudHorizontal = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Ship HUD", "Horizontal", 50, new ConfigDescription("Horizontal position on screen, in percent. 0 is left, 100 is right.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			ShipHudVertical = ((BaseUnityPlugin)this).Config.Bind<int>("3 - Ship HUD", "Vertical", 20, new ConfigDescription("Vertical position on screen, in percent. 0 is bottom, 100 is top.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			Autopilot.Active = StartMode.Value == SteeringMode.Automatic;
			_harmony.PatchAll(typeof(Autopilot));
			_harmony.PatchAll(typeof(MapCourse));
			_harmony.PatchAll(typeof(ShipCamera));
			_harmony.PatchAll(typeof(ShipHud));
			if (!GameAccess.SelfTest(out var problem))
			{
				Log.LogError((object)("SteadyHelm cannot reach part of the game; setting a course on the map will not work. A game update probably renamed something. Details: " + problem));
			}
			Log.LogInfo((object)(string.Format("{0} {1} loaded. Mode: {2}, aim: {3}, ", "SteadyHelm", "1.0.0", StartMode.Value, AimKey.Value) + $"switch: {SwitchModeKey.Value}, map: {MapCourseKey.Value}, camera: {CameraKey.Value}"));
		}

		private void OnDestroy()
		{
			_harmony.UnpatchSelf();
		}

		private void Update()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			Ship val = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetControlledShip() : null);
			Autopilot.TrackHelm(val);
			KeyboardShortcut value;
			int armed;
			if ((Object)(object)val != (Object)null)
			{
				value = MapCourseKey.Value;
				armed = (((KeyboardShortcut)(ref value)).IsPressed() ? 1 : 0);
			}
			else
			{
				armed = 0;
			}
			MapCourse.Armed = (byte)armed != 0;
			if ((Object)(object)val == (Object)null || IsTyping())
			{
				return;
			}
			value = SwitchModeKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				Autopilot.Active = !Autopilot.Active;
				Autopilot.HoldCurrentCourse(val);
				Say(Autopilot.Active ? "Steering: automatic" : "Steering: manual");
			}
			if (Autopilot.Active)
			{
				value = AimKey.Value;
				if (((KeyboardShortcut)(ref value)).IsPressed() && (Object)(object)GameCamera.instance != (Object)null)
				{
					Autopilot.SetCourse(((Component)GameCamera.instance).transform.forward);
				}
			}
			value = CameraKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				ShipCamera.Cycle();
			}
		}

		internal static void Say(string message)
		{
			if (ShowMessages.Value && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false);
			}
		}

		private static bool IsTyping()
		{
			if (Console.IsVisible() || TextInput.IsVisible())
			{
				return true;
			}
			if ((Object)(object)Chat.instance != (Object)null)
			{
				return Chat.instance.HasFocus();
			}
			return false;
		}
	}
	internal enum CameraView
	{
		Normal,
		Bow,
		Overhead
	}
	[HarmonyPatch]
	internal static class ShipCamera
	{
		private static CameraView _view;

		internal static void Cycle()
		{
			_view = ((_view == CameraView.Normal) ? CameraView.Bow : ((_view == CameraView.Bow) ? CameraView.Overhead : CameraView.Normal));
			Plugin.Say((_view == CameraView.Normal) ? "Camera: normal" : ((_view == CameraView.Bow) ? "Camera: bow" : "Camera: overhead"));
		}

		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		[HarmonyPostfix]
		private static void Reposition(GameCamera __instance, float ___m_distance)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			Ship val = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetControlledShip() : null);
			if ((Object)(object)val == (Object)null)
			{
				_view = CameraView.Normal;
			}
			else if (_view != CameraView.Normal && !((Object)(object)val.m_floatCollider == (Object)null))
			{
				Transform transform = ((Component)val).transform;
				Vector3 size = val.m_floatCollider.size;
				((Component)__instance).transform.position = ((_view == CameraView.Bow) ? (transform.position + transform.forward * (size.x - 0.3f) + transform.up * 3f) : (transform.position + Vector3.up * (size.z + ___m_distance + 1.3f)));
			}
		}
	}
	[HarmonyPatch]
	internal static class ShipHud
	{
		[HarmonyPatch(typeof(Hud), "UpdateShipHud")]
		[HarmonyPostfix]
		private static void Place(Hud __instance)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.MoveShipHud.Value && !((Object)(object)__instance.m_shipControlsRoot == (Object)null))
			{
				__instance.m_shipControlsRoot.transform.position = new Vector3((float)(Screen.width * Plugin.ShipHudHorizontal.Value) / 100f, (float)(Screen.height * Plugin.ShipHudVertical.Value) / 100f, 0f);
			}
		}
	}
	internal static class PluginInfo
	{
		internal const string Guid = "matheba.steadyhelm";

		internal const string Name = "SteadyHelm";

		internal const string Version = "1.0.0";
	}
}