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.4")] [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.4"; private static ConfigEntry _enabled; private static ConfigEntry _enableInDungeons; private static ConfigEntry _blockMonsterDoorSensors; private static ConfigEntry _playerRadius; private static ConfigEntry _closeDelaySeconds; private Harmony _harmony; internal static bool IsEnabled => _enabled.Value; internal static bool EnableInDungeons => _enableInDungeons.Value; internal static bool BlockMonsterDoorSensors => _blockMonsterDoorSensors.Value; internal static float PlayerRadius => Mathf.Max(0f, _playerRadius.Value); internal static float CloseDelay => Mathf.Clamp(_closeDelaySeconds.Value, 2, 10); 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown _enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enable automatic closing for opened doors and gates."); _enableInDungeons = ((BaseUnityPlugin)this).Config.Bind("General", "Enable in dungeons", false, "Enable automatic closing while the local player is inside dungeons/interiors."); _blockMonsterDoorSensors = ((BaseUnityPlugin)this).Config.Bind("Compatibility", "Block monster door sensors", true, "Prevents compatible door sensor mods from opening player doors for monsters."); _playerRadius = ((BaseUnityPlugin)this).Config.Bind("General", "Player radius", 3f, new ConfigDescription("Door will wait again while any player is inside this radius.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 20f), Array.Empty())); _closeDelaySeconds = ((BaseUnityPlugin)this).Config.Bind("General", "Close delay seconds", 5, new ConfigDescription("Seconds before an opened door can close. Allowed range: 2-10.", (AcceptableValueBase)(object)new AcceptableValueRange(2, 10), Array.Empty())); DoorAutoCloser.Initialize(this); DoorAutoCloser.CacheGameMethods(); _harmony = new Harmony("obelisk.valheim.autoclosedoors"); _harmony.PatchAll(); DoorAutoCloser.PatchCompatibility(_harmony); } private void OnDestroy() { DoorAutoCloser.Reset(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } [HarmonyPatch(typeof(Door), "RPC_UseDoor")] internal static class DoorRpcUseDoorPatch { private static void Postfix(Door __instance) { DoorAutoCloser.OnDoorStateChanged(__instance); } } internal static class DoorAutoCloser { private const float LinkedDoorSearchRadius = 5f; private const float LinkedDoorMaxHeightDifference = 0.35f; private const float LinkedDoorMinDistance = 0.1f; private static readonly Dictionary OpenDoors = new Dictionary(); private static readonly List DueDoors = new List(); private static readonly List LinkedDoors = new List(); private static readonly List NearbyPieces = new List(); private static AutoCloseDoorsPlugin _plugin; private static Coroutine _checkRoutine; private static MethodInfo _playerInInteriorMethod; private static bool _compatibilityPatched; public static void Initialize(AutoCloseDoorsPlugin plugin) { _plugin = plugin; } public static void CacheGameMethods() { _playerInInteriorMethod = AccessTools.Method(typeof(Player), "InInterior", (Type[])null, (Type[])null); } public static void PatchCompatibility(Harmony harmony) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown if (!_compatibilityPatched && harmony != null) { Type type = AccessTools.TypeByName("MonsterDoorSensor"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "OpenDoor", (Type[])null, (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() { if ((Object)(object)_plugin != (Object)null && _checkRoutine != null) { ((MonoBehaviour)_plugin).StopCoroutine(_checkRoutine); } _checkRoutine = null; OpenDoors.Clear(); DueDoors.Clear(); LinkedDoors.Clear(); NearbyPieces.Clear(); } public static void OnDoorStateChanged(Door door) { if (!AutoCloseDoorsPlugin.IsEnabled || IsDungeonDisabled() || !IsOpen(door)) { Forget(door); } else { Track(door, Time.time + AutoCloseDoorsPlugin.CloseDelay, restartRoutine: true); } } private static void Track(Door door, float nextCheckTime, bool restartRoutine) { OpenDoors[door] = nextCheckTime; if (restartRoutine) { RestartCheckRoutine(); } } private static void Forget(Door door) { if (door != null) { OpenDoors.Remove(door); } } private static void RestartCheckRoutine() { if (!((Object)(object)_plugin == (Object)null)) { if (_checkRoutine != null) { ((MonoBehaviour)_plugin).StopCoroutine(_checkRoutine); } _checkRoutine = ((MonoBehaviour)_plugin).StartCoroutine(CheckOpenDoors()); } } private static IEnumerator CheckOpenDoors() { while (OpenDoors.Count > 0) { if (!AutoCloseDoorsPlugin.IsEnabled) { OpenDoors.Clear(); break; } if (IsDungeonDisabled()) { OpenDoors.Clear(); break; } float dueDoors = GetDueDoors(Time.time); if (DueDoors.Count == 0) { float num = Mathf.Max(0.1f, dueDoors - Time.time); yield return (object)new WaitForSeconds(num); continue; } for (int i = 0; i < DueDoors.Count; i++) { Door val = DueDoors[i]; if (OpenDoors.ContainsKey(val)) { CheckDoor(val); } } DueDoors.Clear(); } _checkRoutine = null; } private static float GetDueDoors(float now) { DueDoors.Clear(); float num = float.MaxValue; foreach (KeyValuePair openDoor in OpenDoors) { if (!IsOpen(openDoor.Key)) { DueDoors.Add(openDoor.Key); } else if (openDoor.Value <= now) { DueDoors.Add(openDoor.Key); } else if (openDoor.Value < num) { num = openDoor.Value; } } return num; } private static void CheckDoor(Door door) { CollectLinkedOpenDoors(door); if (LinkedDoors.Count == 0) { Forget(door); } else if (IsAnyPlayerNear(LinkedDoors)) { float nextCheckTime = Time.time + AutoCloseDoorsPlugin.CloseDelay; for (int i = 0; i < LinkedDoors.Count; i++) { Track(LinkedDoors[i], nextCheckTime, restartRoutine: false); } } else { for (int j = 0; j < LinkedDoors.Count; j++) { CloseDoor(LinkedDoors[j]); Forget(LinkedDoors[j]); } } } private static void CollectLinkedOpenDoors(Door door) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) LinkedDoors.Clear(); NearbyPieces.Clear(); if (!IsOpen(door)) { return; } LinkedDoors.Add(door); Piece.GetAllPiecesInRadius(((Component)door).transform.position, 5f, NearbyPieces); for (int i = 0; i < NearbyPieces.Count; i++) { Piece val = NearbyPieces[i]; if (!((Object)(object)val == (Object)null)) { Door component = ((Component)val).GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component == (Object)(object)door) && IsOpen(component) && IsLinkedDoor(door, component)) { LinkedDoors.Add(component); } } } } private static bool IsLinkedDoor(Door door, Door otherDoor) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_001b: 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_0022: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)door).transform; Transform transform2 = ((Component)otherDoor).transform; Vector3 position = transform.position; Vector3 position2 = transform2.position; if (Mathf.Abs(position.y - position2.y) > 0.35f) { return false; } Vector3 val = position2 - position; val.y = 0f; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < 0.1f || magnitude > 5f) { return false; } Vector3 val2 = val / magnitude; Vector3 val3 = Horizontal(transform.right); Vector3 val4 = Horizontal(transform2.right); Vector3 val5 = Horizontal(transform.forward); Vector3 val6 = Horizontal(transform2.forward); if (val3 == Vector3.zero || val4 == Vector3.zero || val5 == Vector3.zero || val6 == Vector3.zero) { return false; } ((Vector3)(ref val3)).Normalize(); ((Vector3)(ref val4)).Normalize(); ((Vector3)(ref val5)).Normalize(); ((Vector3)(ref val6)).Normalize(); bool num = Mathf.Abs(Vector3.Dot(val2, val3)) >= 0.75f; bool flag = Vector3.Dot(val3, val4) <= -0.75f || Vector3.Dot(val5, val6) <= -0.75f; bool flag2 = Vector3.Dot(val3, val4) >= 0.75f && Vector3.Dot(val5, val6) >= 0.75f; if (num) { return flag || flag2; } return false; } private static bool IsAnyPlayerNear(List doors) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) float playerRadius = AutoCloseDoorsPlugin.PlayerRadius; for (int i = 0; i < doors.Count; i++) { if (Player.IsPlayerInRange(((Component)doors[i]).transform.position, playerRadius)) { return true; } } return false; } private static void CloseDoor(Door door) { if (!IsOpen(door)) { return; } ZNetView doorView = GetDoorView(door); if (!((Object)(object)doorView == (Object)null) && doorView.IsValid()) { if (!doorView.IsOwner()) { doorView.ClaimOwnership(); } doorView.GetZDO().Set(ZDOVars.s_state, 0, false); } } private static bool IsOpen(Door door) { ZNetView doorView = GetDoorView(door); if ((Object)(object)doorView == (Object)null || !doorView.IsValid()) { return false; } return doorView.GetZDO().GetInt(ZDOVars.s_state, 0) != 0; } private static ZNetView GetDoorView(Door door) { if (door == null) { return null; } return ((Component)door).GetComponent(); } private static bool IsDungeonDisabled() { if (AutoCloseDoorsPlugin.EnableInDungeons) { return false; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || _playerInInteriorMethod == null) { return false; } return (bool)_playerInInteriorMethod.Invoke(localPlayer, null); } private static Vector3 Horizontal(Vector3 vector) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) vector.y = 0f; return vector; } } internal static class MonsterDoorSensorOpenDoorPatch { public static bool Prefix() { return !AutoCloseDoorsPlugin.BlockMonsterDoorSensors; } }