Decompiled source of CruiseControl v1.0.2

BepInEx/plugins/CruiseControl/CruiseControl.dll

Decompiled a week ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CruiseControl.Configuration;
using CruiseControl.Localization;
using CruiseControl.Runtime;
using CruiseControl.UI;
using Fusion;
using HarmonyLib;
using ModSettingsMenu.Api;
using SunkenlandLocalizationAPI.Api;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("CruiseControl")]
[assembly: AssemblyDescription("Cruise control mod for Sunkenland by Ice Box Studio")]
[assembly: AssemblyCompany("Ice Box Studio")]
[assembly: AssemblyProduct("CruiseControl")]
[assembly: AssemblyCopyright("Copyright © 2026 Ice Box Studio All rights reserved.")]
[assembly: ComVisible(false)]
[assembly: Guid("c668fef8-d6f1-4e45-a154-1e558cbe9bf4")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.1.0")]
namespace CruiseControl
{
	[BepInPlugin("IceBoxStudio.Sunkenland.CruiseControl", "CruiseControl", "1.0.1")]
	[BepInDependency("IceBoxStudio.Sunkenland.ModSettingsMenu", "1.2.0")]
	[BepInDependency("IceBoxStudio.Sunkenland.LocalizationAPI", "1.1.0")]
	public sealed class CruiseControl : BaseUnityPlugin
	{
		private Harmony _harmony;

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			LocalizationApi.LanguageChanged += OnLanguageChanged;
			try
			{
				Log.LogInfo((object)"=============================================");
				Log.LogInfo((object)("CruiseControl " + I18n.Text("plugin.initializing")));
				Log.LogInfo((object)(I18n.Text("plugin.author_prefix") + "Ice Box Studio(https://steamcommunity.com/id/ibox666/)"));
				ConfigManager.Bind(((BaseUnityPlugin)this).Config);
				RegisterSettings();
				_harmony = new Harmony("IceBoxStudio.Sunkenland.CruiseControl");
				_harmony.PatchAll(Assembly.GetExecutingAssembly());
				Log.LogInfo((object)("CruiseControl " + I18n.Text("plugin.initialized")));
				Log.LogInfo((object)"=============================================");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Failed to initialize Cruise Control: {arg}");
			}
		}

		private static void RegisterSettings()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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_004f: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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_008d: Expected O, but got Unknown
			ModSettingsRegistry.Register("IceBoxStudio.Sunkenland.CruiseControl", new ModSettingsModOptions
			{
				Name = "Cruise Control",
				LocalizedName = () => I18n.Text("mod.name"),
				Description = I18n.Text("mod.description"),
				Author = "Ice Box Studio",
				Version = "1.0.1",
				NexusModsId = 82,
				ThunderstoreTeam = "Ice_Box_Studio_Sunkenland",
				ThunderstoreModName = "CruiseControl"
			});
		}

		private static void OnLanguageChanged(string language)
		{
			RegisterSettings();
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "IceBoxStudio.Sunkenland.CruiseControl";

		public const string PLUGIN_NAME = "CruiseControl";

		public const string PLUGIN_VERSION = "1.0.1";
	}
}
namespace CruiseControl.UI
{
	internal static class VehicleSpeedDisplay
	{
		internal static void Append(TextMeshProUGUI speedText)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)speedText == (Object)null) && global::CruiseControl.Runtime.CruiseControl.TryGetPrompt(out var active, out var boat, out var _))
			{
				if (active && (Object)(object)boat != (Object)null && Object.op_Implicit((Object)(object)boat.Rigid))
				{
					Vector3 velocity = boat.Rigid.velocity;
					string text = (((Vector3)(ref velocity)).magnitude * 10f).ToString("f1") + "km/h";
					((TMP_Text)speedText).text = ((boat.MoveState < 0) ? ("-" + text) : text);
				}
				((TMP_Text)speedText).enableWordWrapping = false;
				((TMP_Text)speedText).text = ((TMP_Text)speedText).text + Prompt(active, ((TMP_Text)speedText).fontSize);
			}
		}

		internal static void Append(Text speedText)
		{
			if (!((Object)(object)speedText == (Object)null) && global::CruiseControl.Runtime.CruiseControl.TryGetPrompt(out var active, out var _, out var _))
			{
				speedText.text += Prompt(active, speedText.fontSize);
			}
		}

		private static string Prompt(bool active, float fontSize)
		{
			int num = Mathf.Max(12, Mathf.RoundToInt(fontSize * 0.55f));
			string text = I18n.Text(active ? "ui.cruise.cancel" : "ui.cruise.enable", ConfigManager.CruiseKeyText);
			return "\n<size=" + num + ">" + text.TrimStart(Array.Empty<char>()) + "</size>";
		}
	}
}
namespace CruiseControl.Runtime
{
	internal static class CruiseControl
	{
		private static Boat _boat;

