Decompiled source of NoDrowsyDragonDriving v1.0.0

NoDrowsyDragonDriving.dll

Decompiled 17 hours ago
using System;
using System.Diagnostics;
using System.IO;
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.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("NoDrowsyDragonDriving")]
[assembly: AssemblyDescription("Preserves saddle riding during SleepSkip vote flow.")]
[assembly: AssemblyCompany("sighsorry")]
[assembly: AssemblyProduct("NoDrowsyDragonDriving")]
[assembly: AssemblyCopyright("Copyright (c) sighsorry")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 NoDrowsyDragonDriving
{
	[BepInPlugin("sighsorry.NoDrowsyDragonDriving", "NoDrowsyDragonDriving", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class NoDrowsyDragonDrivingPlugin : BaseUnityPlugin
	{
		internal const string ModGuid = "sighsorry.NoDrowsyDragonDriving";

		internal const string ModName = "NoDrowsyDragonDriving";

		internal const string ModVersion = "1.0.0";

		private const string ConfigFileName = "sighsorry.NoDrowsyDragonDriving.cfg";

		private static readonly string ConfigFileFullPath = Path.Combine(Paths.ConfigPath, "sighsorry.NoDrowsyDragonDriving.cfg");

		internal static readonly ManualLogSource Log = Logger.CreateLogSource("NoDrowsyDragonDriving");

		internal static ConfigEntry<bool>? DetachGuardEnabled;

		internal static ConfigEntry<int>? DetachGuardGraceWindowMs;

		internal static ConfigEntry<int>? DetachGuardGraceMaxUses;

		internal static ConfigEntry<int>? DetachGuardGraceMaxFrames;

		private readonly Harmony _harmony = new Harmony("sighsorry.NoDrowsyDragonDriving");

		private FileSystemWatcher? _configWatcher;

		private DateTime _lastConfigReloadUtc = DateTime.MinValue;

		private static readonly TimeSpan ConfigReloadDebounce = TimeSpan.FromMilliseconds(250.0);

		private void Awake()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			DetachGuardEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enable Riding Detach Guard", true, "Enable/disable riding detach guard during sleep-stop flow. This setting updates live.");
			DetachGuardEnabled.SettingChanged += OnDetachGuardSettingChanged;
			DetachGuardGraceWindowMs = ((BaseUnityPlugin)this).Config.Bind<int>("1 - General", "Detach Guard Extra Window (ms)", 300, new ConfigDescription("Extra post-SleepStop guard window in milliseconds for off-stack detach calls. 0 disables.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 2000), Array.Empty<object>()));
			DetachGuardGraceWindowMs.SettingChanged += OnDetachGuardTuningChanged;
			DetachGuardGraceMaxUses = ((BaseUnityPlugin)this).Config.Bind<int>("1 - General", "Detach Guard Extra Blocks", 2, new ConfigDescription("How many detach calls can be blocked during the extra post-SleepStop window. 0 disables.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 8), Array.Empty<object>()));
			DetachGuardGraceMaxUses.SettingChanged += OnDetachGuardTuningChanged;
			DetachGuardGraceMaxFrames = ((BaseUnityPlugin)this).Config.Bind<int>("1 - General", "Detach Guard Extra Window (frames)", 6, new ConfigDescription("Maximum frame distance from SleepStop for extra off-stack guard blocks. Lower values reduce false positives.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 120), Array.Empty<object>()));
			DetachGuardGraceMaxFrames.SettingChanged += OnDetachGuardTuningChanged;
			SetupWatcher();
			_harmony.PatchAll();
			Log.LogInfo((object)"NoDrowsyDragonDriving loaded");
			Log.LogInfo((object)string.Format("{0}: guard={1}, graceWindowMs={2}, graceFrames={3}, graceBlocks={4}", "NoDrowsyDragonDriving", DetachGuardEnabled?.Value ?? true, DetachGuardGraceWindowMs?.Value ?? 0, DetachGuardGraceMaxFrames?.Value ?? 0, DetachGuardGraceMaxUses?.Value ?? 0));
		}

		private void OnDestroy()
		{
			if (DetachGuardEnabled != null)
			{
				DetachGuardEnabled.SettingChanged -= OnDetachGuardSettingChanged;
			}
			if (DetachGuardGraceWindowMs != null)
			{
				DetachGuardGraceWindowMs.SettingChanged -= OnDetachGuardTuningChanged;
			}
			if (DetachGuardGraceMaxUses != null)
			{
				DetachGuardGraceMaxUses.SettingChanged -= OnDetachGuardTuningChanged;
			}
			if (DetachGuardGraceMaxFrames != null)
			{
				DetachGuardGraceMaxFrames.SettingChanged -= OnDetachGuardTuningChanged;
			}
			_configWatcher?.Dispose();
			_harmony.UnpatchSelf();
		}

		private void SetupWatcher()
		{
			_configWatcher = new FileSystemWatcher(Paths.ConfigPath, "sighsorry.NoDrowsyDragonDriving.cfg")
			{
				IncludeSubdirectories = false,
				SynchronizingObject = ThreadingHelper.SynchronizingObject,
				EnableRaisingEvents = true
			};
			_configWatcher.Changed += ReadConfigValues;
			_configWatcher.Created += ReadConfigValues;
			_configWatcher.Renamed += ReadConfigValues;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			DateTime utcNow = DateTime.UtcNow;
			if (utcNow - _lastConfigReloadUtc < ConfigReloadDebounce)
			{
				return;
			}
			_lastConfigReloadUtc = utcNow;
			try
			{
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("NoDrowsyDragonDriving: failed to reload config. " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private void OnDetachGuardSettingChanged(object? sender, EventArgs e)
		{
			bool flag = DetachGuardEnabled?.Value ?? true;
			if (!flag)
			{
				SleepSkipRidingState.ClearDetachBlockState();
			}
			Log.LogInfo((object)("NoDrowsyDragonDriving: Riding detach guard " + (flag ? "enabled" : "disabled") + " (live update)."));
		}

		private void OnDetachGuardTuningChanged(object? sender, EventArgs e)
		{
			int num = Math.Max(0, DetachGuardGraceWindowMs?.Value ?? 0);
			int num2 = Math.Max(0, DetachGuardGraceMaxUses?.Value ?? 0);
			int num3 = Math.Max(0, DetachGuardGraceMaxFrames?.Value ?? 0);
			SleepSkipRidingState.TrimDetachGraceStateToCurrentConfig();
			Log.LogInfo((object)string.Format("{0}: Detach guard extra window updated (window={1}ms, frames={2}, blocks={3}).", "NoDrowsyDragonDriving", num, num3, num2));
		}
	}
	[HarmonyPatch]
	internal static class SleepSkipOpenMenuPatch
	{
		private const string TargetTypeName = "SleepSkip.SleepSkipPlugin";

		private const string TargetMethodName = "OpenMenuOnClient";

		private const string VoteYesRpcName = "VoteYes";

		private const string VoteNoRpcName = "VoteNo";

		private static MethodBase? TargetMethod()
		{
			return AccessTools.Method("SleepSkip.SleepSkipPlugin:OpenMenuOnClient", (Type[])null, (Type[])null);
		}

		private static bool Prefix()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return true;
			}
			if (!SleepSkipRidingState.IsPlayerRidingSaddle(localPlayer))
			{
				return true;
			}
			switch (SleepSkipRidingState.GetPopupAutoChoice())
			{
			case SleepSkipRidingState.PopupAutoChoiceSetting.AlwaysAccept:
				SleepSkipRidingState.SendVote("VoteYes");
				return false;
			case SleepSkipRidingState.PopupAutoChoiceSetting.AlwaysDecline:
				SleepSkipRidingState.SendVote("VoteNo");
				return false;
			default:
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(Game), "SleepStop")]
	internal static class GameSleepStopPatch
	{
		private static void Prefix()
		{
			SleepSkipRidingState.EnterSleepStopScope();
			if (SleepSkipRidingState.IsDetachGuardEnabled())
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null && SleepSkipRidingState.IsPlayerRidingSaddle(localPlayer))
				{
					SleepSkipRidingState.ArmDetachBlock();
				}
			}
		}

		private static Exception? Finalizer(Exception? __exception)
		{
			SleepSkipRidingState.ExitSleepStopScope();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Character), "AttachStop")]
	internal static class CharacterAttachStopPatch
	{
		private static bool Prefix(Character __instance)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			return !SleepSkipRidingState.ShouldBlockDetach();
		}
	}
	[HarmonyPatch(typeof(Player), "AttachStop")]
	internal static class PlayerAttachStopPatch
	{
		private static bool Prefix(Player __instance)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			return !SleepSkipRidingState.ShouldBlockDetach();
		}
	}
	[HarmonyPatch(typeof(Player), "StopDoodadControl")]
	internal static class PlayerStopDoodadControlPatch
	{
		private static bool Prefix(Player __instance)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			return !SleepSkipRidingState.ShouldBlockDetach();
		}
	}
	internal static class SleepSkipRidingState
	{
		internal enum PopupAutoChoiceSetting
		{
			Ask,
			AlwaysAccept,
			AlwaysDecline
		}

		private const string SleepSkipTypeName = "SleepSkip.SleepSkipPlugin";

		private const string PopupAutoChoiceFieldName = "PopupAutoChoice";

		private const double BlockTimeoutSeconds = 2.0;

		private static DateTime s_detachBlockUntilUtc = DateTime.MinValue;

		private static DateTime s_detachGraceUntilUtc = DateTime.MinValue;

		private static int s_detachGraceRemaining;

		private static DateTime s_lastSleepStopUtc = DateTime.MinValue;

		private static int s_lastSleepStopFrame = -1;

		private static int s_sleepStopScopeDepth;

		private static PropertyInfo? s_popupChoiceValueProperty;

		private static bool s_loggedPopupChoiceFieldMissing;

		private static bool s_loggedPopupChoiceReadFailed;

		private static readonly Type? SleepSkipType = AccessTools.TypeByName("SleepSkip.SleepSkipPlugin");

		private static readonly FieldInfo? PopupAutoChoiceField = ((SleepSkipType != null) ? AccessTools.Field(SleepSkipType, "PopupAutoChoice") : null);

		internal static bool IsPlayerRidingSaddle(Player player)
		{
			if (!((Character)player).IsAttached())
			{
				return false;
			}
			try
			{
				IDoodadController doodadController = player.GetDoodadController();
				return doodadController is Sadle;
			}
			catch
			{
				return false;
			}
		}

		internal static bool IsDetachGuardEnabled()
		{
			return NoDrowsyDragonDrivingPlugin.DetachGuardEnabled?.Value ?? true;
		}

		internal static void ArmDetachBlock()
		{
			if (IsDetachGuardEnabled())
			{
				DateTime dateTime = (s_lastSleepStopUtc = DateTime.UtcNow);
				s_lastSleepStopFrame = Time.frameCount;
				s_detachBlockUntilUtc = dateTime.AddSeconds(2.0);
				int num = Math.Max(0, NoDrowsyDragonDrivingPlugin.DetachGuardGraceWindowMs?.Value ?? 0);
				int num2 = Math.Max(0, NoDrowsyDragonDrivingPlugin.DetachGuardGraceMaxUses?.Value ?? 0);
				if (num > 0 && num2 > 0)
				{
					s_detachGraceUntilUtc = dateTime.AddMilliseconds(num);
					s_detachGraceRemaining = num2;
				}
				else
				{
					s_detachGraceUntilUtc = DateTime.MinValue;
					s_detachGraceRemaining = 0;
				}
			}
		}

		internal static void EnterSleepStopScope()
		{
			s_sleepStopScopeDepth++;
		}

		internal static void ExitSleepStopScope()
		{
			s_sleepStopScopeDepth = Math.Max(0, s_sleepStopScopeDepth - 1);
		}

		internal static void ClearDetachBlockState()
		{
			s_detachBlockUntilUtc = DateTime.MinValue;
			s_detachGraceUntilUtc = DateTime.MinValue;
			s_detachGraceRemaining = 0;
			s_lastSleepStopUtc = DateTime.MinValue;
			s_lastSleepStopFrame = -1;
			s_sleepStopScopeDepth = 0;
		}

		internal static void TrimDetachGraceStateToCurrentConfig()
		{
			int num = Math.Max(0, NoDrowsyDragonDrivingPlugin.DetachGuardGraceWindowMs?.Value ?? 0);
			int num2 = Math.Max(0, NoDrowsyDragonDrivingPlugin.DetachGuardGraceMaxUses?.Value ?? 0);
			if (num <= 0 || num2 <= 0)
			{
				s_detachGraceUntilUtc = DateTime.MinValue;
				s_detachGraceRemaining = 0;
			}
			else if (s_detachGraceRemaining > num2)
			{
				s_detachGraceRemaining = num2;
			}
		}

		internal static bool ShouldBlockDetach()
		{
			if (!IsDetachGuardEnabled())
			{
				return false;
			}
			DateTime utcNow = DateTime.UtcNow;
			bool flag = utcNow <= s_detachBlockUntilUtc;
			bool flag2 = utcNow <= s_detachGraceUntilUtc && s_detachGraceRemaining > 0;
			if (!flag && !flag2)
			{
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !IsPlayerRidingSaddle(localPlayer))
			{
				return false;
			}
			if (s_sleepStopScopeDepth > 0)
			{
				return true;
			}
			if (!flag2)
			{
				return false;
			}
			int frameBudget = Math.Max(0, NoDrowsyDragonDrivingPlugin.DetachGuardGraceMaxFrames?.Value ?? 0);
			if (!IsRecentSleepStop(frameBudget, utcNow))
			{
				return false;
			}
			s_detachGraceRemaining = Math.Max(0, s_detachGraceRemaining - 1);
			return true;
		}

		private static bool IsRecentSleepStop(int frameBudget, DateTime nowUtc)
		{
			if (s_lastSleepStopUtc == DateTime.MinValue || s_lastSleepStopFrame < 0)
			{
				return false;
			}
			if (nowUtc > s_detachGraceUntilUtc)
			{
				return false;
			}
			if (frameBudget <= 0)
			{
				return false;
			}
			int num = Time.frameCount - s_lastSleepStopFrame;
			if (num < 0)
			{
				return false;
			}
			return num <= frameBudget;
		}

		internal static PopupAutoChoiceSetting GetPopupAutoChoice()
		{
			if (PopupAutoChoiceField == null)
			{
				if (!s_loggedPopupChoiceFieldMissing)
				{
					s_loggedPopupChoiceFieldMissing = true;
					NoDrowsyDragonDrivingPlugin.Log.LogWarning((object)"SleepSkip PopupAutoChoice field was not found. Falling back to Ask.");
				}
				return PopupAutoChoiceSetting.Ask;
			}
			try
			{
				object value = PopupAutoChoiceField.GetValue(null);
				if (value == null)
				{
					return PopupAutoChoiceSetting.Ask;
				}
				if ((object)s_popupChoiceValueProperty == null)
				{
					s_popupChoiceValueProperty = value.GetType().GetProperty("Value");
				}
				if (s_popupChoiceValueProperty == null)
				{
					if (!s_loggedPopupChoiceReadFailed)
					{
						s_loggedPopupChoiceReadFailed = true;
						NoDrowsyDragonDrivingPlugin.Log.LogWarning((object)"SleepSkip PopupAutoChoice.Value property was not found. Falling back to Ask.");
					}
					return PopupAutoChoiceSetting.Ask;
				}
				string text = s_popupChoiceValueProperty.GetValue(value)?.ToString() ?? string.Empty;
				if (1 == 0)
				{
				}
				PopupAutoChoiceSetting result = ((text == "AlwaysAccept") ? PopupAutoChoiceSetting.AlwaysAccept : ((text == "AlwaysDecline") ? PopupAutoChoiceSetting.AlwaysDecline : PopupAutoChoiceSetting.Ask));
				if (1 == 0)
				{
				}
				return result;
			}
			catch (Exception ex)
			{
				if (!s_loggedPopupChoiceReadFailed)
				{
					s_loggedPopupChoiceReadFailed = true;
					NoDrowsyDragonDrivingPlugin.Log.LogWarning((object)("Failed to read SleepSkip PopupAutoChoice. Falling back to Ask. " + ex.GetType().Name + ": " + ex.Message));
				}
				return PopupAutoChoiceSetting.Ask;
			}
		}

		internal static void SendVote(string rpcName)
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, rpcName, new object[1] { ZNet.GetUID() });
			}
		}
	}
}