Decompiled source of AutoCloseDoors v0.1.9

AutoCloseDoors.dll

Decompiled a month ago
using System;
using System.Collections;
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 UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Obelisk.AutoCloseDoors;

[BepInPlugin("obelisk.valheim.autoclosedoors", "AutoCloseDoors", "0.1.9")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class AutoCloseDoorsPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "obelisk.valheim.autoclosedoors";

	public const string PluginName = "AutoCloseDoors";

	public const string PluginVersion = "0.1.9";

	private static ConfigEntry<bool> _enabled;

	private static ConfigEntry<bool> _enableInDungeons;

	private static ConfigEntry<bool> _blockMonsterDoorSensors;

	private static ConfigEntry<float> _playerRadius;

	private static ConfigEntry<int> _closeDelaySeconds;

	private Harmony _harmony;

	internal static bool IsEnabled
	{
		get
		{
			if (_enabled != null)
			{
				return _enabled.Value;
			}
			return false;
		}
	}

	internal static bool EnableInDungeons
	{
		get
		{
			if (_enableInDungeons != null)
			{
				return _enableInDungeons.Value;
			}
			return false;
		}
	}

	internal static bool BlockMonsterDoorSensors
	{
		get
		{
			if (_blockMonsterDoorSensors != null)
			{
				return _blockMonsterDoorSensors.Value;
			}
			return false;
		}
	}

	internal static float PlayerRadius
	{
		get
		{
			if (_playerRadius == null)
			{
				return 0f;
			}
			float value = _playerRadius.Value;
			if (!float.IsNaN(value) && !float.IsInfinity(value))
			{
				return Mathf.Clamp(value, 0f, 20f);
			}
			return 3f;
		}
	}

	internal static long CloseDelayMilliseconds => (long)Mathf.Clamp((_closeDelaySeconds == null) ? 5 : _closeDelaySeconds.Value, 2, 10) * 1000L;

	private void Awake()
	{
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Expected O, but got Unknown
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Expected O, but got Unknown
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Expected O, but got Unknown
		_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable automatic closing for opened doors and gates.");
		_enableInDungeons = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable in dungeons", false, "Enable automatic closing for doors located inside dungeons/interiors.");
		_blockMonsterDoorSensors = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "Block monster door sensors", true, "Prevents compatible door sensor mods from opening player-built doors for monsters.");
		_playerRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Player radius", 3f, new ConfigDescription("Door will wait again while any player is inside this radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
		_closeDelaySeconds = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Close delay seconds", 5, new ConfigDescription("Seconds before an opened door can close. Allowed range: 2-10.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 10), Array.Empty<object>()));
		_enabled.SettingChanged += OnSchedulingSettingChanged;
		_enableInDungeons.SettingChanged += OnSchedulingSettingChanged;
		_closeDelaySeconds.SettingChanged += OnSchedulingSettingChanged;
		DoorAutoCloser.Initialize(this);
		DoorAutoCloser.CacheGameMethods();
		_harmony = new Harmony("obelisk.valheim.autoclosedoors");
		_harmony.PatchAll();
		DoorAutoCloser.PatchCompatibility(_harmony);
	}

	private void OnDestroy()
	{
		if (_enabled != null)
		{
			_enabled.SettingChanged -= OnSchedulingSettingChanged;
		}
		if (_enableInDungeons != null)
		{
			_enableInDungeons.SettingChanged -= OnSchedulingSettingChanged;
		}
		if (_closeDelaySeconds != null)
		{
			_closeDelaySeconds.SettingChanged -= OnSchedulingSettingChanged;
		}
		DoorAutoCloser.Reset();
		Harmony harmony = _harmony;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		_harmony = null;
		_enabled = null;
		_enableInDungeons = null;
		_blockMonsterDoorSensors = null;
		_playerRadius = null;
		_closeDelaySeconds = null;
	}

	private static void OnSchedulingSettingChanged(object sender, EventArgs eventArgs)
	{
		DoorAutoCloser.RefreshConfiguration();
	}
}
[HarmonyPatch(typeof(Door), "Awake")]
internal static class DoorAwakePatch
{
	private static void Postfix(Door __instance)
	{
		DoorAutoCloser.OnDoorLoaded(__instance);
	}
}
[HarmonyPatch(typeof(Door), "SetState")]
internal static class DoorSetStatePatch
{
	private static void Postfix(Door __instance)
	{
		DoorAutoCloser.OnDoorStateObserved(__instance);
	}
}
internal static class DoorAutoCloser
{
	private sealed class DoorRegistration
	{
		public Door Door;