		private static HelicopterController _helicopter;

		private static float _targetSpeed;

		internal static bool IsActive
		{
			get
			{
				if (!((Object)(object)_boat != (Object)null))
				{
					return (Object)(object)_helicopter != (Object)null;
				}
				return true;
			}
		}

		internal static void Toggle()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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)
			if (Object.op_Implicit((Object)(object)Global.code) && Global.code.OnGUI)
			{
				return;
			}
			Boat boat;
			HelicopterController helicopter;
			if (IsActive)
			{
				Clear();
			}
			else if (TryGetCurrentVehicle(out boat, out helicopter) && CanEnable(boat, helicopter))
			{
				_boat = boat;
				_helicopter = helicopter;
				Vector3 velocity;
				float magnitude;
				if (!((Object)(object)boat != (Object)null))
				{
					velocity = helicopter.Rigid.velocity;
					magnitude = ((Vector3)(ref velocity)).magnitude;
				}
				else
				{
					velocity = boat.Rigid.velocity;
					magnitude = ((Vector3)(ref velocity)).magnitude;
				}
				_targetSpeed = magnitude;
			}
		}

		internal static void Tick()
		{
			if (!IsActive)
			{
				return;
			}
			if (!TryGetCurrentVehicle(out var boat, out var helicopter) || (Object)(object)boat != (Object)(object)_boat || (Object)(object)helicopter != (Object)(object)_helicopter)
			{
				Clear();
			}
			else if ((Object)(object)boat != (Object)null)
			{
				if (!SupportsCruise(boat) || !HasInputAuthority(boat) || !boat.EngineOn || HasBoatOverrideInput())
				{
					Clear();
				}
			}
			else if (!HasInputAuthority(helicopter) || !helicopter.EngineOn || HasHelicopterOverrideInput())
			{
				Clear();
			}
		}

		internal static bool IsActiveFor(Boat boat, HelicopterController helicopter)
		{
			if (IsActive && (Object)(object)boat == (Object)(object)_boat)
			{
				return (Object)(object)helicopter == (Object)(object)_helicopter;
			}
			return false;
		}

		internal static void UpdateBoatInput(Boat boat, ref BoatNetworkInput input)
		{
			if (SupportsCruise(boat) && IsActiveFor(boat, null) && HasInputAuthority(boat) && !HasBoatOverrideInput())
			{
				input.MoveState = 1;
			}
		}

		internal static void MaintainBoat(Boat boat)
		{
			//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_0056: 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_0077: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			if (!SupportsCruise(boat) || !IsActiveFor(boat, null) || !HasInputAuthority(boat) || HasBoatOverrideInput())
			{
				return;
			}
			if (!boat.EngineOn || !Object.op_Implicit((Object)(object)boat.Rigid) || boat.Rigid.isKinematic)
			{
				Clear();
				return;
			}
			Vector3 boatForward = GetBoatForward(boat);
			float num = Vector3.Dot(boat.Rigid.velocity, boatForward);
			if (num <= 0.1f)
			{
				Clear();
				return;
			}
			Rigidbody rigid = boat.Rigid;
			rigid.velocity += boatForward * (_targetSpeed - num);
		}

		internal static void UpdateBoatForce(Boat boat, ref int force)
		{
			if (SupportsCruise(boat) && IsActiveFor(boat, null) && !HasBoatOverrideInput())
			{
				force = 1;
			}
		}

		internal static void MaintainHelicopter(HelicopterController helicopter)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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)
			if (IsActiveFor(null, helicopter) && HasInputAuthority(helicopter) && !HasHelicopterOverrideInput())
			{
				if (!helicopter.EngineOn || !Object.op_Implicit((Object)(object)helicopter.Rigid) || helicopter.Rigid.isKinematic)
				{
					Clear();
					return;
				}
				Vector3 velocity = helicopter.Rigid.velocity;
				Vector3 val = ((((Vector3)(ref velocity)).sqrMagnitude > 0.01f) ? ((Vector3)(ref velocity)).normalized : ((Component)helicopter).transform.forward);
				helicopter.Rigid.velocity = val * _targetSpeed;
			}
		}

		internal static bool TryGetPrompt(out bool active, out Boat boat, out HelicopterController helicopter)
		{
			active = false;
			if (!TryGetCurrentVehicle(out boat, out helicopter))
			{
				return false;
			}
			if ((Object)(object)boat != (Object)null && !SupportsCruise(boat))
			{
				return false;
			}
			active = IsActiveFor(boat, helicopter);
			if (!active)
			{
				return CanEnable(boat, helicopter);
			}
			return true;
		}

		private static bool CanEnable(Boat boat, HelicopterController helicopter)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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)
			Vector3 velocity;
			if ((Object)(object)boat != (Object)null)
			{
				if (SupportsCruise(boat) && HasInputAuthority(boat) && boat.EngineOn && Object.op_Implicit((Object)(object)boat.Rigid) && !boat.Rigid.isKinematic)
				{
					velocity = boat.Rigid.velocity;
					if (!(((Vector3)(ref velocity)).magnitude * 10f < ConfigManager.ActivationSpeedKmh))
					{
						return Vector3.Dot(boat.Rigid.velocity, GetBoatForward(boat)) > 0.1f;
					}
				}
				return false;
			}
			if (HasInputAuthority(helicopter) && helicopter.EngineOn && Object.op_Implicit((Object)(object)helicopter.Rigid) && !helicopter.Rigid.isKinematic)
			{
				velocity = helicopter.Rigid.velocity;
				return ((Vector3)(ref velocity)).magnitude * 10f >= ConfigManager.ActivationSpeedKmh;
			}
			return false;
		}

		private static bool SupportsCruise(Boat boat)
		{
			if ((Object)(object)boat != (Object)null && !Object.op_Implicit((Object)(object)boat.M_Sail))
			{
				return !boat.SeparatWaterObject;
			}
			return false;
		}

		private static bool HasInputAuthority(Boat boat)
		{
			if ((Object)(object)boat != (Object)null && Object.op_Implicit((Object)(object)((SimulationBehaviour)boat).Object))
			{
				return ((SimulationBehaviour)boat).Object.HasInputAuthority;
			}
			return false;
		}

		private static bool HasInputAuthority(HelicopterController helicopter)
		{
			if ((Object)(object)helicopter != (Object)null && Object.op_Implicit((Object)(object)((SimulationBehaviour)helicopter).Object))
			{
				return ((SimulationBehaviour)helicopter).Object.HasInputAuthority;
			}
			return false;
		}

		private static bool TryGetCurrentVehicle(out Boat boat, out HelicopterController helicopter)
		{
			boat = null;
			helicopter = null;
			if (!Object.op_Implicit((Object)(object)Global.code) || !Object.op_Implicit((Object)(object)Global.code.Player))
			{
				return false;
			}
			boat = Global.code.Player.drivingObject;
			if ((Object)(object)boat != (Object)null)
			{
				return true;
			}
			helicopter = Global.code.Player.CurHelicopter;
			return (Object)(object)helicopter != (Object)null;
		}

		private static Vector3 GetBoatForward(Boat boat)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			Transform engineForward = boat.engineForward;
			Vector3 val = Vector3.ProjectOnPlane(((Object)(object)engineForward != (Object)null) ? engineForward.forward : ((Component)boat).transform.forward, Vector3.up);
			return ((Vector3)(ref val)).normalized;
		}

		private static bool HasBoatOverrideInput()
		{
			InputManager instance = InputManager.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				if (!instance.BackHold)
				{
					if (instance.BoatBoostHold)
					{
						return !UsesCruiseKey(instance.BoatBoostKeyAction);
					}
					return false;
				}
				return true;
			}
			return false;
		}

		private static bool UsesCruiseKey(KeyAction keyAction)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			if (keyAction != null)
			{
				return ConfigManager.UsesKey(keyAction.keyCode);
			}
			return false;
		}

		private static bool HasHelicopterOverrideInput()
		{
			InputManager instance = InputManager.Instance;
			if ((!((Object)(object)instance != (Object)null) || (!instance.HelicopterThrottlePositiveHold && !instance.HelicopterThrottleNegativeHold && !instance.HelicopterYawNegativeHold && !instance.HelicopterYawPositiveHold)) && !(Mathf.Abs(Input.GetAxis("Mouse X")) > 0.01f))
			{
				return Mathf.Abs(Input.GetAxis("Mouse Y")) > 0.01f;
			}
			return true;
		}

		private static void Clear()
		{
			_boat = null;
			_helicopter = null;
			_targetSpeed = 0f;
		}
	}
	internal static class CruiseInput
	{
		internal static void Run()
		{
			if (ConfigManager.IsDown())
			{
				CruiseControl.Toggle();
			}
			CruiseControl.Tick();
		}
	}
}
namespace CruiseControl.Patches
{
	[HarmonyPatch(typeof(Boat), "AddForce", new Type[] { typeof(int) })]
	internal static class BoatAddForcePatch
	{
		private static void Prefix(Boat __instance, ref int __0)
		{
			global::CruiseControl.Runtime.CruiseControl.UpdateBoatForce(__instance, ref __0);
		}
	}
	[HarmonyPatch(typeof(Boat), "FixedUpdate")]
	internal static class BoatFixedUpdatePatch
	{
		private static void Postfix(Boat __instance)
		{
			global::CruiseControl.Runtime.CruiseControl.MaintainBoat(__instance);
		}
	}
	[HarmonyPatch(typeof(Boat), "PrepareInput")]
	internal static class BoatPrepareInputPatch
	{
		private static void Postfix(Boat __instance, ref BoatNetworkInput __result)
		{
			global::CruiseControl.Runtime.CruiseControl.UpdateBoatInput(__instance, ref __result);
		}
	}
	[HarmonyPatch(typeof(HelicopterController), "FixedUpdate")]
	internal static class HelicopterFixedUpdatePatch
	{
		private static void Postfix(HelicopterController __instance)
		{
			global::CruiseControl.Runtime.CruiseControl.MaintainHelicopter(__instance);
		}
	}
	[HarmonyPatch(typeof(HelicopterHUD), "FixedUpdate")]
	internal static class HelicopterSpeedUiPatch
	{
		private static void Postfix(HelicopterHUD __instance)
		{
			VehicleSpeedDisplay.Append(__instance.speedTxt);
		}
	}
	[HarmonyPatch(typeof(InputManager), "Update")]
	internal static class InputManagerUpdatePatch
	{
		private static void Postfix()
		{
			CruiseInput.Run();
		}
	}
	[HarmonyPatch(typeof(UICombat), "Update")]
	internal static class VehicleSpeedUiPatch
	{
		private static void Postfix(TextMeshProUGUI ___tmpVehicleSpeed)
		{
			VehicleSpeedDisplay.Append(___tmpVehicleSpeed);
		}
	}
}
namespace CruiseControl.Localization
{
	internal static class I18n
	{
		private const string FileName = "CruiseControl.Localization.json";

