Decompiled source of RemoteLever v1.0.3

RemoteLever.dll

Decompiled a month ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("RemoteLever")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RemoteLever")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("0947733e-d699-4472-8c49-1d8d08d42652")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace RemoteLever;

[BepInPlugin("azumi.remotelever", "RemoteLever", "1.0.3")]
public class RemoteLeverPlugin : BaseUnityPlugin
{
	internal static ManualLogSource Log;

	internal static ConfigEntry<Key> LeverKey;

	internal static ConfigEntry<bool> EnableAutoDeparture;

	internal static ConfigEntry<int> AutoDepartureHour;

	internal static ConfigEntry<int> AutoDepartureMinute;

	internal static ConfigEntry<string> AutoDepartureAmPm;

	internal static bool EjectResetInProgress;

	private Harmony harmony;

	internal static void LockLeverForReset()
	{
		if (!EjectResetInProgress)
		{
			EjectResetInProgress = true;
			Log.LogInfo((object)"Remote lever locked: player eject/reset sequence started.");
		}
	}

	internal static void UnlockLeverAfterReset()
	{
		if (EjectResetInProgress)
		{
			EjectResetInProgress = false;
			Log.LogInfo((object)"Remote lever unlocked: player eject/reset sequence completed.");
		}
	}

	internal static bool IsLeverLocked(StartOfRound round)
	{
		if (EjectResetInProgress)
		{
			return true;
		}
		if ((Object)(object)round != (Object)null && round.firingPlayersCutsceneRunning)
		{
			return true;
		}
		return false;
	}

	internal static void ShowTip(string title, string message)
	{
		if ((Object)(object)HUDManager.Instance != (Object)null)
		{
			HUDManager.Instance.DisplayTip(title, message, false, false, "LC_Tip1");
		}
	}