		public ZNetView View;

		public int ViewInstanceId;

		public ZDOID ZdoId;
	}

	private sealed class ScheduledDoor
	{
		public Door Door;

		public ZNetView View;

		public long NextCheckMilliseconds;
	}

	private const string CloseDoorRpcName = "Obelisk_AutoCloseDoors_V2_Close";

	private const string CloseDeadlineZdoName = "Obelisk.AutoCloseDoors.CloseDeadlineMs";

	private const long OwnershipRetryMilliseconds = 1000L;

	private const long RpcRetryMilliseconds = 1000L;

	private const long DoorStateRetryMilliseconds = 500L;

	private const float NetworkTimeRetrySeconds = 0.25f;

	private const float MinimumSchedulerWaitSeconds = 0.1f;

	private static readonly Dictionary<int, DoorRegistration> RegisteredViews = new Dictionary<int, DoorRegistration>();

	private static readonly Dictionary<ZDOID, DoorRegistration> LoadedDoors = new Dictionary<ZDOID, DoorRegistration>();

	private static readonly Dictionary<ZDOID, ScheduledDoor> ScheduledDoors = new Dictionary<ZDOID, ScheduledDoor>();

	private static readonly List<ZDOID> DueDoorIds = new List<ZDOID>();

	private static readonly List<ZDOID> RemovalDoorIds = new List<ZDOID>();

	private static readonly List<DoorRegistration> RegistrationSnapshot = new List<DoorRegistration>();

	private static AutoCloseDoorsPlugin _plugin;

	private static Coroutine _schedulerRoutine;

	private static MethodInfo _doorUpdateStateMethod;

	private static MethodInfo _doorCanInteractMethod;

	private static long _schedulerSleepUntilMilliseconds;

	private static bool _schedulerActive;

	private static bool _compatibilityPatched;

	public static void Initialize(AutoCloseDoorsPlugin plugin)
	{
		Reset();
		_plugin = plugin;
	}

	public static void CacheGameMethods()
	{
		_doorUpdateStateMethod = AccessTools.Method(typeof(Door), "UpdateState", (Type[])null, (Type[])null);
		_doorCanInteractMethod = AccessTools.Method(typeof(Door), "CanInteract", (Type[])null, (Type[])null);
	}

	public static void PatchCompatibility(Harmony harmony)
	{
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Expected O, but got Unknown
		if (!_compatibilityPatched && harmony != null)
		{
			Type type = AccessTools.TypeByName("MonsterDoorSensor");
			MethodInfo methodInfo = ((type == null) ? null : (AccessTools.Method(type, "OpenDoor", new Type[2]
			{
				typeof(Character),
				typeof(Vector3)
			}, (Type[])null) ?? AccessTools.Method(type, "OpenDoor", new Type[1] { typeof(Character) }, (Type[])null)));
			MethodInfo methodInfo2 = AccessTools.Method(typeof(MonsterDoorSensorOpenDoorPatch), "Prefix", (Type[])null, (Type[])null);
			if (!(methodInfo == null) && !(methodInfo2 == null))
			{
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_compatibilityPatched = true;
			}
		}
	}

	public static void Reset()
	{
		StopScheduler();
		RegistrationSnapshot.Clear();
		foreach (DoorRegistration value in RegisteredViews.Values)
		{
			RegistrationSnapshot.Add(value);
		}
		for (int i = 0; i < RegistrationSnapshot.Count; i++)
		{
			ZNetView view = RegistrationSnapshot[i].View;
			if ((Object)(object)view != (Object)null && view.IsValid())
			{
				view.Unregister("Obelisk_AutoCloseDoors_V2_Close");
			}
		}
		RegisteredViews.Clear();
		LoadedDoors.Clear();
		ScheduledDoors.Clear();
		DueDoorIds.Clear();
		RemovalDoorIds.Clear();
		RegistrationSnapshot.Clear();
		_plugin = null;
		_doorUpdateStateMethod = null;
		_doorCanInteractMethod = null;
		_schedulerSleepUntilMilliseconds = 0L;
		_schedulerActive = false;
		_compatibilityPatched = false;
	}

