Decompiled source of AutoDoors v1.0.13

AutoDoors.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
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: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AutoDoors")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("AutoDoors")]
[assembly: AssemblyTitle("AutoDoors")]
[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 AutoDoors
{
	[BepInPlugin("zenox.autodoors", "AutoDoors", "1.0.12")]
	public class AutoDoorsPlugin : BaseUnityPlugin
	{
		private class DoorTracking
		{
			public bool WasInRange;

			public bool OpenedByMod;

			public bool IsManual;

			public bool WasOpenLastTick;

			public float OutOfRangeTimer;

			public bool SuppressNextEffect;

			public List<Door> Partners;

			public float PartnersLastScanned = -999f;

			public float LastCloseSuppressLogTime = -999f;
		}

		[HarmonyPatch(typeof(Door), "UpdateState")]
		private static class Door_UpdateState_Patch
		{
			private static void Postfix(Door __instance)
			{
				if ((Object)(object)Instance != (Object)null)
				{
					Instance.RegisterDoor(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Door), "SetState")]
		private static class Door_SetState_MuteSound_Patch
		{
			private static readonly FieldInfo AnimatorField = AccessTools.Field(typeof(Door), "m_animator");

			private static bool Prefix(Door __instance, int state)
			{
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Expected O, but got Unknown
				if ((Object)(object)Instance == (Object)null || !Instance.trackedDoors.TryGetValue(__instance, out var value) || !value.SuppressNextEffect)
				{
					return true;
				}
				value.SuppressNextEffect = false;
				Animator val = (Animator)AnimatorField.GetValue(__instance);
				if (val.GetInteger("state") != state)
				{
					val.SetInteger("state", state);
				}
				if ((Object)(object)__instance.m_openEnable != (Object)null)
				{
					__instance.m_openEnable.SetActive(state != 0);
				}
				return false;
			}
		}

		public const string PluginGUID = "zenox.autodoors";

		public const string PluginName = "AutoDoors";

		public const string PluginVersion = "1.0.12";

		public static AutoDoorsPlugin Instance;

		public static ConfigEntry<bool> ModEnabled;

		public static ConfigEntry<float> RangeMultiplier;

		public static ConfigEntry<float> UpdateInterval;

		public static ConfigEntry<bool> IgnoreLockedDoors;

		public static ConfigEntry<float> CloseDelaySeconds;

		public static ConfigEntry<bool> RequireFacingDoor;

		public static ConfigEntry<float> FacingAngleThreshold;

		public static ConfigEntry<bool> MuteAutoDoorSound;

		public static ConfigEntry<bool> PairDoubleDoors;

		public static ConfigEntry<float> MaxPairDistance;

		private readonly Harmony harmony = new Harmony("zenox.autodoors");

		private readonly Dictionary<Door, DoorTracking> trackedDoors = new Dictionary<Door, DoorTracking>();

		private float timeSinceLastCheck;

		private readonly Dictionary<Door, (int state, bool inRange, bool facingOk)> tickData = new Dictionary<Door, (int, bool, bool)>();

		private void Awake()
		{
			Instance = this;
			ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable/disable automatic opening and closing of doors and gates.");
			RangeMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "RangeMultiplier", 1f, "Multiplier applied to the player's normal interaction distance to decide how close you need to be for a door to open automatically.");
			UpdateInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "UpdateInterval", 0.1f, "Minimum time in seconds between range checks. Lower = more responsive, higher = better performance.");
			IgnoreLockedDoors = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "IgnoreLockedDoors", true, "If true, doors that require a key are left alone (you still need to unlock them by hand).");
			CloseDelaySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CloseDelaySeconds", 0.5f, "Seconds to wait after leaving range before auto-closing a door. 0 = close immediately (original behavior).");
			RequireFacingDoor = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RequireFacingDoor", true, "If true, doors only auto-open when you're roughly walking/facing towards them - prevents every door in a hallway opening at once just from being in range.");
			FacingAngleThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("General", "FacingAngleThreshold", 45f, "Half-angle in degrees from your camera/crosshair direction still counted as 'facing' the door. Only used if RequireFacingDoor is true. Lower = stricter (must look more directly at it).");
			MuteAutoDoorSound = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "MuteAutoDoorSound", false, "If true, suppresses the door's open/close sound and particle effect when triggered automatically by this mod. Doors opened/closed by hand still play the normal sound.");
			PairDoubleDoors = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PairDoubleDoors", true, "If true, two door pieces snapped close together (a double door) are treated as one unit: if either half would open, both open; both only close once neither half is in range/facing anymore.");
			MaxPairDistance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MaxPairDistance", 2.5f, "Max gap in meters between two door/gate pieces (measured between their own edges, not their pivots) to be treated as a double-door pair. Only used if PairDoubleDoors is true.");
			harmony.PatchAll(Assembly.GetExecutingAssembly());
			((BaseUnityPlugin)this).Logger.LogInfo((object)"AutoDoors v1.0.12 loaded.");
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		internal void RegisterDoor(Door door)
		{
			if (!trackedDoors.ContainsKey(door))
			{
				trackedDoors[door] = new DoorTracking();
			}
		}

		private void Update()
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Unknown result type (might be due to invalid IL or missing references)
			if (!ModEnabled.Value)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead())
			{
				return;
			}
			timeSinceLastCheck += Time.deltaTime;
			if (timeSinceLastCheck < UpdateInterval.Value)
			{
				return;
			}
			timeSinceLastCheck = 0f;
			float num = localPlayer.m_maxInteractDistance * RangeMultiplier.Value;
			float radiusSq = num * num;
			Vector3 playerPos = ((Component)localPlayer).transform.position;
			List<Door> list = null;
			tickData.Clear();
			foreach (KeyValuePair<Door, DoorTracking> trackedDoor in trackedDoors)
			{
				Door key = trackedDoor.Key;
				DoorTracking value = trackedDoor.Value;
				if ((Object)(object)key == (Object)null)
				{
					(list ?? (list = new List<Door>())).Add(key);
					continue;
				}
				ZNetView component = ((Component)key).GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || !component.IsValid())
				{
					continue;
				}
				ZDO zDO = component.GetZDO();
				int num2 = zDO.GetInt("state", 0);
				if (IgnoreLockedDoors.Value && (Object)(object)key.m_keyItem != (Object)null)
				{
					continue;
				}
				if (PairDoubleDoors.Value)
				{
					ScanForPartners(key, value);
				}
				bool flag = Vector3.SqrMagnitude(((Component)key).transform.position - playerPos) <= radiusSq;
				if (flag)
				{
					if (!value.WasInRange)
					{
						if (num2 != 0 && !value.OpenedByMod)
						{
							value.IsManual = true;
						}
						else
						{
							value.IsManual = false;
						}
					}
					else if (value.OpenedByMod && value.WasOpenLastTick && num2 == 0)
					{
						value.IsManual = true;
						value.OpenedByMod = false;
					}
				}
				else if (num2 == 0)
				{
					value.OpenedByMod = false;
					value.IsManual = false;
				}
				bool flag2 = value.Partners != null && value.Partners.Exists((Door p) => (Object)(object)p != (Object)null && Vector3.SqrMagnitude(((Component)p).transform.position - playerPos) <= radiusSq);
				if (flag || flag2)
				{
					value.OutOfRangeTimer = 0f;
				}
				else
				{
					value.OutOfRangeTimer += UpdateInterval.Value;
				}
				bool item = true;
				if (RequireFacingDoor.Value)
				{
					Vector3 val = ((Component)key).transform.position - playerPos;
					if (((Vector3)(ref val)).sqrMagnitude > 0.01f && (Object)(object)GameCamera.instance != (Object)null)
					{
						float num3 = Vector3.Dot(((Component)GameCamera.instance).transform.forward, ((Vector3)(ref val)).normalized);
						float num4 = Mathf.Cos(FacingAngleThreshold.Value * (MathF.PI / 180f));
						item = num3 >= num4;
					}
				}
				tickData[key] = (num2, flag, item);
				value.WasOpenLastTick = num2 != 0;
				value.WasInRange = flag;
			}
			foreach (KeyValuePair<Door, (int, bool, bool)> tickDatum in tickData)
			{
				Door key2 = tickDatum.Key;
				(int, bool, bool) value2 = tickDatum.Value;
				int item2 = value2.Item1;
				bool item3 = value2.Item2;
				bool item4 = value2.Item3;
				DoorTracking doorTracking = trackedDoors[key2];
				(int, bool, bool) value3;
				bool flag3 = doorTracking.Partners != null && doorTracking.Partners.Exists((Door p) => tickData.TryGetValue(p, out value3) && value3.Item2);
				if (item3 || flag3)
				{
					bool flag4 = item2 == 0 && item4;
					bool flag5 = doorTracking.Partners != null && doorTracking.Partners.Exists((Door p) => tickData.TryGetValue(p, out value3) && value3.Item1 == 0 && value3.Item2 && value3.Item3);
					if (!doorTracking.IsManual && item2 == 0 && (flag4 || flag5))
					{
						if (MuteAutoDoorSound.Value)
						{
							doorTracking.SuppressNextEffect = true;
						}
						if (flag5 && !flag4)
						{
							((BaseUnityPlugin)this).Logger.LogInfo((object)("[AutoDoors] Door '" + ((Object)key2).name + "' opened because a paired partner door wants to open (this door's own facing/range check didn't pass)."));
						}
						key2.Interact((Humanoid)(object)localPlayer, false, false);
						doorTracking.OpenedByMod = true;
					}
					continue;
				}
				bool flag6 = doorTracking.Partners == null || doorTracking.Partners.TrueForAll((Door p) => !tickData.TryGetValue(p, out value3) || !value3.Item2);
				if (doorTracking.IsManual || !doorTracking.OpenedByMod || item2 == 0 || !(doorTracking.OutOfRangeTimer >= CloseDelaySeconds.Value))
				{
					continue;
				}
				if (!flag6)
				{
					if (Time.time - doorTracking.LastCloseSuppressLogTime > 3f)
					{
						doorTracking.LastCloseSuppressLogTime = Time.time;
						((BaseUnityPlugin)this).Logger.LogInfo((object)("[AutoDoors] Door '" + ((Object)key2).name + "' close suppressed - a paired partner door is still in range."));
					}
				}
				else
				{
					if (MuteAutoDoorSound.Value)
					{
						doorTracking.SuppressNextEffect = true;
					}
					key2.Interact((Humanoid)(object)localPlayer, false, false);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (Door item5 in list)
			{
				trackedDoors.Remove(item5);
			}
		}

		private void ScanForPartners(Door door, DoorTracking tracking)
		{
			//IL_013f: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			if ((tracking.Partners != null && tracking.Partners.Count > 0) || Time.time - tracking.PartnersLastScanned < 5f)
			{
				return;
			}
			tracking.PartnersLastScanned = Time.time;
			float horizontalHalfWidth = GetHorizontalHalfWidth(door);
			List<Door> list = null;
			foreach (KeyValuePair<Door, DoorTracking> trackedDoor in trackedDoors)
			{
				Door key = trackedDoor.Key;
				if (!((Object)(object)key == (Object)null) && !((Object)(object)key == (Object)(object)door))
				{
					float num = Vector3.Distance(((Component)key).transform.position, ((Component)door).transform.position);
					float num2 = num - horizontalHalfWidth - GetHorizontalHalfWidth(key);
					if (num2 <= MaxPairDistance.Value)
					{
						(list ?? (list = new List<Door>())).Add(key);
					}
				}
			}
			if (list != null)
			{
				tracking.Partners = list;
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[AutoDoors] Paired door '{((Object)door).name}' at {((Component)door).transform.position} with {list.Count} partner(s) (gap <= {MaxPairDistance.Value}m).");
			}
		}

		private static float GetHorizontalHalfWidth(Door door)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			Collider componentInChildren = ((Component)door).GetComponentInChildren<Collider>();
			if ((Object)(object)componentInChildren == (Object)null)
			{
				return 0f;
			}
			Bounds bounds = componentInChildren.bounds;
			Vector3 size = ((Bounds)(ref bounds)).size;
			return Mathf.Max(size.x, size.z) * 0.5f;
		}
	}
}