Decompiled source of AutoCloseDoors v1.0.0

AutoCloseDoors.dll

Decompiled 3 days 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 System.Security;
using System.Security.Permissions;
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.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("AutoCloseDoors")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+36b52aea168d77af850e89d6c8846c2f9324a51c")]
[assembly: AssemblyProduct("AutoCloseDoors")]
[assembly: AssemblyTitle("AutoCloseDoors")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 AutoCloseDoors
{
	internal static class DoorCloser
	{
		private static readonly Dictionary<Door, Coroutine> pending = new Dictionary<Door, Coroutine>();

		private const float RetryInterval = 0.25f;

		private const float RetryBudget = 2f;

		public static void Arm(Door door, float delay)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			Cancel(door);
			string prefabName = Utils.GetPrefabName(((Component)door).gameObject);
			pending[door] = ((MonoBehaviour)Plugin.Instance).StartCoroutine(CloseAfterDelay(door, delay, prefabName));
			Plugin.Log.LogDebug((object)$"{prefabName} at {((Component)door).transform.position}: armed, closes in {delay:0.##} s");
		}

		public static void Cancel(Door door)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (pending.TryGetValue(door, out var value))
			{
				if (value != null)
				{
					((MonoBehaviour)Plugin.Instance).StopCoroutine(value);
				}
				pending.Remove(door);
				Plugin.Log.LogDebug((object)$"{Utils.GetPrefabName(((Component)door).gameObject)} at {((Component)door).transform.position}: timer cancelled, closed by hand");
			}
		}

		private static IEnumerator CloseAfterDelay(Door door, float delay, string prefabName)
		{
			try
			{
				yield return (object)new WaitForSeconds(delay);
				float waited = 0f;
				while (true)
				{
					if ((Object)(object)door == (Object)null || (Object)(object)door.m_nview == (Object)null || !door.m_nview.IsValid())
					{
						Plugin.Log.LogDebug((object)(prefabName + ": door unloaded before its timer ran out, nothing to do"));
						yield break;
					}
					if (!Plugin.Enabled.Value)
					{
						yield break;
					}
					if (door.m_nview.GetZDO().GetInt(ZDOVars.s_state, 0) == 0)
					{
						Plugin.Log.LogDebug((object)$"{prefabName} at {((Component)door).transform.position}: already closed");
						yield break;
					}
					if (door.CanInteract())
					{
						break;
					}
					if (waited >= 2f)
					{
						Plugin.Log.LogDebug((object)$"{prefabName} at {((Component)door).transform.position}: gave up, still mid-animation after {2f} s");
						yield break;
					}
					waited += 0.25f;
					yield return (object)new WaitForSeconds(0.25f);
				}
				bool flag = door.m_nview.IsOwner();
				door.m_nview.InvokeRPC("UseDoor", new object[1] { false });
				Plugin.Log.LogDebug((object)$"{prefabName} at {((Component)door).transform.position}: closed (owner: {flag})");
			}
			finally
			{
				pending.Remove(door);
			}
		}
	}
	internal sealed class DoorRule
	{
		public ConfigEntry<bool> Enabled;

		public ConfigEntry<float> CloseDelay;

		public float EffectiveDelay
		{
			get
			{
				if (!(CloseDelay.Value > 0f))
				{
					return Plugin.CloseDelay.Value;
				}
				return CloseDelay.Value;
			}
		}
	}
	internal static class DoorRules
	{
		private static readonly Dictionary<string, DoorRule> rules = new Dictionary<string, DoorRule>(StringComparer.Ordinal);

		private static readonly Dictionary<string, string> displayNames = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			{ "wood_door", "Wood door" },
			{ "wood_gate", "Wood gate" },
			{ "wood_fence_gate", "Wood fence gate" },
			{ "darkwood_gate", "Darkwood gate" },
			{ "iron_grate", "Iron gate" },
			{ "stave_gate", "Stave gate" },
			{ "piece_dvergr_wood_door", "Dvergr wood door" },
			{ "piece_drawbridge", "Drawbridge" },
			{ "piece_drawbridge_log", "Log drawbridge" },
			{ "piece_hexagonal_door", "Hexagonal gate" },
			{ "flametal_gate", "Flametal gate" },
			{ "ashwood_door", "Ashwood door" },
			{ "piece_cloth_hanging_door", "Cloth hanging door" },
			{ "piece_cloth_hanging_door_blue", "Blue cloth hanging door" },
			{ "piece_cloth_hanging_door_blue2", "Blue cloth hanging door (wide)" }
		};

		public static string DisplayName(string prefabName)
		{
			if (!displayNames.TryGetValue(prefabName, out var value))
			{
				return prefabName;
			}
			return value;
		}

		public static DoorRule For(string prefabName)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			if (rules.TryGetValue(prefabName, out var value))
			{
				return value;
			}
			string text = DisplayName(prefabName);
			string text2 = ((text == prefabName) ? prefabName : (text + " (" + prefabName + ")"));
			value = new DoorRule();
			value.Enabled = Plugin.ConfigFile.Bind<bool>(prefabName, "Enabled", true, "Close " + text2 + " automatically after you open it.");
			value.CloseDelay = Plugin.ConfigFile.Bind<float>(prefabName, "CloseDelay", 0f, new ConfigDescription("Seconds before " + text2 + " closes itself. 0 uses General.CloseDelay.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>()));
			rules[prefabName] = value;
			return value;
		}

		public static void BindAll(IEnumerable<string> prefabNames)
		{
			ConfigFile configFile = Plugin.ConfigFile;
			bool saveOnConfigSet = configFile.SaveOnConfigSet;
			configFile.SaveOnConfigSet = false;
			int count = rules.Count;
			try
			{
				foreach (string prefabName in prefabNames)
				{
					For(prefabName);
				}
			}
			finally
			{
				configFile.SaveOnConfigSet = saveOnConfigSet;
			}
			if (saveOnConfigSet && rules.Count > count)
			{
				configFile.Save();
			}
		}
	}
	[BepInPlugin("rhenn.autoclosedoors", "AutoCloseDoors", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGUID = "rhenn.autoclosedoors";

		public const string PluginName = "AutoCloseDoors";

		public const string PluginVersion = "1.0.0";

		internal static Plugin Instance;

		internal static ManualLogSource Log;

		internal static ConfigFile ConfigFile;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> CloseDelay;

		private readonly Harmony harmony = new Harmony("rhenn.autoclosedoors");

		private void Awake()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigFile = ((BaseUnityPlugin)this).Config;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. Set to false and no door closes itself, whatever the door sections below say.");
			CloseDelay = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CloseDelay", 3f, new ConfigDescription("Seconds after you open a door before it closes itself. A door's own section can override it with a CloseDelay of its own.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 60f), Array.Empty<object>()));
			harmony.PatchAll(Assembly.GetExecutingAssembly());
			Log.LogInfo((object)string.Format("{0} {1} loaded. Enabled = {2}, CloseDelay = {3} s", "AutoCloseDoors", "1.0.0", Enabled.Value, CloseDelay.Value));
		}

		private void OnDestroy()
		{
			harmony.UnpatchSelf();
		}
	}
}
namespace AutoCloseDoors.Patches
{
	[HarmonyPatch(typeof(Door), "Open")]
	internal static class Door_Open_Patch
	{
		private const int Unknown = -2;