	public static void OnDoorLoaded(Door door)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_plugin == (Object)null || !IsAlive(door))
		{
			return;
		}
		ZNetView view = GetDoorView(door);
		ZDO val = (((Object)(object)view != (Object)null && view.IsValid()) ? view.GetZDO() : null);
		if (val == null)
		{
			return;
		}
		int instanceID = ((Object)view).GetInstanceID();
		ZDOID uid = val.m_uid;
		if (!RegisteredViews.TryGetValue(instanceID, out var value) || value.View != view)
		{
			if (value != null)
			{
				RemoveRegistration(value, unregisterRpc: true);
			}
			value = new DoorRegistration
			{
				Door = door,
				View = view,
				ViewInstanceId = instanceID,
				ZdoId = uid
			};
			view.Register("Obelisk_AutoCloseDoors_V2_Close", (Action<long>)delegate
			{
				HandleCloseDoorRpc(door, view);
			});
			RegisteredViews[instanceID] = value;
		}
		else
		{
			if (value.ZdoId != uid)
			{
				if (LoadedDoors.TryGetValue(value.ZdoId, out var value2) && value2 == value)
				{
					LoadedDoors.Remove(value.ZdoId);
				}
				if (ScheduledDoors.TryGetValue(value.ZdoId, out var value3) && value3.Door == value.Door)
				{
					ScheduledDoors.Remove(value.ZdoId);
				}
			}
			value.Door = door;
			value.ZdoId = uid;
		}
		LoadedDoors[uid] = value;
		DoorLifecycleRelay doorLifecycleRelay = ((Component)door).GetComponent<DoorLifecycleRelay>();
		if ((Object)(object)doorLifecycleRelay == (Object)null)
		{
			doorLifecycleRelay = ((Component)door).gameObject.AddComponent<DoorLifecycleRelay>();
		}
		doorLifecycleRelay.Initialize(door, instanceID, uid);
		OnDoorStateObserved(door);
	}

	public static void OnDoorStateObserved(Door door)
	{
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: 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_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_plugin == (Object)null || !IsAlive(door))
		{
			return;
		}
		ZNetView doorView = GetDoorView(door);
		ZDO val = (((Object)(object)doorView != (Object)null && doorView.IsValid()) ? doorView.GetZDO() : null);
		if (val == null)
		{
			ForgetDoor(door, default(ZDOID));
			return;
		}
		if (!RegisteredViews.TryGetValue(((Object)doorView).GetInstanceID(), out var value) || value.View != doorView)
		{
			OnDoorLoaded(door);
			return;
		}
		ZDOID uid = val.m_uid;
		long timeMilliseconds;
		if (!IsAutoCloseEligible(door) || !IsOpen(door, val))
		{
			if (doorView.IsOwner())
			{
				ClearDeadline(val);
			}
			ForgetDoor(door, uid);
		}
		else if (TryGetNetworkTimeMilliseconds(out timeMilliseconds))
		{
			long num = val.GetLong("Obelisk.AutoCloseDoors.CloseDeadlineMs", 0L);
			if (num <= 0 && doorView.IsOwner())
			{
				SetDeadline(door, doorView, val, timeMilliseconds + AutoCloseDoorsPlugin.CloseDelayMilliseconds);
				return;
			}
			long nextCheckTime = GetNextCheckTime(doorView, num, timeMilliseconds);
			ScheduleDoor(door, doorView, uid, nextCheckTime);
		}
	}

	public static void OnDoorDestroyed(Door door, int viewInstanceId, ZDOID zdoId)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		if (RegisteredViews.TryGetValue(viewInstanceId, out var value) && value.Door == door)
		{
			RemoveRegistration(value, unregisterRpc: true);
		}
		if (LoadedDoors.TryGetValue(zdoId, out var value2) && value2.Door == door)
		{
			LoadedDoors.Remove(zdoId);
		}
		ForgetDoor(door, zdoId);
	}

	public static void RefreshConfiguration()
	{
		if ((Object)(object)_plugin == (Object)null)
		{
			return;
		}
		RegistrationSnapshot.Clear();
		foreach (DoorRegistration value in LoadedDoors.Values)
		{
			RegistrationSnapshot.Add(value);
		}
		for (int i = 0; i < RegistrationSnapshot.Count; i++)
		{
			DoorRegistration doorRegistration = RegistrationSnapshot[i];
			if (IsAlive(doorRegistration.Door) && !((Object)(object)doorRegistration.View == (Object)null) && doorRegistration.View.IsValid())
			{
				if (doorRegistration.View.IsOwner())
				{
					ClearDeadline(doorRegistration.View.GetZDO());
				}
				OnDoorStateObserved(doorRegistration.Door);
			}
		}
		RegistrationSnapshot.Clear();
	}

	private static void HandleCloseDoorRpc(Door door, ZNetView expectedView)
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_plugin == (Object)null || !AutoCloseDoorsPlugin.IsEnabled || !IsAlive(door))
		{
			return;
		}
		ZNetView doorView = GetDoorView(door);
		if ((Object)(object)doorView == (Object)null || doorView != expectedView || !doorView.IsValid() || !doorView.IsOwner())
		{
			return;
		}
		ZDO zDO = doorView.GetZDO();
		if (zDO == null)
		{
			return;
		}
		long timeMilliseconds;
		if (!IsAutoCloseEligible(door) || !IsOpen(door, zDO))
		{
			ClearDeadline(zDO);
			ForgetDoor(door, zDO.m_uid);
		}
		else if (TryGetNetworkTimeMilliseconds(out timeMilliseconds))
		{
			long num = zDO.GetLong("Obelisk.AutoCloseDoors.CloseDeadlineMs", 0L);
			if (num <= 0)
			{
				SetDeadline(door, doorView, zDO, timeMilliseconds + AutoCloseDoorsPlugin.CloseDelayMilliseconds);
			}
			else if (num > timeMilliseconds)
			{
				ScheduleDoor(door, doorView, zDO.m_uid, num);
			}
			else if (IsAnyPlayerNear(door))
			{
				SetDeadline(door, doorView, zDO, timeMilliseconds + AutoCloseDoorsPlugin.CloseDelayMilliseconds);
			}
			else
			{
				CloseOwnedDoor(door, doorView, zDO, timeMilliseconds);
			}
		}
	}

	private static void CloseOwnedDoor(Door door, ZNetView view, ZDO zdo, long nowMilliseconds)
	{
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		if (!IsAlive(door) || (Object)(object)view == (Object)null || !view.IsValid() || !view.IsOwner() || zdo == null || !IsOpen(door, zdo))
		{
			return;
		}
		long num = zdo.GetLong("Obelisk.AutoCloseDoors.CloseDeadlineMs", 0L);
		if (num > 0 && num <= nowMilliseconds)
		{
			if (!CanInteractNow(door))
			{
				SetDeadline(door, view, zdo, nowMilliseconds + 500);
				return;
			}
			ClearDeadline(zdo);
			zdo.Set(ZDOVars.s_state, GetClosedState(door), false);
			ForgetDoor(door, zdo.m_uid);
			RefreshDoorState(door);
		}
	}

	private static void SetDeadline(Door door, ZNetView view, ZDO zdo, long deadlineMilliseconds)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		if (zdo.GetLong("Obelisk.AutoCloseDoors.CloseDeadlineMs", 0L) != deadlineMilliseconds)
		{
			zdo.Set("Obelisk.AutoCloseDoors.CloseDeadlineMs", deadlineMilliseconds);
		}
		ScheduleDoor(door, view, zdo.m_uid, deadlineMilliseconds);
	}

	private static void ClearDeadline(ZDO zdo)
	{
		if (zdo != null && zdo.GetLong("Obelisk.AutoCloseDoors.CloseDeadlineMs", 0L) != 0L)
		{
			zdo.Set("Obelisk.AutoCloseDoors.CloseDeadlineMs", 0L);
		}
	}

	private static void ScheduleDoor(Door door, ZNetView view, ZDOID zdoId, long nextCheckMilliseconds)
	{
		//IL_002c: 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)
		if (!((Object)(object)_plugin == (Object)null) && IsAlive(door) && !((Object)(object)view == (Object)null) && view.IsValid())
		{
			if (!ScheduledDoors.TryGetValue(zdoId, out var value))
			{
				value = new ScheduledDoor();
				ScheduledDoors[zdoId] = value;
			}
			value.Door = door;
			value.View = view;
			value.NextCheckMilliseconds = nextCheckMilliseconds;
			if (!_schedulerActive)
			{
				StartScheduler();
			}
			else if (_schedulerSleepUntilMilliseconds > 0 && nextCheckMilliseconds < _schedulerSleepUntilMilliseconds)
			{
				RestartScheduler();
			}
		}
	}

	private static void ForgetDoor(Door door, ZDOID zdoId)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: 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_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		if (zdoId != default(ZDOID) && ScheduledDoors.TryGetValue(zdoId, out var value) && ((Object)(object)door == (Object)null || value.Door == door))
		{
			ScheduledDoors.Remove(zdoId);
		}
		else
		{
			if (door == null)
			{
				return;
			}
			RemovalDoorIds.Clear();
			foreach (KeyValuePair<ZDOID, ScheduledDoor> scheduledDoor in ScheduledDoors)
			{
				if (scheduledDoor.Value.Door == door)
				{
					RemovalDoorIds.Add(scheduledDoor.Key);
				}
			}
			for (int i = 0; i < RemovalDoorIds.Count; i++)
			{
				ScheduledDoors.Remove(RemovalDoorIds[i]);
			}
			RemovalDoorIds.Clear();
		}
	}

	private static void RemoveRegistration(DoorRegistration registration, bool unregisterRpc)
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		if (registration != null)
		{
			if (unregisterRpc && (Object)(object)registration.View != (Object)null && registration.View.IsValid())
			{
				registration.View.Unregister("Obelisk_AutoCloseDoors_V2_Close");
			}
			if (RegisteredViews.TryGetValue(registration.ViewInstanceId, out var value) && value == registration)
			{
				RegisteredViews.Remove(registration.ViewInstanceId);
			}
			if (LoadedDoors.TryGetValue(registration.ZdoId, out var value2) && value2 == registration)
			{
				LoadedDoors.Remove(registration.ZdoId);
			}
			if (ScheduledDoors.TryGetValue(registration.ZdoId, out var value3) && value3.Door == registration.Door)
			{
				ScheduledDoors.Remove(registration.ZdoId);
			}
		}
	}

	private static void StartScheduler()
	{
		if (!((Object)(object)_plugin == (Object)null) && ScheduledDoors.Count != 0 && !_schedulerActive)
		{
			_schedulerActive = true;
			Coroutine val = ((MonoBehaviour)_plugin).StartCoroutine(SchedulerLoop());
			_schedulerRoutine = (_schedulerActive ? val : null);
		}
	}

	private static void RestartScheduler()
	{
		if (!((Object)(object)_plugin == (Object)null))
		{
			if (_schedulerRoutine != null)
			{
				((MonoBehaviour)_plugin).StopCoroutine(_schedulerRoutine);
			}
			_schedulerRoutine = null;
			_schedulerActive = false;
			_schedulerSleepUntilMilliseconds = 0L;
			StartScheduler();
		}
	}

	private static void StopScheduler()
	{
		if ((Object)(object)_plugin != (Object)null && _schedulerRoutine != null)
		{
			((MonoBehaviour)_plugin).StopCoroutine(_schedulerRoutine);
		}
		_schedulerRoutine = null;
		_schedulerActive = false;
		_schedulerSleepUntilMilliseconds = 0L;
	}

	private static IEnumerator SchedulerLoop()
	{
		try
		{
			while ((Object)(object)_plugin != (Object)null && ScheduledDoors.Count > 0)
			{
				_schedulerSleepUntilMilliseconds = 0L;
				if (!TryGetNetworkTimeMilliseconds(out var timeMilliseconds))
				{
					yield return (object)new WaitForSeconds(0.25f);
					continue;
				}
				DueDoorIds.Clear();
				foreach (KeyValuePair<ZDOID, ScheduledDoor> scheduledDoor in ScheduledDoors)
				{
					if (scheduledDoor.Value.NextCheckMilliseconds <= timeMilliseconds)
					{
						DueDoorIds.Add(scheduledDoor.Key);
					}
				}
				for (int i = 0; i < DueDoorIds.Count; i++)
				{
					ProcessScheduledDoor(DueDoorIds[i], timeMilliseconds);
				}
				DueDoorIds.Clear();
				if (ScheduledDoors.Count == 0)
				{
					break;
				}
				long num = long.MaxValue;
				foreach (ScheduledDoor value in ScheduledDoors.Values)
				{
					if (value.NextCheckMilliseconds < num)
					{
						num = value.NextCheckMilliseconds;
					}
				}
				if (!TryGetNetworkTimeMilliseconds(out timeMilliseconds))
				{
					yield return (object)new WaitForSeconds(0.25f);
					continue;
				}
				float num2 = Mathf.Max(0.1f, (float)(num - timeMilliseconds) / 1000f);
				_schedulerSleepUntilMilliseconds = timeMilliseconds + (long)(num2 * 1000f);
				yield return (object)new WaitForSeconds(num2);
			}
		}
		finally
		{
			_schedulerRoutine = null;
			_schedulerActive = false;
			_schedulerSleepUntilMilliseconds = 0L;
		}
	}

	private static void ProcessScheduledDoor(ZDOID zdoId, long nowMilliseconds)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		if (!ScheduledDoors.TryGetValue(zdoId, out var value))
		{
			return;
		}
		Door door = value.Door;
		ZNetView view = value.View;
		ZDO val = (((Object)(object)view != (Object)null && view.IsValid()) ? view.GetZDO() : null);
		if (!IsAlive(door) || val == null || val.m_uid != zdoId)
		{
			ScheduledDoors.Remove(zdoId);
			return;
		}
		if (!IsAutoCloseEligible(door) || !IsOpen(door, val))
		{
			if (view.IsOwner())
			{
				ClearDeadline(val);
			}
			ScheduledDoors.Remove(zdoId);
			return;
		}
		long num = val.GetLong("Obelisk.AutoCloseDoors.CloseDeadlineMs", 0L);
		if (!view.IsOwner())
		{
			value.NextCheckMilliseconds = ((num > nowMilliseconds) ? num : (nowMilliseconds + 1000));
			return;
		}
		if (num <= 0)
		{
			SetDeadline(door, view, val, nowMilliseconds + AutoCloseDoorsPlugin.CloseDelayMilliseconds);
			return;
		}
		if (num > nowMilliseconds)
		{
			value.NextCheckMilliseconds = num;
			return;
		}
		value.NextCheckMilliseconds = nowMilliseconds + 1000;
		view.InvokeRPC("Obelisk_AutoCloseDoors_V2_Close", Array.Empty<object>());
	}

	private static long GetNextCheckTime(ZNetView view, long deadlineMilliseconds, long nowMilliseconds)
	{
		if (deadlineMilliseconds > nowMilliseconds)
		{
			return deadlineMilliseconds;
		}
		if (!view.IsOwner())
		{
			return nowMilliseconds + 1000;
		}
		return nowMilliseconds;
	}

	private static bool TryGetNetworkTimeMilliseconds(out long timeMilliseconds)
	{
		timeMilliseconds = 0L;
		if ((Object)(object)ZNet.instance == (Object)null)
		{
			return false;
		}
		double timeSeconds = ZNet.instance.GetTimeSeconds();
		if (double.IsNaN(timeSeconds) || double.IsInfinity(timeSeconds) || timeSeconds < 0.0)
		{
			return false;
		}
		timeMilliseconds = (long)(timeSeconds * 1000.0);
		return true;
	}

	private static bool IsAutoCloseEligible(Door door)
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		if (!AutoCloseDoorsPlugin.IsEnabled || !IsAlive(door) || door.m_canNotBeClosed || (Object)(object)door.m_keyItem != (Object)null)
		{
			return false;
		}
		if (!AutoCloseDoorsPlugin.EnableInDungeons)
		{
			return !Character.InInterior(((Component)door).transform.position);
		}
		return true;
	}

	private static bool CanInteractNow(Door door)
	{
		if (_doorCanInteractMethod == null)
		{
			return false;
		}
		try
		{
			object obj = _doorCanInteractMethod.Invoke(door, null);
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}
		catch (Exception)
		{
			return false;
		}
	}

	private static void RefreshDoorState(Door door)
	{
		if (_doorUpdateStateMethod == null)
		{
			return;
		}
		try
		{
			_doorUpdateStateMethod.Invoke(door, null);
		}
		catch (Exception)
		{
		}
	}

	private static bool IsAnyPlayerNear(Door door)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		float playerRadius = AutoCloseDoorsPlugin.PlayerRadius;
		if (playerRadius > 0f && IsAlive(door))
		{
			return Player.IsPlayerInRange(((Component)door).transform.position, playerRadius);
		}
		return false;
	}

	private static bool IsOpen(Door door, ZDO zdo)
	{
		if (!IsAlive(door) || zdo == null)
		{
			return false;
		}
		return (zdo.GetInt(ZDOVars.s_state, 0) != 0) ^ door.m_invertedOpenClosedText;
	}

	private static int GetClosedState(Door door)
	{
		if (!IsAlive(door) || !door.m_invertedOpenClosedText)
		{
			return 0;
		}
		return 1;
	}

	private static ZNetView GetDoorView(Door door)
	{
		if (!IsAlive(door))
		{
			return null;
		}
		return ((Component)door).GetComponent<ZNetView>();
	}

	private static bool IsAlive(Door door)
	{
		if ((Object)(object)door != (Object)null)
		{
			return (Object)(object)((Component)door).gameObject != (Object)null;
		}
		return false;
	}
}
internal sealed class DoorLifecycleRelay : MonoBehaviour
{
	private Door _door;

