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" + text.TrimStart(Array.Empty()) + ""; } } } 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 _activationSpeedKmh; private static ConfigEntry _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("Cruise Control", "ActivationSpeedKmh", 5f, I18n.Localizer.Config("config.activation_speed", 10, "Cruise Control", "config.section", 10, (AcceptableValueBase)null)); _cruiseKey = config.Bind("Cruise Control", "CruiseKey", (KeyCode)306, I18n.Localizer.Config("config.cruise_key", 20, "Cruise Control", "config.section", 10, (AcceptableValueBase)null)); } } }