		private static readonly ModLocalizer _localizer = Load();

		internal static ModLocalizer Localizer => _localizer;

		internal static string Text(string key, params object[] args)
		{
			return _localizer.GetLocalizedText(key, args);
		}

		private static ModLocalizer Load()
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			ModLocalizer obj = LocalizationApi.For("IceBoxStudio.Sunkenland.CruiseControl");
			obj.RegisterJson(Path.Combine(directoryName, "CruiseControl.Localization.json"));
			return obj;
		}
	}
}
namespace CruiseControl.Configuration
{
	internal static class ConfigManager
	{
		private static ConfigEntry<float> _activationSpeedKmh;

		private static ConfigEntry<KeyCode> _cruiseKey;

		internal static float ActivationSpeedKmh => Math.Max(0.1f, (_activationSpeedKmh == null) ? 5f : _activationSpeedKmh.Value);

		internal static KeyCode CruiseKey
		{
			get
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				if (_cruiseKey != null)
				{
					return _cruiseKey.Value;
				}
				return (KeyCode)306;
			}
		}

		internal static string CruiseKeyText
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Invalid comparison between Unknown and I4
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Invalid comparison between Unknown and I4
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				if ((int)CruiseKey == 306 || (int)CruiseKey == 305)
				{
					return I18n.Text("key.ctrl");
				}
				return ((object)CruiseKey/*cast due to .constrained prefix*/).ToString();
			}
		}

		internal static bool IsDown()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if ((int)CruiseKey != 0)
			{
				return Input.GetKeyDown(CruiseKey);
			}
			return false;
		}

		internal static bool UsesKey(KeyCode key)
		{
			//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)
			return CruiseKey == key;
		}

		internal static void Bind(ConfigFile config)
		{
			_activationSpeedKmh = config.Bind<float>("Cruise Control", "ActivationSpeedKmh", 5f, I18n.Localizer.Config("config.activation_speed", 10, "Cruise Control", "config.section", 10, (AcceptableValueBase)null));
			_cruiseKey = config.Bind<KeyCode>("Cruise Control", "CruiseKey", (KeyCode)306, I18n.Localizer.Config("config.cruise_key", 20, "Cruise Control", "config.section", 10, (AcceptableValueBase)null));
		}
	}
}