	private int _viewInstanceId;

	private ZDOID _zdoId;

	public void Initialize(Door door, int viewInstanceId, ZDOID zdoId)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		_door = door;
		_viewInstanceId = viewInstanceId;
		_zdoId = zdoId;
	}

	private void OnDestroy()
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		DoorAutoCloser.OnDoorDestroyed(_door, _viewInstanceId, _zdoId);
		_door = null;
	}
}
internal static class MonsterDoorSensorOpenDoorPatch
{
	public static bool Prefix(object __instance)
	{
		if (AutoCloseDoorsPlugin.BlockMonsterDoorSensors)
		{
			return !IsPlayerBuiltDoor((Component)((__instance is Component) ? __instance : null));
		}
		return true;
	}

	private static bool IsPlayerBuiltDoor(Component sensor)
	{
		if ((Object)(object)sensor == (Object)null)
		{
			return false;
		}
		Door val = sensor.GetComponentInChildren<Door>() ?? sensor.GetComponent<Door>() ?? sensor.GetComponentInParent<Door>();
		Piece val2 = (((Object)(object)val == (Object)null) ? null : (((Component)val).GetComponent<Piece>() ?? ((Component)val).GetComponentInParent<Piece>()));
		val2 = val2 ?? sensor.GetComponent<Piece>() ?? sensor.GetComponentInParent<Piece>();
		ZNetView val3 = (((Object)(object)val == (Object)null) ? null : (((Component)val).GetComponent<ZNetView>() ?? ((Component)val).GetComponentInParent<ZNetView>()));
		val3 = val3 ?? (((Object)(object)val2 == (Object)null) ? null : (((Component)val2).GetComponent<ZNetView>() ?? ((Component)val2).GetComponentInParent<ZNetView>()));
		val3 = val3 ?? sensor.GetComponent<ZNetView>() ?? sensor.GetComponentInParent<ZNetView>();
		ZDO val4 = (((Object)(object)val3 != (Object)null && val3.IsValid()) ? val3.GetZDO() : null);
		if (val4 != null)
		{
			return val4.GetLong(ZDOVars.s_creator, 0L) != 0;
		}
		if ((Object)(object)val2 != (Object)null)
		{
			return val2.IsPlacedByPlayer();
		}
		return false;
	}
}