	private void Awake()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Expected O, but got Unknown
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Expected O, but got Unknown
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		harmony = new Harmony("azumi.remotelever");
		harmony.PatchAll();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"RemoteLever loaded.");
		LeverKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Controls", "Lever Key", (Key)98, "Remote lever control key.");
		EnableAutoDeparture = ((BaseUnityPlugin)this).Config.Bind<bool>("Auto", "Enable Auto Departure", false, "Automatically pull the lever and return to orbit at the configured in game time.");
		AutoDepartureHour = ((BaseUnityPlugin)this).Config.Bind<int>("Auto", "Auto Departure Hour", 6, new ConfigDescription("Scheduled departure hour (12-hour format).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 12), Array.Empty<object>()));
		AutoDepartureMinute = ((BaseUnityPlugin)this).Config.Bind<int>("Auto", "Auto Departure Minute", 0, new ConfigDescription("Scheduled departure minute.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 59), Array.Empty<object>()));
		AutoDepartureAmPm = ((BaseUnityPlugin)this).Config.Bind<string>("Auto", "Auto Departure AM/PM", "PM", new ConfigDescription("Scheduled departure AM/PM.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "AM", "PM" }), Array.Empty<object>()));
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Automatic Departure: " + (EnableAutoDeparture.Value ? "Enabled" : "Disabled")));
		((BaseUnityPlugin)this).Logger.LogInfo((object)$"Scheduled time: {AutoDepartureHour.Value}:{AutoDepartureMinute.Value:00} {AutoDepartureAmPm.Value}");
	}
}
[HarmonyPatch(typeof(HUDManager))]
internal class HUDManagerPatch
{
	private static float lastPressTime;

	private static bool autoDepartureTriggered;

	private static bool wasShipLanded;

	[HarmonyPatch("Update")]
	[HarmonyPostfix]
	private static void UpdatePatch()
	{
		StartOfRound instance = StartOfRound.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			return;
		}
		if (instance.shipHasLanded && !wasShipLanded)
		{
			wasShipLanded = true;
			autoDepartureTriggered = false;
			RemoteLeverPlugin.Log.LogInfo((object)"Ship has landed on moon. Automatic departure timer initialized.");
			if (RemoteLeverPlugin.EnableAutoDeparture.Value)
			{
				RemoteLeverPlugin.Log.LogInfo((object)("Automatic departure scheduled for " + $"{RemoteLeverPlugin.AutoDepartureHour.Value}:" + $"{RemoteLeverPlugin.AutoDepartureMinute.Value:00} " + RemoteLeverPlugin.AutoDepartureAmPm.Value));
			}
		}
		if (!instance.shipHasLanded && wasShipLanded)
		{
			wasShipLanded = false;
			RemoteLeverPlugin.Log.LogInfo((object)"Ship is no longer on the moon. Automatic departure state reset.");
		}
		CheckAutomaticDeparture(instance);
		CheckManualLeverInput(instance);
	}

	private static void CheckAutomaticDeparture(StartOfRound round)
	{
		if (!RemoteLeverPlugin.EnableAutoDeparture.Value || autoDepartureTriggered || (Object)(object)GameNetworkManager.Instance == (Object)null || !GameNetworkManager.Instance.isHostingGame || RemoteLeverPlugin.IsLeverLocked(round) || !round.shipHasLanded || round.shipIsLeaving || round.travellingToNewLevel || round.beganLoadingNewLevel || ((Object)(object)RoundManager.Instance != (Object)null && RoundManager.Instance.dungeonIsGenerating))
		{
			return;
		}
		TimeOfDay instance = TimeOfDay.Instance;
		if ((Object)(object)instance == (Object)null || !instance.timeHasStarted || ((Object)(object)round.currentLevel != (Object)null && !round.currentLevel.planetHasTime))
		{
			return;
		}
		int configuredTargetMinutes = GetConfiguredTargetMinutes();
		int currentGameTimeMinutes = GetCurrentGameTimeMinutes(instance);
		if (currentGameTimeMinutes < configuredTargetMinutes)
		{
			return;
		}
		StartMatchLever val = Object.FindObjectOfType<StartMatchLever>();
		if ((Object)(object)val == (Object)null)
		{
			RemoteLeverPlugin.Log.LogWarning((object)"Automatic departure failed: StartMatchLever not found.");
			return;
		}
		autoDepartureTriggered = true;
		try
		{
			RemoteLeverPlugin.Log.LogInfo((object)("Automatic departure triggered at " + FormatTime12Hour(currentGameTimeMinutes) + "."));
			val.LeverAnimation();
			val.EndGame();
			if ((Object)(object)HUDManager.Instance != (Object)null)
			{
				HUDManager.Instance.AddTextToChatOnServer("<color=#00FFFF>[RemoteLever]</color> Automatic ship departure initiated at " + FormatTime12Hour(currentGameTimeMinutes) + ".", -1);
			}
		}
		catch (Exception arg)
		{
			autoDepartureTriggered = false;
			RemoteLeverPlugin.Log.LogError((object)$"Automatic departure exception: {arg}");
		}
	}

	private static bool IsInputBlocked()
	{
		PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
		if ((Object)(object)val != (Object)null)
		{
			if (val.inTerminalMenu)
			{
				RemoteLeverPlugin.Log.LogInfo((object)"Remote lever blocked: terminal menu open.");
				return true;
			}
			if (val.isTypingChat)
			{
				RemoteLeverPlugin.Log.LogInfo((object)"Remote lever blocked: player is typing chat.");
				return true;
			}
		}
		Terminal val2 = Object.FindObjectOfType<Terminal>();
		if ((Object)(object)val2 != (Object)null && val2.terminalInUse)
		{
			RemoteLeverPlugin.Log.LogInfo((object)"Remote lever blocked: terminal is in use.");
			return true;
		}
		return false;
	}

	private static int GetConfiguredTargetMinutes()
	{
		int num = RemoteLeverPlugin.AutoDepartureHour.Value;
		int value = RemoteLeverPlugin.AutoDepartureMinute.Value;
		string value2 = RemoteLeverPlugin.AutoDepartureAmPm.Value;
		if (value2 == "AM")
		{
			if (num == 12)
			{
				num = 0;
			}
		}
		else if (num != 12)
		{
			num += 12;
		}
		return num * 60 + value;
	}

	private static int GetCurrentGameTimeMinutes(TimeOfDay timeOfDay)
	{
		int num = Mathf.FloorToInt(timeOfDay.normalizedTimeOfDay * (60f * (float)timeOfDay.numberOfHours));
		num += 360;
		return num % 1440;
	}

	private static string FormatTime12Hour(int totalMinutes)
	{
		totalMinutes %= 1440;
		int num = totalMinutes / 60;
		int num2 = totalMinutes % 60;
		string arg = ((num >= 12) ? "PM" : "AM");
		int num3 = num % 12;
		if (num3 == 0)
		{
			num3 = 12;
		}
		return $"{num3}:{num2:00} {arg}";
	}

	private static void CheckManualLeverInput(StartOfRound round)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: 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)
		//IL_001f: Invalid comparison between Unknown and I4
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		if (Keyboard.current == null)
		{
			return;
		}
		Key value = RemoteLeverPlugin.LeverKey.Value;
		if ((int)value == 0)
		{
			return;
		}
		ButtonControl val = (ButtonControl)(object)Keyboard.current[value];
		if (val == null || !val.wasPressedThisFrame || IsInputBlocked())
		{
			return;
		}
		if (RemoteLeverPlugin.IsLeverLocked(round))
		{
			RemoteLeverPlugin.Log.LogWarning((object)"Remote lever ignored: eject/reset sequence is in progress.");
			RemoteLeverPlugin.ShowTip("Remote Lever", "Remote Lever cannot be used while the eject sequence is in progress.");
		}
		else
		{
			if (Time.time - lastPressTime < 0.5f)
			{
				return;
			}
			lastPressTime = Time.time;
			if ((Object)(object)GameNetworkManager.Instance == (Object)null)
			{
				return;
			}
			if (!GameNetworkManager.Instance.isHostingGame)
			{
				HUDManager.Instance.DisplayTip("Remote Lever", "Only the host can control the ship.", false, false, "LC_Tip1");
				return;
			}
			StartMatchLever val2 = Object.FindObjectOfType<StartMatchLever>();
			if (!((Object)(object)val2 == (Object)null))
			{
				try
				{
					if (round.shipIsLeaving)
					{
						RemoteLeverPlugin.Log.LogWarning((object)"Remote lever ignored: ship is already leaving.");
					}
					else if (round.travellingToNewLevel)
					{
						RemoteLeverPlugin.Log.LogWarning((object)"Remote lever ignored: travelling to a new level.");
					}
					else if (round.beganLoadingNewLevel)
					{
						RemoteLeverPlugin.Log.LogWarning((object)"Remote lever ignored: new level loading has begun.");
					}
					else if (round.shipLeftAutomatically)
					{
						RemoteLeverPlugin.Log.LogWarning((object)"Remote lever ignored: ship already left automatically.");
					}
					else if ((Object)(object)RoundManager.Instance != (Object)null && RoundManager.Instance.dungeonIsGenerating)
					{
						RemoteLeverPlugin.Log.LogWarning((object)"Remote lever ignored: dungeon is generating.");
					}
					else if (round.inShipPhase)
					{
						if (round.shipHasLanded)
						{
							RemoteLeverPlugin.Log.LogWarning((object)"Remote lever ignored: inconsistent Orbit state (inShipPhase=true, shipHasLanded=true).");
						}
						else
						{
							RemoteLeverPlugin.Log.LogInfo((object)"Triggering landing remotely...");
							val2.LeverAnimation();
							val2.StartGame();
							HUDManager.Instance.AddTextToChatOnServer("<color=#00FFFF>[RemoteLever]</color> Ship landing initiated remotely.", -1);
						}
					}
					else if (!round.shipHasLanded)
					{
						RemoteLeverPlugin.Log.LogWarning((object)"Remote lever ignored: ship has not landed.");
					}
					else
					{
						RemoteLeverPlugin.Log.LogInfo((object)"Triggering departure remotely...");
						autoDepartureTriggered = true;
						val2.LeverAnimation();
						val2.EndGame();
						HUDManager.Instance.AddTextToChatOnServer("<color=#00FFFF>[RemoteLever]</color> Ship departure initiated remotely.", -1);
					}
					return;
				}
				catch (Exception arg)
				{
					RemoteLeverPlugin.Log.LogError((object)$"Remote lever exception: {arg}");
					return;
				}
			}
			RemoteLeverPlugin.Log.LogWarning((object)"StartMatchLever not found.");
		}
	}
}
[HarmonyPatch(typeof(StartOfRound), "FirePlayersAfterDeadlineClientRpc")]
internal static class FirePlayersAfterDeadlinePatch
{
	[HarmonyPrefix]
	private static void Prefix()
	{
		RemoteLeverPlugin.LockLeverForReset();
	}
}
[HarmonyPatch(typeof(StartOfRound), "EndPlayersFiredSequenceClientRpc")]
internal static class EndPlayersFiredSequencePatch
{
	[HarmonyPostfix]
	private static void Postfix()
	{
		RemoteLeverPlugin.UnlockLeverAfterReset();
	}
}
[HarmonyPatch(typeof(StartMatchLever), "EndGame")]
internal static class StartMatchLeverEndGamePatch
{
	[HarmonyPrefix]
	private static bool Prefix(StartMatchLever __instance)
	{
		StartOfRound playersManager = __instance.playersManager;
		if ((Object)(object)playersManager == (Object)null)
		{
			return true;
		}
		if (RemoteLeverPlugin.IsLeverLocked(playersManager))
		{
			RemoteLeverPlugin.Log.LogWarning((object)"EndGame blocked: eject/reset sequence is in progress.");
			return false;
		}
		return true;
	}
}
[HarmonyPatch(typeof(StartMatchLever), "StartGame")]
internal static class StartMatchLeverStartGamePatch
{
	[HarmonyPrefix]
	private static bool Prefix(StartMatchLever __instance)
	{
		StartOfRound playersManager = __instance.playersManager;
		if ((Object)(object)playersManager == (Object)null)
		{
			return true;
		}
		if (RemoteLeverPlugin.IsLeverLocked(playersManager))
		{
			RemoteLeverPlugin.Log.LogWarning((object)"StartGame blocked: eject/reset sequence is in progress.");
			return false;
		}
		return true;
	}
}