		private static void Prefix(Door __instance, out int __state)
		{
			__state = -2;
			if ((Object)(object)__instance.m_nview != (Object)null && __instance.m_nview.IsValid())
			{
				__state = __instance.m_nview.GetZDO().GetInt(ZDOVars.s_state, 0);
			}
		}

		private static void Postfix(Door __instance, int __state)
		{
			//IL_004f: 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 (!Plugin.Enabled.Value)
			{
				return;
			}
			switch (__state)
			{
			case -2:
				break;
			default:
				DoorCloser.Cancel(__instance);
				break;
			case 0:
			{
				string prefabName = Utils.GetPrefabName(((Component)__instance).gameObject);
				if ((Object)(object)__instance.m_keyItem != (Object)null || __instance.m_canNotBeClosed)
				{
					Plugin.Log.LogDebug((object)$"{prefabName} at {((Component)__instance).transform.position}: skipped, the game does not close this door again");
					break;
				}
				DoorRule doorRule = DoorRules.For(prefabName);
				if (!doorRule.Enabled.Value)
				{
					Plugin.Log.LogDebug((object)$"{prefabName} at {((Component)__instance).transform.position}: auto-close is off for this door");
				}
				else
				{
					DoorCloser.Arm(__instance, doorRule.EffectiveDelay);
				}
				break;
			}
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetScene_Awake_Patch
	{
		private static void Postfix(ZNetScene __instance)
		{
			SortedSet<string> sortedSet = new SortedSet<string>(StringComparer.Ordinal);
			foreach (GameObject prefab in __instance.m_prefabs)
			{
				if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab.GetComponent<Door>() == (Object)null))
				{
					sortedSet.Add(((Object)prefab).name);
				}
			}
			DoorRules.BindAll(sortedSet);
			Plugin.Log.LogDebug((object)string.Format("{0} door types: {1}", sortedSet.Count, string.Join(", ", sortedSet)));
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}