Decompiled source of Stoneveil v0.4.4

plugins/Stoneveil/Stoneveil.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Stoneveil")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.4.0")]
[assembly: AssemblyInformationalVersion("0.4.4")]
[assembly: AssemblyProduct("Stoneveil")]
[assembly: AssemblyTitle("Stoneveil")]
[assembly: AssemblyVersion("0.4.4.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 Secret
{
	internal sealed class AutomaticCloseRequest
	{
		private bool pending;

		private float expires;

		private float nextAttempt;

		internal void Request(float now)
		{
			if (!pending)
			{
				pending = true;
				expires = now + 60f;
				nextAttempt = now;
			}
		}

		internal void Cancel()
		{
			pending = false;
		}

		internal bool ShouldAttempt(float now, bool owner, DoorState state)
		{
			if (!owner || !state.Enabled || !state.Open || now >= expires)
			{
				Cancel();
				return false;
			}
			if (!pending || now < nextAttempt)
			{
				return false;
			}
			nextAttempt = now + 0.25f;
			return true;
		}

		internal static bool AcceptRpc(long sender, long owner, bool isOwner, DoorState state)
		{
			if (isOwner && sender == owner && state.Enabled)
			{
				return state.Open;
			}
			return false;
		}

		internal static bool AcceptStateWrite(int observed, int published, bool isOwner, DoorState state)
		{
			if (isOwner && state.Enabled && state.Open && observed == 0)
			{
				return published != 0;
			}
			return false;
		}

		internal static int NativeState(DoorState state)
		{
			if (!state.Enabled || !state.Open)
			{
				return 0;
			}
			return 1;
		}
	}
	internal enum DoorCommand
	{
		Convert,
		Remove,
		Toggle,
		CycleMotion,
		Reverse,
		ToggleConcealment
	}
	internal enum DoorMotion
	{
		HingeLeft,
		HingeRight,
		SlideLeft,
		SlideRight
	}
	internal enum PanelKind
	{
		Wall,
		Hatch
	}
	internal readonly struct DoorState
	{
		private const int EnabledBit = 1;

		private const int OpenBit = 2;

		private const int ConcealedBit = 4;

		private const int ReverseBit = 8;

		private const int StackedStoneBit = 64;

		internal readonly int Value;

		internal bool Enabled => (Value & 1) != 0;

		internal bool Open => (Value & 2) != 0;

		internal bool Concealed => (Value & 4) != 0;

		internal bool Reverse => (Value & 8) != 0;

		internal bool StackedStone => (Value & 0x40) != 0;

		internal DoorMotion Motion => (DoorMotion)((Value >> 4) & 3);

		internal DoorState(int value)
		{
			Value = ((value >= 0 && value <= 127 && (value == 0 || (value & 1) != 0)) ? value : 0);
		}

		internal DoorState Apply(DoorCommand command, bool stackStone = false)
		{
			switch (command)
			{
			case DoorCommand.Convert:
				if (!Enabled)
				{
					return new DoorState(1 | (stackStone ? 64 : 0));
				}
				return this;
			case DoorCommand.Remove:
				return new DoorState(0);
			default:
				if (!Enabled)
				{
					return this;
				}
				switch (command)
				{
				case DoorCommand.Toggle:
					return new DoorState(Value ^ 2);
				case DoorCommand.ToggleConcealment:
					return new DoorState(Value ^ 4);
				case DoorCommand.Reverse:
					if (!Open)
					{
						return new DoorState(Value ^ 8);
					}
					break;
				case DoorCommand.CycleMotion:
					if (!Open)
					{
						return new DoorState((Value & -49) | ((int)(Motion + 1) % 4 << 4));
					}
					break;
				}
				return this;
			}
		}
	}
	internal static class GameAccess
	{
		internal static readonly Func<Player, bool> TakeInput = AccessTools.MethodDelegate<Func<Player, bool>>(AccessTools.Method(typeof(Player), "TakeInput", (Type[])null, (Type[])null), (object)null, true);

		internal static readonly Action<WearNTear> SetupColliders = AccessTools.MethodDelegate<Action<WearNTear>>(AccessTools.Method(typeof(WearNTear), "SetupColliders", (Type[])null, (Type[])null), (object)null, true);

		private static readonly FieldRef<List<PrivateArea>> Areas = AccessTools.StaticFieldRefAccess<List<PrivateArea>>(AccessTools.Field(typeof(PrivateArea), "m_allAreas"));

		private static readonly Func<PrivateArea, bool> IsEnabled = AccessTools.MethodDelegate<Func<PrivateArea, bool>>(AccessTools.Method(typeof(PrivateArea), "IsEnabled", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<PrivateArea, Vector3, float, bool> IsInside = AccessTools.MethodDelegate<Func<PrivateArea, Vector3, float, bool>>(AccessTools.Method(typeof(PrivateArea), "IsInside", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<PrivateArea, long, bool> IsPermitted = AccessTools.MethodDelegate<Func<PrivateArea, long, bool>>(AccessTools.Method(typeof(PrivateArea), "IsPermitted", (Type[])null, (Type[])null), (object)null, true);

		internal static Player ResolveSender(long sender)
		{
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				ZNetView component = ((Component)allPlayer).GetComponent<ZNetView>();
				if (Object.op_Implicit((Object)(object)component) && component.IsValid() && component.GetZDO().GetOwner() == sender)
				{
					return allPlayer;
				}
			}
			return null;
		}

		internal static bool HasWardAccess(Vector3 point, long playerId)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			foreach (PrivateArea item in Areas.Invoke())
			{
				if (Object.op_Implicit((Object)(object)item) && IsEnabled(item) && IsInside(item, point, 0f))
				{
					flag = true;
					if (((Component)item).GetComponent<Piece>().GetCreator() == playerId || IsPermitted(item, playerId))
					{
						return true;
					}
				}
			}
			return !flag;
		}
	}
	internal static class LinkedSwitchAccess
	{
		private static readonly HashSet<int> SwitchPrefabs = new HashSet<int>
		{
			StringExtensionMethods.GetStableHashCode("doorswitch_wood"),
			StringExtensionMethods.GetStableHashCode("doorswitch_iron"),
			StringExtensionMethods.GetStableHashCode("doorswitch_rune"),
			StringExtensionMethods.GetStableHashCode("doorswitch_bookshelf")
		};

		internal static bool CanUse(Player player, ZDO source, ZDO target, bool open)
		{
			return GetDenialReason(player, source, target, open) == null;
		}

		internal static string GetDenialReason(Player player, ZDO source, ZDO target, bool open)
		{
			return GetLinkDenialReason(source, target, open) ?? GetInteractionDenialReason(player, source, target, open);
		}

		internal static string GetLinkDenialReason(ZDO source, ZDO target, bool open)
		{
			string targetDenialReason = GetTargetDenialReason(source, target, open);
			if (targetDenialReason != null)
			{
				return targetDenialReason;
			}
			if (!LinkedSwitchPolicy.HasReference(source.GetString("doorswitch_links", ""), target.GetString("latchlink_identity", "")))
			{
				return "The switch's link to this door is missing on this peer";
			}
			return null;
		}

		internal static string GetInteractionDenialReason(Player player, ZDO source, ZDO target, bool open)
		{
			//IL_002b: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)player))
			{
				return "The requesting player is not loaded";
			}
			if (((Character)player).IsDead())
			{
				return "The requesting player is dead";
			}
			string targetDenialReason = GetTargetDenialReason(source, target, open);
			if (targetDenialReason != null)
			{
				return targetDenialReason;
			}
			if (!GameAccess.HasWardAccess(source.GetPosition(), player.GetPlayerID()))
			{
				return "Ward access denied at the linked switch";
			}
			if (!GameAccess.HasWardAccess(target.GetPosition(), player.GetPlayerID()))
			{
				return "Ward access denied at the door";
			}
			int mode = source.GetInt("doorswitch_mode", 0);
			float num = Vector3.Distance(((Component)player).transform.position, source.GetPosition());
			if (!LinkedSwitchPolicy.Allows(mode, open, num, player.m_maxInteractDistance, linked: true, permitted: true, enabled: true))
			{
				return $"Too far from the linked switch ({num:0.0} m; limit {player.m_maxInteractDistance + 2f:0.0} m)";
			}
			return null;
		}

		private static string GetTargetDenialReason(ZDO source, ZDO target, bool open)
		{
			if (source == null)
			{
				return "The linked switch data is not available on this peer";
			}
			if (target == null)
			{
				return "The door data is not available on this peer";
			}
			if (!Chainloader.PluginInfos.ContainsKey("com.tomtom.latchlink"))
			{
				return "LatchLink is not loaded on this peer";
			}
			if (!SwitchPrefabs.Contains(source.GetPrefab()))
			{
				return "The request source is not a LatchLink switch";
			}
			if (!new DoorState(target.GetInt("com.tomtom.secret.state.v1", 0)).Enabled)
			{
				return "This panel's Stoneveil hinge is disabled";
			}
			int num = source.GetInt("doorswitch_mode", 0);
			if (num < 0 || num > 2)
			{
				return "The linked switch has an invalid mode";
			}
			if ((num == 1 && !open) || (num == 2 && open))
			{
				return "The requested action conflicts with the switch mode";
			}
			return null;
		}
	}
	internal static class LinkedSwitchPolicy
	{
		internal static bool HasReference(string references, string identity)
		{
			if (!Guid.TryParseExact(identity, "N", out var _))
			{
				return false;
			}
			string[] array = (references ?? "").Split(';');
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i] == "g:" + identity)
				{
					return true;
				}
			}
			return false;
		}

		internal static bool Allows(int mode, bool open, float playerDistance, float interactDistance, bool linked, bool permitted, bool enabled)
		{
			if (enabled && linked && permitted && playerDistance >= 0f && interactDistance >= 0f && !float.IsInfinity(playerDistance) && !float.IsInfinity(interactDistance) && playerDistance <= interactDistance + 2f)
			{
				if (mode != 0 && !(mode == 1 && open))
				{
					if (mode == 2)
					{
						return !open;
					}
					return false;
				}
				return true;
			}
			return false;
		}
	}
	internal static class LinkedSwitchRpc
	{
		private sealed class Pending
		{
			internal SecretDoor Door;

			internal long Player;

			internal ZDOID Source;

			internal ZDOID Target;

			internal bool Open;

			internal float Expires;
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static CoroutineHandler <0>__OnServerReceive;

			public static CoroutineHandler <1>__OnClientReceive;
		}

		private const byte Request = 0;

		private const byte Response = 1;

		private static CustomRPC rpc;

		private static readonly Dictionary<long, Pending> Requests = new Dictionary<long, Pending>();

		private static long nextRequest;

		private static float nextCleanup;

		private static ZNet session;

		internal static void Initialize()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			NetworkManager instance = NetworkManager.Instance;
			object obj = <>O.<0>__OnServerReceive;
			if (obj == null)
			{
				CoroutineHandler val = OnServerReceive;
				<>O.<0>__OnServerReceive = val;
				obj = (object)val;
			}
			object obj2 = <>O.<1>__OnClientReceive;
			if (obj2 == null)
			{
				CoroutineHandler val2 = OnClientReceive;
				<>O.<1>__OnClientReceive = val2;
				obj2 = (object)val2;
			}
			rpc = instance.AddRPC("Stoneveil_LinkAuthorization", (CoroutineHandler)obj, (CoroutineHandler)obj2);
		}

		internal static void Authorize(SecretDoor door, long player, ZDOID source, ZDOID target, bool open)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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)
			//IL_00ab: 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)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			Update();
			long server = GetServer();
			if (rpc == null || server == 0L || Requests.Count >= 256)
			{
				door.CompleteSwitchAuthorization(player, source, target, open, "Switch authorization is unavailable; try again");
				return;
			}
			foreach (Pending value in Requests.Values)
			{
				if ((Object)(object)value.Door == (Object)(object)door)
				{
					return;
				}
			}
			long num = ++nextRequest;
			Requests.Add(num, new Pending
			{
				Door = door,
				Player = player,
				Source = source,
				Target = target,
				Open = open,
				Expires = Time.unscaledTime + 5f
			});
			ZPackage val = new ZPackage();
			val.Write((byte)0);
			val.Write(num);
			val.Write(source);
			val.Write(target);
			val.Write(open);
			rpc.SendPackage(server, val);
		}

		private static IEnumerator OnServerReceive(long sender, ZPackage package)
		{
			byte b = package.ReadByte();
			if (b == 1 && sender == ZNet.GetUID())
			{
				ReceiveResponse(package);
			}
			else if (b == 0 && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				long num = package.ReadLong();
				ZDOMan instance = ZDOMan.instance;
				ZDO source = ((instance != null) ? instance.GetZDO(package.ReadZDOID()) : null);
				ZDOMan instance2 = ZDOMan.instance;
				ZDO val = ((instance2 != null) ? instance2.GetZDO(package.ReadZDOID()) : null);
				bool open = package.ReadBool();
				string text = ((val == null || val.GetOwner() != sender) ? "Door ownership changed while authorizing the switch; try again" : LinkedSwitchAccess.GetLinkDenialReason(source, val, open));
				ZPackage val2 = new ZPackage();
				val2.Write((byte)1);
				val2.Write(num);
				val2.Write(text ?? "");
				rpc.SendPackage(sender, val2);
			}
			yield break;
		}

		private static IEnumerator OnClientReceive(long sender, ZPackage package)
		{
			long server = GetServer();
			if (server != 0L && sender == server && package.ReadByte() == 1)
			{
				ReceiveResponse(package);
			}
			yield break;
		}

		private static void ReceiveResponse(ZPackage package)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			long key = package.ReadLong();
			string text = package.ReadString();
			if (!Requests.TryGetValue(key, out var value))
			{
				return;
			}
			Requests.Remove(key);
			if (Object.op_Implicit((Object)(object)value.Door))
			{
				if (Time.unscaledTime >= value.Expires)
				{
					text = "Switch authorization timed out; try again";
				}
				value.Door.CompleteSwitchAuthorization(value.Player, value.Source, value.Target, value.Open, string.IsNullOrEmpty(text) ? null : text);
			}
		}

		private static long GetServer()
		{
			if (!((Object)(object)ZNet.instance == (Object)null))
			{
				if (!ZNet.instance.IsServer())
				{
					return ZNet.instance.GetServerPeer()?.m_uid ?? 0;
				}
				return ZNet.GetUID();
			}
			return 0L;
		}

		internal static void Update()
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)session != (Object)(object)ZNet.instance)
			{
				Requests.Clear();
				session = ZNet.instance;
				nextCleanup = 0f;
			}
			if (Time.unscaledTime < nextCleanup)
			{
				return;
			}
			nextCleanup = Time.unscaledTime + 1f;
			List<long> list = new List<long>();
			foreach (KeyValuePair<long, Pending> request in Requests)
			{
				if (!Object.op_Implicit((Object)(object)request.Value.Door) || Time.unscaledTime >= request.Value.Expires)
				{
					list.Add(request.Key);
				}
			}
			foreach (long item in list)
			{
				Pending pending = Requests[item];
				Requests.Remove(item);
				if (Object.op_Implicit((Object)(object)pending.Door))
				{
					pending.Door.CompleteSwitchAuthorization(pending.Player, pending.Source, pending.Target, pending.Open, "Switch authorization timed out; try again");
				}
			}
		}
	}
	public sealed class StoneveilDoor : Door
	{
		public bool InteractFromSwitch(Humanoid user, ZDOID switchId, bool open)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			return NativeDoorAdapter.Panel((Door)(object)this)?.InteractFromSwitch(user, switchId, open) ?? false;
		}

		public string GetSwitchFailure()
		{
			return NativeDoorAdapter.Panel((Door)(object)this)?.LastSwitchFailure;
		}

		private void Awake()
		{
			Piece component = ((Component)this).GetComponent<Piece>();
			if (Object.op_Implicit((Object)(object)component))
			{
				base.m_name = component.m_name;
			}
			NativeDoorAdapter.AwakeMethod.Invoke(this, null);
		}

		private void UpdateState()
		{
			NativeDoorAdapter.UpdateMethod.Invoke(this, null);
		}
	}
	internal static class NativeDoorAdapter
	{
		internal static readonly MethodInfo AwakeMethod = AccessTools.Method(typeof(Door), "Awake", (Type[])null, (Type[])null);

		internal static readonly MethodInfo UpdateMethod = AccessTools.Method(typeof(Door), "UpdateState", (Type[])null, (Type[])null);

		private static readonly MethodInfo UseMethod = AccessTools.Method(typeof(Door), "RPC_UseDoor", (Type[])null, (Type[])null);

		internal static void Use(Door door, long sender)
		{
			UseMethod.Invoke(door, new object[2] { sender, false });
		}

		internal static SecretDoor Panel(Door door)
		{
			if (!(door is StoneveilDoor))
			{
				return null;
			}
			return ((Component)door).GetComponent<SecretDoor>();
		}

		internal static void LogInteractionPatches()
		{
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)AccessTools.Method(typeof(Door), "Interact", (Type[])null, (Type[])null));
			if (patchInfo != null)
			{
				SecretPlugin.Warn("Door.Interact prefixes: " + string.Join(", ", patchInfo.Prefixes.Select((Patch p) => p.owner + ":" + p.PatchMethod.DeclaringType?.FullName + "." + p.PatchMethod.Name)));
			}
		}
	}
	[HarmonyPatch(typeof(Door), "UpdateState")]
	internal static class NativeDoorUpdatePatch
	{
		private static void Prefix(Door __instance)
		{
			NativeDoorAdapter.Panel(__instance)?.PollNativeState();
		}
	}
	[HarmonyPatch(typeof(Door), "SetState")]
	internal static class NativeDoorStatePatch
	{
		private static bool Prefix(Door __instance, int state)
		{
			if (!(__instance is StoneveilDoor))
			{
				return true;
			}
			NativeDoorAdapter.Panel(__instance)?.ObserveNativeState(state);
			return false;
		}
	}
	[HarmonyPatch(typeof(Door), "CanInteract")]
	internal static class NativeDoorCanInteractPatch
	{
		private static bool Prefix(Door __instance, ref bool __result)
		{
			if (!(__instance is StoneveilDoor))
			{
				return true;
			}
			__result = NativeDoorAdapter.Panel(__instance)?.CanOperate ?? false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Door), "Interact")]
	[HarmonyPriority(0)]
	[HarmonyAfter(new string[] { "com.tomtom.latchlink", "Harmony.Azumatt.WardIsLove" })]
	internal static class NativeDoorInteractPatch
	{
		private static bool Prefix(Door __instance, Humanoid character, bool hold, bool alt, ref bool __result)
		{
			if (!(__instance is StoneveilDoor))
			{
				return true;
			}
			__result = NativeDoorAdapter.Panel(__instance)?.InteractPanel(character, hold, alt) ?? false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Door), "RPC_UseDoor")]
	internal static class NativeDoorUsePatch
	{
		private static bool Prefix(Door __instance, long uid)
		{
			if (!(__instance is StoneveilDoor))
			{
				return true;
			}
			NativeDoorAdapter.Panel(__instance)?.HandleNativeUse(uid);
			return false;
		}
	}
	[HarmonyPatch(typeof(Door), "Open")]
	internal static class NativeDoorOpenPatch
	{
		private static bool Prefix(Door __instance)
		{
			if (!(__instance is StoneveilDoor))
			{
				return true;
			}
			SecretDoor secretDoor = NativeDoorAdapter.Panel(__instance);
			if (Object.op_Implicit((Object)(object)secretDoor) && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				secretDoor.InteractPanel((Humanoid)(object)Player.m_localPlayer, hold: false, alt: false);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Door), "UseItem")]
	internal static class NativeDoorItemPatch
	{
		private static bool Prefix(Door __instance, ref bool __result)
		{
			if (!(__instance is StoneveilDoor))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Door), "GetHoverText")]
	internal static class NativeDoorHoverPatch
	{
		private static bool Prefix(Door __instance, ref string __result)
		{
			if (!(__instance is StoneveilDoor))
			{
				return true;
			}
			__result = NativeDoorAdapter.Panel(__instance)?.GetHoverText() ?? "";
			return false;
		}
	}
	[HarmonyPatch(typeof(Door), "GetHoverName")]
	internal static class NativeDoorNamePatch
	{
		private static bool Prefix(Door __instance, ref string __result)
		{
			if (!(__instance is StoneveilDoor))
			{
				return true;
			}
			__result = NativeDoorAdapter.Panel(__instance)?.GetHoverName() ?? "";
			return false;
		}
	}
	internal static class PanelCollision
	{
		internal static bool Blocks(Collider panel, Collider candidate)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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)
			if (!Object.op_Implicit((Object)(object)panel) || !Object.op_Implicit((Object)(object)candidate) || !panel.enabled || !candidate.enabled || panel.isTrigger || candidate.isTrigger || !Object.op_Implicit((Object)(object)((Component)candidate).GetComponentInParent<Character>()))
			{
				return false;
			}
			if (!SupportsPenetration(panel) && !SupportsPenetration(candidate))
			{
				return true;
			}
			Vector3 val = default(Vector3);
			float num = default(float);
			if (Physics.ComputePenetration(candidate, ((Component)candidate).transform.position, ((Component)candidate).transform.rotation, panel, ((Component)panel).transform.position, ((Component)panel).transform.rotation, ref val, ref num))
			{
				return num > 0.005f;
			}
			return false;
		}

		private static bool SupportsPenetration(Collider collider)
		{
			if (!(collider is BoxCollider) && !(collider is CapsuleCollider) && !(collider is SphereCollider))
			{
				MeshCollider val = (MeshCollider)(object)((collider is MeshCollider) ? collider : null);
				if (val != null)
				{
					return val.convex;
				}
				return false;
			}
			return true;
		}
	}
	internal static class PanelMotion
	{
		internal static void Evaluate(Vector3 min, Vector3 max, PanelKind kind, DoorState state, float progress, out Vector3 pivot, out Quaternion rotation, out Vector3 translation, float? nearEdgeHeight = null, float? farEdgeHeight = null)
		{
			progress = Math.Clamp(progress, 0f, 1f);
			progress = progress * progress * (3f - 2f * progress);
			pivot = Vector3.Zero;
			rotation = Quaternion.Identity;
			translation = Vector3.Zero;
			if (state.Motion == DoorMotion.SlideLeft || state.Motion == DoorMotion.SlideRight)
			{
				float num = ((state.Motion == DoorMotion.SlideLeft) ? (-1f) : 1f);
				translation = Vector3.UnitX * ((max.X - min.X + 0.1f) * num * progress);
				return;
			}
			bool flag = state.Motion == DoorMotion.HingeRight;
			Vector3 axis;
			if (kind == PanelKind.Wall)
			{
				pivot = new Vector3(flag ? max.X : min.X, min.Y, (min.Z + max.Z) * 0.5f);
				axis = Vector3.UnitY;
			}
			else
			{
				float y = ((!flag) ? (nearEdgeHeight ?? min.Y) : (farEdgeHeight ?? max.Y));
				pivot = new Vector3((min.X + max.X) * 0.5f, y, flag ? max.Z : min.Z);
				axis = Vector3.UnitX;
			}
			float num2 = (flag ? (-1f) : 1f) * (state.Reverse ? (-1f) : 1f);
			rotation = Quaternion.CreateFromAxisAngle(axis, num2 * MathF.PI * 0.5f * progress);
		}
	}
	internal sealed class PanelRig : IDisposable
	{
		private readonly List<(Transform node, Vector3 position, Quaternion rotation)> parts = new List<(Transform, Vector3, Quaternion)>();

		private readonly List<(Collider original, Collider copy, bool wasEnabled)> rootColliders = new List<(Collider, Collider, bool)>();

		private readonly Transform root;

		private readonly WearNTear wear;

		private readonly float nearEdgeHeight;

		private readonly float farEdgeHeight;

		private StoneStack stack;

		internal bool StackedStone { get; }

		internal Bounds Bounds { get; private set; }

		internal PanelRig(Transform root, bool stackedStone = false, bool checkClearance = false)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Expected O, but got Unknown
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: 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_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Expected O, but got Unknown
			//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Expected O, but got Unknown
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0399: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0503: Unknown result type (might be due to invalid IL or missing references)
			//IL_050b: Unknown result type (might be due to invalid IL or missing references)
			this.root = root;
			StackedStone = stackedStone;
			wear = ((Component)root).GetComponent<WearNTear>();
			Collider[] componentsInChildren = ((Component)root).GetComponentsInChildren<Collider>(true);
			if (!Object.op_Implicit((Object)(object)wear) || Object.op_Implicit((Object)(object)((Component)root).GetComponent<Renderer>()) || ((Component)root).GetComponentsInChildren<Rigidbody>(true).Length != 0 || ((Component)root).GetComponentsInChildren<ZNetView>(true).Length != 1)
			{
				throw new InvalidOperationException("This piece has an unsupported component layout.");
			}
			bool flag = true;
			List<Vector3> list = new List<Vector3>();
			Bounds val = default(Bounds);
			Collider[] array = componentsInChildren;
			Bounds bounds = default(Bounds);
			foreach (Collider val2 in array)
			{
				if (val2.isTrigger)
				{
					continue;
				}
				BoxCollider val3 = (BoxCollider)(object)((val2 is BoxCollider) ? val2 : null);
				if (val3 != null)
				{
					((Bounds)(ref bounds))..ctor(val3.center, val3.size);
				}
				else
				{
					MeshCollider val4 = (MeshCollider)(object)((val2 is MeshCollider) ? val2 : null);
					if (val4 == null || !Object.op_Implicit((Object)(object)val4.sharedMesh))
					{
						throw new InvalidOperationException("Only box and mesh panel colliders are supported.");
					}
					bounds = val4.sharedMesh.bounds;
				}
				for (int j = 0; j < 8; j++)
				{
					Vector3 val5 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)(((j & 1) != 0) ? 1 : (-1)), (float)(((j & 2) != 0) ? 1 : (-1)), (float)(((j & 4) != 0) ? 1 : (-1))));
					Vector3 val6 = root.InverseTransformPoint(((Component)val2).transform.TransformPoint(val5));
					list.Add(val6);
					if (flag)
					{
						((Bounds)(ref val))..ctor(val6, Vector3.zero);
						flag = false;
					}
					else
					{
						((Bounds)(ref val)).Encapsulate(val6);
					}
				}
			}
			if (flag)
			{
				throw new InvalidOperationException("This piece has no solid panel geometry.");
			}
			Bounds = val;
			if (stackedStone && checkClearance)
			{
				CheckUpperClearance(root, val);
			}
			float num = 0f;
			float num2 = 0f;
			int num3 = 0;
			int num4 = 0;
			foreach (Vector3 item in list)
			{
				if (Mathf.Abs(item.z - ((Bounds)(ref val)).min.z) < 0.01f)
				{
					num += item.y;
					num3++;
				}
				if (Mathf.Abs(item.z - ((Bounds)(ref val)).max.z) < 0.01f)
				{
					num2 += item.y;
					num4++;
				}
			}
			nearEdgeHeight = num / (float)num3;
			farEdgeHeight = num2 / (float)num4;
			foreach (Transform item2 in root)
			{
				Transform val7 = item2;
				if (((Component)val7).GetComponentsInChildren<Renderer>(true).Length == 0 && ((Component)val7).GetComponentsInChildren<Collider>(true).Length == 0)
				{
					continue;
				}
				Transform[] componentsInChildren2 = ((Component)val7).GetComponentsInChildren<Transform>(true);
				for (int i = 0; i < componentsInChildren2.Length; i++)
				{
					if (((Component)componentsInChildren2[i]).CompareTag("snappoint"))
					{
						throw new InvalidOperationException("This piece mixes snap points with moving geometry.");
					}
				}
				parts.Add((val7, val7.localPosition, val7.localRotation));
			}
			try
			{
				array = ((Component)root).GetComponents<Collider>();
				foreach (Collider val8 in array)
				{
					if (!val8.isTrigger)
					{
						GameObject val9 = new GameObject("Secret_Collider");
						val9.layer = ((Component)root).gameObject.layer;
						val9.transform.SetParent(root, false);
						BoxCollider val10 = (BoxCollider)(object)((val8 is BoxCollider) ? val8 : null);
						Collider val11;
						if (val10 != null)
						{
							BoxCollider obj = val9.AddComponent<BoxCollider>();
							obj.center = val10.center;
							obj.size = val10.size;
							val11 = (Collider)(object)obj;
						}
						else
						{
							MeshCollider val12 = (MeshCollider)val8;
							MeshCollider obj2 = val9.AddComponent<MeshCollider>();
							obj2.sharedMesh = val12.sharedMesh;
							obj2.convex = val12.convex;
							val11 = (Collider)(object)obj2;
						}
						val11.sharedMaterial = val8.sharedMaterial;
						val11.contactOffset = val8.contactOffset;
						val11.enabled = val8.enabled;
						rootColliders.Add((val8, val11, val8.enabled));
						val8.enabled = false;
						parts.Add((val9.transform, Vector3.zero, Quaternion.identity));
					}
				}
				if (stackedStone)
				{
					List<Transform> list2 = new List<Transform>();
					foreach (var part in parts)
					{
						list2.Add(part.node);
					}
					stack = new StoneStack(root, list2);
					parts.Add((stack.Upper, stack.Upper.localPosition, Quaternion.identity));
					Bounds val13 = val;
					((Bounds)(ref val13)).center = ((Bounds)(ref val13)).center + stack.Upper.localPosition;
					((Bounds)(ref val)).Encapsulate(val13);
					Bounds = val;
				}
				Physics.SyncTransforms();
				GameAccess.SetupColliders(wear);
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		private static void CheckUpperClearance(Transform root, Bounds lower)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 upperOffset = StoneStackLayout.UpperOffset;
			Vector3 val = root.TransformPoint(((Bounds)(ref lower)).center + new Vector3(upperOffset.X, upperOffset.Y, upperOffset.Z));
			Vector3 lossyScale = root.lossyScale;
			((Vector3)(ref lossyScale))..ctor(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.y), Mathf.Abs(lossyScale.z));
			Vector3 val2 = Vector3.Max(Vector3.Scale(((Bounds)(ref lower)).extents, lossyScale) - Vector3.one * 0.025f, Vector3.one * 0.01f);
			Physics.SyncTransforms();
			Collider[] array = Physics.OverlapBox(val, val2, root.rotation, -1, (QueryTriggerInteraction)1);
			foreach (Collider val3 in array)
			{
				if (!((Component)val3).transform.IsChildOf(root) && ((Component)val3).gameObject.layer != LayerMask.NameToLayer("ghost"))
				{
					throw new InvalidOperationException("Clear the space above this wall before adding its 2x2 secret hinge.");
				}
			}
		}

		internal void SyncVisuals()
		{
			stack?.SyncVisuals();
		}

		internal void Apply(PanelKind kind, DoorState state, float progress)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: 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_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: 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_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			if (progress == 0f)
			{
				foreach (var part in parts)
				{
					if (Object.op_Implicit((Object)(object)part.node))
					{
						part.node.localPosition = part.position;
						part.node.localRotation = part.rotation;
					}
				}
				return;
			}
			Bounds bounds = Bounds;
			Vector3 min = ToNumerics(((Bounds)(ref bounds)).min);
			bounds = Bounds;
			PanelMotion.Evaluate(min, ToNumerics(((Bounds)(ref bounds)).max), kind, state, progress, out var pivot, out var rotation, out var translation, nearEdgeHeight, farEdgeHeight);
			Quaternion val = default(Quaternion);
			((Quaternion)(ref val))..ctor(rotation.X, rotation.Y, rotation.Z, rotation.W);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(pivot.X, pivot.Y, pivot.Z);
			Vector3 val3 = default(Vector3);
			((Vector3)(ref val3))..ctor(translation.X, translation.Y, translation.Z);
			foreach (var part2 in parts)
			{
				if (Object.op_Implicit((Object)(object)part2.node))
				{
					part2.node.localPosition = val2 + val * (part2.position - val2) + val3;
					part2.node.localRotation = val * part2.rotation;
				}
			}
		}

		internal bool ContainsCharacter()
		{
			//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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			Collider[] componentsInChildren = ((Component)root).GetComponentsInChildren<Collider>();
			foreach (Collider val in componentsInChildren)
			{
				if (!val.enabled || val.isTrigger)
				{
					continue;
				}
				Bounds bounds = val.bounds;
				Vector3 val2 = Vector3.Max(((Bounds)(ref bounds)).extents, Vector3.one * 0.01f);
				Collider[] array = Physics.OverlapBox(((Bounds)(ref bounds)).center, val2, Quaternion.identity, -1, (QueryTriggerInteraction)1);
				foreach (Collider candidate in array)
				{
					if (PanelCollision.Blocks(val, candidate))
					{
						return true;
					}
				}
			}
			return false;
		}

		internal static Vector3 ToNumerics(Vector3 value)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(value.x, value.y, value.z);
		}

		public void Dispose()
		{
			Apply(PanelKind.Wall, default(DoorState), 0f);
			stack?.Dispose();
			stack = null;
			foreach (var rootCollider in rootColliders)
			{
				if (Object.op_Implicit((Object)(object)rootCollider.original))
				{
					rootCollider.original.enabled = rootCollider.wasEnabled;
				}
				if (Object.op_Implicit((Object)(object)rootCollider.copy))
				{
					rootCollider.copy.enabled = false;
					StoneStack.RemoveTemporary(((Component)rootCollider.copy).gameObject);
				}
			}
			rootColliders.Clear();
			parts.Clear();
			if (Object.op_Implicit((Object)(object)wear))
			{
				GameAccess.SetupColliders(wear);
			}
		}
	}
	public sealed class SecretDoor : MonoBehaviour, Hoverable, Interactable
	{
		private const string StateKey = "com.tomtom.secret.state.v1";

		private const string CommandRpc = "Secret_Command";

		private const string ReplyRpc = "Secret_Reply";

		private const string SwitchRpc = "Stoneveil_LinkedSwitch";

		internal static readonly HashSet<SecretDoor> MovingPanels = new HashSet<SecretDoor>();

		private ZNetView view;

		private Piece piece;

		private PanelKind kind;

		private PanelRig rig;

		private DoorState state;

		private float progress;

		private float nextPoll;

		private float nextOperation;

		private float nextBlockedLog;

		private bool initialized;

		private bool failed;

		private StoneveilDoor nativeDoor;

		private int publishedNativeState;

		private bool manualNativeUse;

		private bool adapterUnavailable;

		private bool lastAdapterOwner;

		private bool switchInteraction;

		private bool switchOpen;

		private ZDOID interactionSwitch;

		private bool switchPipelineReached;

		private readonly AutomaticCloseRequest automaticClose = new AutomaticCloseRequest();

		internal string LastSwitchFailure { get; private set; }

		private bool IsStackableStone => view.GetZDO().GetPrefab() == StringExtensionMethods.GetStableHashCode("stone_wall_2x1");

		internal bool CanOperate
		{
			get
			{
				if (initialized && Object.op_Implicit((Object)(object)view) && view.IsValid() && new DoorState(view.GetZDO().GetInt("com.tomtom.secret.state.v1", 0)).Enabled && rig != null && !failed && Time.unscaledTime >= nextOperation)
				{
					return Mathf.Approximately(progress, state.Open ? 1f : 0f);
				}
				return false;
			}
		}

		private void Start()
		{
			view = ((Component)this).GetComponent<ZNetView>();
			piece = ((Component)this).GetComponent<Piece>();
			if (Object.op_Implicit((Object)(object)view) && view.IsValid() && SecretPlugin.Supported.TryGetValue(view.GetZDO().GetPrefab(), out kind))
			{
				view.Register<int>("Secret_Command", (Action<long, int>)ReceiveCommand);
				view.Register<string>("Secret_Reply", (Action<long, string>)ReceiveReply);
				view.Register<ZPackage>("Stoneveil_LinkedSwitch", (Action<long, ZPackage>)ReceiveSwitchCommand);
				initialized = true;
				Sync(initial: true);
			}
		}

		private void Update()
		{
			if (!initialized || !view.IsValid())
			{
				return;
			}
			if (Time.unscaledTime >= nextPoll)
			{
				nextPoll = Time.unscaledTime + 0.1f;
				Sync(initial: false);
			}
			PollNativeState();
			TryAutomaticClose();
			if (rig != null)
			{
				rig.SyncVisuals();
				progress = Mathf.MoveTowards(progress, state.Open ? 1f : 0f, Time.deltaTime / 0.75f);
				rig.Apply(kind, state, progress);
				if (progress > 0f)
				{
					MovingPanels.Add(this);
				}
				else
				{
					MovingPanels.Remove(this);
				}
			}
		}

		private void Sync(bool initial)
		{
			state = new DoorState(view.GetZDO().GetInt("com.tomtom.secret.state.v1", 0));
			if (!state.Enabled)
			{
				automaticClose.Cancel();
				PublishNativeState();
				rig?.Dispose();
				rig = null;
				failed = false;
				progress = 0f;
				MovingPanels.Remove(this);
				return;
			}
			bool flag = state.StackedStone && IsStackableStone;
			if (rig != null && rig.StackedStone != flag)
			{
				rig.Dispose();
				rig = null;
			}
			if (rig == null && !failed)
			{
				try
				{
					rig = new PanelRig(((Component)this).transform, flag);
				}
				catch (Exception ex)
				{
					failed = true;
					SecretPlugin.Warn("Cannot animate " + ((Object)this).name + ": " + ex.Message);
				}
			}
			if (initial && rig != null)
			{
				progress = (state.Open ? 1f : 0f);
				rig.Apply(kind, state, progress);
				if (progress > 0f)
				{
					MovingPanels.Add(this);
				}
			}
			EnsureNativeDoor();
		}

		internal void Request(Player player, DoorCommand command)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (initialized && view.IsValid() && PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false))
			{
				if (command != DoorCommand.Toggle && piece.GetCreator() != player.GetPlayerID())
				{
					SecretPlugin.Tell("Only the piece's builder can change its secret hinge.");
					return;
				}
				view.InvokeRPC("Secret_Command", new object[1] { (int)command });
			}
		}

		private void ReceiveCommand(long sender, int value)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			if (!view.IsValid() || !view.IsOwner() || !Enum.IsDefined(typeof(DoorCommand), value))
			{
				return;
			}
			Player val = GameAccess.ResolveSender(sender);
			if (!Object.op_Implicit((Object)(object)val) || ((Character)val).IsDead() || !piece.IsPlacedByPlayer())
			{
				return;
			}
			bool flag = value != 2;
			if ((flag && (piece.GetCreator() != val.GetPlayerID() || !SecretPlugin.HasHammer(val))) || !GameAccess.HasWardAccess(((Component)this).transform.position, val.GetPlayerID()))
			{
				Reply(sender, "You do not have access to this hinge.");
				return;
			}
			float num = (flag ? 8f : (val.m_maxInteractDistance + 2f));
			if (Vector3.Distance(((Component)val).transform.position, ((Component)this).transform.position) > num)
			{
				return;
			}
			Sync(initial: false);
			if (Time.unscaledTime < nextOperation)
			{
				return;
			}
			if (value == 1 && failed)
			{
				view.GetZDO().Set("com.tomtom.secret.state.v1", 0);
				Sync(initial: false);
				Reply(sender, "Secret hinge removed.");
				return;
			}
			if ((value == 1 || value == 3 || value == 4) && (state.Open || progress > 0f))
			{
				Reply(sender, "Close the panel before changing or removing its hinge.");
				return;
			}
			if (!state.Enabled && value != 0)
			{
				Reply(sender, "This piece has no secret hinge.");
				return;
			}
			if (failed)
			{
				Reply(sender, "The panel cannot animate. Remove its hinge and check the log.");
				return;
			}
			if (value == 2)
			{
				if (Object.op_Implicit((Object)(object)nativeDoor))
				{
					manualNativeUse = true;
					try
					{
						NativeDoorAdapter.Use((Door)(object)nativeDoor, sender);
						return;
					}
					finally
					{
						manualNativeUse = false;
					}
				}
				TogglePanel(sender);
				return;
			}
			DoorState doorState = state.Apply((DoorCommand)value, IsStackableStone);
			if (value == 0 && rig == null)
			{
				if (doorState.StackedStone && !GameAccess.HasWardAccess(((Component)this).transform.TransformPoint(Vector3.up), val.GetPlayerID()))
				{
					Reply(sender, "You do not have access to the space above this wall.");
					return;
				}
				try
				{
					rig = new PanelRig(((Component)this).transform, doorState.StackedStone && IsStackableStone, checkClearance: true);
				}
				catch (Exception ex)
				{
					Reply(sender, ex.Message);
					return;
				}
			}
			if (doorState.Value != state.Value)
			{
				view.GetZDO().Set("com.tomtom.secret.state.v1", doorState.Value);
				nextOperation = Time.unscaledTime + 0.2f;
				Sync(initial: false);
				PublishNativeState();
				switch (value)
				{
				case 0:
					Reply(sender, state.StackedStone ? "2x2 secret stone door created." : "Secret hinge added.");
					break;
				case 1:
					Reply(sender, "Secret hinge removed.");
					break;
				case 3:
					Reply(sender, $"Motion: {state.Motion}");
					break;
				case 4:
					Reply(sender, state.Reverse ? "Swing reversed." : "Swing restored.");
					break;
				case 5:
					Reply(sender, state.Concealed ? "Interaction prompt concealed." : "Interaction prompt visible.");
					break;
				case 2:
					break;
				}
			}
		}

		internal bool InteractFromSwitch(Humanoid user, ZDOID switchId, bool open)
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			LastSwitchFailure = null;
			if (!Object.op_Implicit((Object)(object)nativeDoor) || ((ZDOID)(ref switchId)).IsNone())
			{
				return RejectSwitch("Stoneveil door adapter or source switch is unavailable", switchId, "client");
			}
			bool flag = switchInteraction;
			bool flag2 = switchOpen;
			bool flag3 = switchPipelineReached;
			ZDOID val = interactionSwitch;
			switchInteraction = true;
			switchPipelineReached = false;
			interactionSwitch = switchId;
			switchOpen = open;
			try
			{
				bool num = ((Door)nativeDoor).Interact(user, false, false);
				if (!num && LastSwitchFailure == null)
				{
					RejectSwitch(switchPipelineReached ? "Stoneveil interaction did not submit a request" : "Door interaction was stopped before Stoneveil handled it; check mod patches", switchId, "client");
					if (!switchPipelineReached)
					{
						NativeDoorAdapter.LogInteractionPatches();
					}
				}
				return num;
			}
			finally
			{
				switchInteraction = flag;
				interactionSwitch = val;
				switchOpen = flag2;
				switchPipelineReached = flag3;
			}
		}

		private void ReceiveSwitchCommand(long sender, ZPackage package)
		{
			//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_004a: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			if (initialized && view.IsValid() && view.IsOwner())
			{
				ZDOID val;
				bool open;
				try
				{
					val = package.ReadZDOID();
					open = package.ReadBool();
				}
				catch (Exception)
				{
					return;
				}
				Player player = GameAccess.ResolveSender(sender);
				ZDOMan instance = ZDOMan.instance;
				ZDO source = ((instance != null) ? instance.GetZDO(val) : null);
				string text = ((!piece.IsPlacedByPlayer()) ? "The panel is not a player-built piece" : LinkedSwitchAccess.GetInteractionDenialReason(player, source, view.GetZDO(), open));
				if (text != null)
				{
					RejectSwitch(text, val, "owner");
					Reply(sender, text);
				}
				else
				{
					LinkedSwitchRpc.Authorize(this, sender, val, view.GetZDO().m_uid, open);
				}
			}
		}

		internal void CompleteSwitchAuthorization(long sender, ZDOID sourceId, ZDOID targetId, bool open, string denial)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (!initialized || !Object.op_Implicit((Object)(object)view) || !view.IsValid() || !view.IsOwner() || view.GetZDO().m_uid != targetId)
			{
				return;
			}
			if (denial == null)
			{
				object obj;
				if (piece.IsPlacedByPlayer())
				{
					Player player = GameAccess.ResolveSender(sender);
					ZDOMan instance = ZDOMan.instance;
					obj = LinkedSwitchAccess.GetInteractionDenialReason(player, (instance != null) ? instance.GetZDO(sourceId) : null, view.GetZDO(), open);
				}
				else
				{
					obj = "The panel is not a player-built piece";
				}
				denial = (string)obj;
			}
			if (denial != null)
			{
				RejectSwitch(denial, sourceId, "authorization");
				Reply(sender, denial);
				return;
			}
			Sync(initial: false);
			if (state.Open == open)
			{
				return;
			}
			if (!CanOperate)
			{
				LogBlockedOperation("The panel is still moving or unavailable.");
				Reply(sender, "The panel is still moving or unavailable.");
				return;
			}
			if (Object.op_Implicit((Object)(object)nativeDoor))
			{
				manualNativeUse = true;
				try
				{
					NativeDoorAdapter.Use((Door)(object)nativeDoor, sender);
					return;
				}
				finally
				{
					manualNativeUse = false;
				}
			}
			TogglePanel(sender);
		}

		private void EnsureNativeDoor()
		{
			if (Object.op_Implicit((Object)(object)nativeDoor) || adapterUnavailable || rig == null || failed)
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)((Component)this).GetComponent<Door>()))
			{
				adapterUnavailable = true;
				SecretPlugin.Warn("Another mod already supplied a Door on " + ((Object)this).name + "; skipping the Stoneveil adapter.");
				return;
			}
			publishedNativeState = AutomaticCloseRequest.NativeState(state);
			lastAdapterOwner = view.IsOwner();
			if (view.IsOwner())
			{
				view.GetZDO().Set(ZDOVars.s_state, publishedNativeState, false);
			}
			nativeDoor = ((Component)this).gameObject.AddComponent<StoneveilDoor>();
			((Door)nativeDoor).m_name = piece.m_name;
		}

		private void PublishNativeState()
		{
			if (Object.op_Implicit((Object)(object)nativeDoor) && Object.op_Implicit((Object)(object)view) && view.IsValid())
			{
				publishedNativeState = AutomaticCloseRequest.NativeState(state);
				if (view.IsOwner())
				{
					view.GetZDO().Set(ZDOVars.s_state, publishedNativeState, false);
				}
			}
		}

		internal void PollNativeState()
		{
			if (initialized && Object.op_Implicit((Object)(object)view) && view.IsValid() && Object.op_Implicit((Object)(object)nativeDoor))
			{
				state = new DoorState(view.GetZDO().GetInt("com.tomtom.secret.state.v1", 0));
				if (lastAdapterOwner != view.IsOwner())
				{
					lastAdapterOwner = view.IsOwner();
					automaticClose.Cancel();
					PublishNativeState();
				}
				else
				{
					ObserveNativeState(view.GetZDO().GetInt(ZDOVars.s_state, 0));
				}
			}
		}

		internal void ObserveNativeState(int observed)
		{
			if (initialized && Object.op_Implicit((Object)(object)view) && view.IsValid() && Object.op_Implicit((Object)(object)nativeDoor))
			{
				if (AutomaticCloseRequest.AcceptStateWrite(observed, publishedNativeState, view.IsOwner(), state))
				{
					automaticClose.Request(Time.unscaledTime);
				}
				PublishNativeState();
			}
		}

		internal void HandleNativeUse(long sender)
		{
			if (initialized && Object.op_Implicit((Object)(object)view) && view.IsValid() && view.IsOwner())
			{
				state = new DoorState(view.GetZDO().GetInt("com.tomtom.secret.state.v1", 0));
				if (manualNativeUse)
				{
					TogglePanel(sender);
				}
				else if (AutomaticCloseRequest.AcceptRpc(sender, view.GetZDO().GetOwner(), isOwner: true, state))
				{
					automaticClose.Request(Time.unscaledTime);
					TryAutomaticClose();
				}
			}
		}

		private void TogglePanel(long sender)
		{
			bool open = !state.Open;
			if (!TryCommitOperation(open, out var denial))
			{
				Reply(sender, denial);
			}
		}

		private void TryAutomaticClose()
		{
			if (automaticClose.ShouldAttempt(Time.unscaledTime, view.IsOwner(), state))
			{
				TryCommitOperation(open: false, out var _);
			}
		}

		private bool TryCommitOperation(bool open, out string denial)
		{
			denial = null;
			if (!CanOperate)
			{
				denial = "The panel is still moving or unavailable.";
			}
			else if (!PathClear(open))
			{
				denial = "Someone is in the panel's path; move clear and try again.";
			}
			if (denial != null)
			{
				LogBlockedOperation(denial);
				return false;
			}
			CommitOperation(state.Apply(DoorCommand.Toggle));
			return true;
		}

		private void LogBlockedOperation(string reason)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (!(Time.unscaledTime < nextBlockedLog))
			{
				nextBlockedLog = Time.unscaledTime + 5f;
				SecretPlugin.Warn($"Panel operation blocked: {reason}; door={view.GetZDO().m_uid}; " + $"owner={view.GetZDO().GetOwner()}; state={state.Value}; progress={progress:0.000}; " + $"rig={rig != null}; failed={failed}; cooldown={Mathf.Max(0f, nextOperation - Time.unscaledTime):0.000}");
			}
		}

		private void CommitOperation(DoorState next)
		{
			view.GetZDO().Set("com.tomtom.secret.state.v1", next.Value);
			state = next;
			automaticClose.Cancel();
			nextOperation = Time.unscaledTime + 0.75f + 0.15f;
			PublishNativeState();
		}

		private bool PathClear(bool open)
		{
			if (rig == null)
			{
				return false;
			}
			try
			{
				for (int i = 1; i <= 12; i++)
				{
					rig.Apply(kind, state, Mathf.Lerp(progress, open ? 1f : 0f, (float)i / 12f));
					Physics.SyncTransforms();
					if (rig.ContainsCharacter())
					{
						return false;
					}
				}
				return true;
			}
			finally
			{
				rig.Apply(kind, state, progress);
				Physics.SyncTransforms();
			}
		}

		private void Reply(long sender, string message)
		{
			view.InvokeRPC(sender, "Secret_Reply", new object[1] { message });
		}

		private void ReceiveReply(long sender, string message)
		{
			if (view.IsValid() && sender == view.GetZDO().GetOwner())
			{
				SecretPlugin.Tell(message);
			}
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (!Object.op_Implicit((Object)(object)nativeDoor))
			{
				return InteractPanel(user, hold, alt);
			}
			return ((Door)nativeDoor).Interact(user, hold, alt);
		}

		internal bool InteractPanel(Humanoid user, bool hold, bool alt)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			//IL_011b: 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)
			if (switchInteraction)
			{
				switchPipelineReached = true;
				if (hold || !initialized || !Object.op_Implicit((Object)(object)view) || !view.IsValid())
				{
					return RejectSwitch("The Stoneveil panel is not initialized for interaction", interactionSwitch, "client");
				}
				Player val = (Player)(object)((user is Player) ? user : null);
				if (val == null)
				{
					return RejectSwitch("The switch user is not a player", interactionSwitch, "client");
				}
				ZDOMan instance = ZDOMan.instance;
				ZDO val2 = ((instance != null) ? instance.GetZDO(interactionSwitch) : null);
				string interactionDenialReason = LinkedSwitchAccess.GetInteractionDenialReason(val, val2, view.GetZDO(), switchOpen);
				if (interactionDenialReason != null)
				{
					return RejectSwitch(interactionDenialReason, interactionSwitch, "client");
				}
				if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false))
				{
					return RejectSwitch("Door access denied by the local ward check", interactionSwitch, "client");
				}
				if (!PrivateArea.CheckAccess(val2.GetPosition(), 0f, true, false))
				{
					return RejectSwitch("Switch access denied by the local ward check", interactionSwitch, "client");
				}
				ZPackage val3 = new ZPackage();
				val3.Write(interactionSwitch);
				val3.Write(switchOpen);
				view.InvokeRPC("Stoneveil_LinkedSwitch", new object[1] { val3 });
				return true;
			}
			if (!hold && initialized && view.IsValid() && new DoorState(view.GetZDO().GetInt("com.tomtom.secret.state.v1", 0)).Enabled)
			{
				Player val4 = (Player)(object)((user is Player) ? user : null);
				if (val4 != null)
				{
					Request(val4, DoorCommand.Toggle);
					return true;
				}
			}
			return false;
		}

		private bool RejectSwitch(string reason, ZDOID sourceId, string stage)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			LastSwitchFailure = reason;
			ZDO val = ((Object.op_Implicit((Object)(object)view) && view.IsValid()) ? view.GetZDO() : null);
			SecretPlugin.Warn($"Linked switch denied ({stage}): {reason}; switch={sourceId}; door={val?.m_uid}; " + $"prefab={((val != null) ? new int?(val.GetPrefab()) : ((int?)null))}; owner={((val != null) ? new long?(val.GetOwner()) : ((long?)null))}");
			return false;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}

		public string GetHoverName()
		{
			if (!Object.op_Implicit((Object)(object)piece))
			{
				return "";
			}
			return piece.m_name;
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		public string GetHoverText()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (!initialized || !view.IsValid())
			{
				return "";
			}
			DoorState doorState = new DoorState(view.GetZDO().GetInt("com.tomtom.secret.state.v1", 0));
			if (!doorState.Enabled || doorState.Concealed)
			{
				return "";
			}
			if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false))
			{
				return Localization.instance.Localize("$piece_noaccess");
			}
			return Localization.instance.Localize(piece.m_name + "\n[<color=yellow><b>$KEY_Use</b></color>] " + (doorState.Open ? "$piece_door_close" : "$piece_door_open"));
		}

		internal void StructuralPose(bool closed)
		{
			rig?.Apply(kind, state, closed ? 0f : progress);
		}

		private void OnDestroy()
		{
			automaticClose.Cancel();
			if (Object.op_Implicit((Object)(object)nativeDoor))
			{
				((MonoBehaviour)nativeDoor).CancelInvoke();
				if (Object.op_Implicit((Object)(object)view))
				{
					view.Unregister("UseDoor");
				}
				Object.Destroy((Object)(object)nativeDoor);
			}
			MovingPanels.Remove(this);
			rig?.Dispose();
			if (initialized && Object.op_Implicit((Object)(object)view))
			{
				view.Unregister("Secret_Command");
				view.Unregister("Secret_Reply");
				view.Unregister("Stoneveil_LinkedSwitch");
			}
		}
	}
	[BepInPlugin("com.tomtom.secret", "Stoneveil", "0.4.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class SecretPlugin : BaseUnityPlugin
	{
		public const string Guid = "com.tomtom.secret";

		public const string Version = "0.4.4";

		internal const float Duration = 0.75f;

		internal static readonly Dictionary<int, PanelKind> Supported = new Dictionary<int, PanelKind>();

		internal static SecretPlugin Instance;

		private Harmony harmony;

		private ConfigEntry<KeyboardShortcut> convert;

		private ConfigEntry<KeyboardShortcut> remove;

		private ConfigEntry<KeyboardShortcut> motion;

		private ConfigEntry<KeyboardShortcut> reverse;

		private ConfigEntry<KeyboardShortcut> conceal;

		private void Awake()
		{
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Expected O, but got Unknown
			Instance = this;
			LinkedSwitchRpc.Initialize();
			string[] array = new string[5] { "wood_wall_quarter", "wood_wall_half", "woodwall", "stone_wall_2x1", "stone_wall_1x1" };
			foreach (string text in array)
			{
				Supported[StringExtensionMethods.GetStableHashCode(text)] = PanelKind.Wall;
			}
			array = new string[5] { "wood_floor", "wood_floor_1x1", "stone_floor_2x2", "wood_roof", "wood_roof_45" };
			foreach (string text2 in array)
			{
				Supported[StringExtensionMethods.GetStableHashCode(text2)] = PanelKind.Hatch;
			}
			convert = Bind("Convert", (KeyCode)104, (KeyCode)308);
			remove = Bind("Remove hinge", (KeyCode)104, (KeyCode)306, (KeyCode)308);
			motion = Bind("Cycle motion", (KeyCode)106, (KeyCode)308);
			reverse = Bind("Reverse swing", (KeyCode)106, (KeyCode)306, (KeyCode)308);
			conceal = Bind("Conceal prompt", (KeyCode)107, (KeyCode)308);
			harmony = new Harmony("com.tomtom.secret");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Stoneveil 0.4.4 loaded. Hammer + Alt+H converts a supported piece.");
		}

		private ConfigEntry<KeyboardShortcut> Bind(string name, KeyCode key, params KeyCode[] modifiers)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			return ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hammer controls", name, new KeyboardShortcut(key, modifiers), "Used while holding the vanilla hammer and aiming at a supported piece.");
		}

		private void Update()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			LinkedSwitchRpc.Update();
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || !HasHammer(localPlayer) || !GameAccess.TakeInput(localPlayer) || Hud.IsPieceSelectionVisible())
			{
				return;
			}
			DoorCommand? doorCommand = null;
			KeyboardShortcut value = remove.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				doorCommand = DoorCommand.Remove;
			}
			else
			{
				value = reverse.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					doorCommand = DoorCommand.Reverse;
				}
				else
				{
					value = convert.Value;
					if (((KeyboardShortcut)(ref value)).IsDown())
					{
						doorCommand = DoorCommand.Convert;
					}
					else
					{
						value = motion.Value;
						if (((KeyboardShortcut)(ref value)).IsDown())
						{
							doorCommand = DoorCommand.CycleMotion;
						}
						else
						{
							value = conceal.Value;
							if (((KeyboardShortcut)(ref value)).IsDown())
							{
								doorCommand = DoorCommand.ToggleConcealment;
							}
						}
					}
				}
			}
			if (doorCommand.HasValue)
			{
				Piece hoveringPiece = localPlayer.GetHoveringPiece();
				SecretDoor secretDoor = (Object.op_Implicit((Object)(object)hoveringPiece) ? ((Component)hoveringPiece).GetComponent<SecretDoor>() : null);
				if (!Object.op_Implicit((Object)(object)secretDoor))
				{
					Tell("Aim at a supported wall, floor, or roof piece.");
				}
				else
				{
					secretDoor.Request(localPlayer, doorCommand.Value);
				}
			}
		}

		internal static bool HasHammer(Player player)
		{
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component) && component.IsValid())
			{
				return component.GetZDO().GetInt(ZDOVars.s_rightItem, 0) == StringExtensionMethods.GetStableHashCode("Hammer");
			}
			return false;
		}

		internal static void Tell(string message)
		{
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false);
			}
		}

		internal static void Warn(string message)
		{
			((BaseUnityPlugin)Instance).Logger.LogWarning((object)message);
		}

		private void OnDestroy()
		{
			SecretDoor[] array = Object.FindObjectsByType<SecretDoor>((FindObjectsSortMode)0);
			for (int i = 0; i < array.Length; i++)
			{
				Object.Destroy((Object)(object)array[i]);
			}
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			Instance = null;
		}
	}
	[HarmonyPatch(typeof(ZNetView), "Awake")]
	internal static class AttachDoorPatch
	{
		private static void Postfix(ZNetView __instance)
		{
			if (__instance.IsValid() && SecretPlugin.Supported.ContainsKey(__instance.GetZDO().GetPrefab()) && Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<Piece>()) && !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<SecretDoor>()))
			{
				((Component)__instance).gameObject.AddComponent<SecretDoor>();
			}
		}
	}
	internal sealed class StoneStack : IDisposable
	{
		private readonly List<(GameObject source, GameObject copy)> objects = new List<(GameObject, GameObject)>();

		private readonly Dictionary<Renderer, Renderer> renderers = new Dictionary<Renderer, Renderer>();

		private readonly List<(Collider source, Collider copy)> colliders = new List<(Collider, Collider)>();

		private readonly List<(LODGroup source, LODGroup copy)> lodGroups = new List<(LODGroup, LODGroup)>();

		private readonly List<GameObject> snapPoints = new List<GameObject>();

		private readonly MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock();

		internal Transform Upper { get; }

		internal StoneStack(Transform root, IEnumerable<Transform> lowerParts)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			Upper = new GameObject("Secret_UpperStone").transform;
			Upper.SetParent(root, false);
			Vector3 upperOffset = StoneStackLayout.UpperOffset;
			Upper.localPosition = new Vector3(upperOffset.X, upperOffset.Y, upperOffset.Z);
			try
			{
				foreach (Transform lowerPart in lowerParts)
				{
					CopyTree(lowerPart, Upper);
				}
				LODGroup component = ((Component)root).GetComponent<LODGroup>();
				if (Object.op_Implicit((Object)(object)component))
				{
					lodGroups.Add((component, ((Component)Upper).gameObject.AddComponent<LODGroup>()));
				}
				foreach (var lodGroup in lodGroups)
				{
					LOD[] lODs = lodGroup.source.GetLODs();
					for (int i = 0; i < lODs.Length; i++)
					{
						List<Renderer> list = new List<Renderer>();
						Renderer[] array = lODs[i].renderers;
						foreach (Renderer val in array)
						{
							if (Object.op_Implicit((Object)(object)val) && renderers.TryGetValue(val, out var value))
							{
								list.Add(value);
							}
						}
						lODs[i].renderers = list.ToArray();
					}
					lodGroup.copy.SetLODs(lODs);
					lodGroup.copy.localReferencePoint = lodGroup.source.localReferencePoint;
					lodGroup.copy.size = lodGroup.source.size;
					lodGroup.copy.fadeMode = lodGroup.source.fadeMode;
					lodGroup.copy.animateCrossFading = lodGroup.source.animateCrossFading;
					lodGroup.copy.enabled = lodGroup.source.enabled;
				}
				AddSnapPoints(root);
				SyncVisuals();
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		private void CopyTree(Transform source, Transform parent)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Expected O, but got Unknown
			GameObject val = new GameObject(((Object)source).name);
			val.layer = ((Component)source).gameObject.layer;
			val.transform.SetParent(parent, false);
			val.transform.localPosition = source.localPosition;
			val.transform.localRotation = source.localRotation;
			val.transform.localScale = source.localScale;
			objects.Add((((Component)source).gameObject, val));
			MeshFilter component = ((Component)source).GetComponent<MeshFilter>();
			if (Object.op_Implicit((Object)(object)component))
			{
				val.AddComponent<MeshFilter>().sharedMesh = component.sharedMesh;
			}
			Renderer[] components = ((Component)source).GetComponents<Renderer>();
			foreach (Renderer val2 in components)
			{
				if (!(val2 is MeshRenderer))
				{
					throw new InvalidOperationException("This stone wall uses unsupported animated or particle geometry.");
				}
				MeshRenderer val3 = val.AddComponent<MeshRenderer>();
				((Renderer)val3).sharedMaterials = val2.sharedMaterials;
				((Renderer)val3).shadowCastingMode = val2.shadowCastingMode;
				((Renderer)val3).receiveShadows = val2.receiveShadows;
				((Renderer)val3).lightProbeUsage = val2.lightProbeUsage;
				((Renderer)val3).reflectionProbeUsage = val2.reflectionProbeUsage;
				((Renderer)val3).probeAnchor = val2.probeAnchor;
				renderers.Add(val2, (Renderer)(object)val3);
			}
			Collider[] components2 = ((Component)source).GetComponents<Collider>();
			foreach (Collider val4 in components2)
			{
				if (val4.isTrigger)
				{
					continue;
				}
				BoxCollider val5 = (BoxCollider)(object)((val4 is BoxCollider) ? val4 : null);
				Collider val6;
				if (val5 != null)
				{
					BoxCollider obj = val.AddComponent<BoxCollider>();
					obj.center = val5.center;
					obj.size = val5.size;
					val6 = (Collider)(object)obj;
				}
				else
				{
					MeshCollider val7 = (MeshCollider)(object)((val4 is MeshCollider) ? val4 : null);
					if (val7 == null)
					{
						throw new InvalidOperationException("This stone wall uses an unsupported collider.");
					}
					MeshCollider obj2 = val.AddComponent<MeshCollider>();
					obj2.sharedMesh = val7.sharedMesh;
					obj2.convex = val7.convex;
					val6 = (Collider)(object)obj2;
				}
				val6.sharedMaterial = val4.sharedMaterial;
				val6.contactOffset = val4.contactOffset;
				val6.enabled = val4.enabled;
				colliders.Add((val4, val6));
			}
			LODGroup component2 = ((Component)source).GetComponent<LODGroup>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				lodGroups.Add((component2, val.AddComponent<LODGroup>()));
			}
			foreach (Transform item in source)
			{
				Transform source2 = item;
				CopyTree(source2, val.transform);
			}
		}

		private void AddSnapPoints(Transform root)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_00ab: 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_00d1: Expected O, but got Unknown
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			List<Transform> list2 = new List<Transform>();
			foreach (Transform item in root)
			{
				Transform val = item;
				if (((Component)val).CompareTag("snappoint"))
				{
					list2.Add(val);
					list.Add(val.localPosition);
				}
			}
			foreach (Transform item2 in list2)
			{
				Vector3 vector = StoneStackLayout.UpperPoint(PanelRig.ToNumerics(item2.localPosition));
				Vector3 position = new Vector3(vector.X, vector.Y, vector.Z);
				if (!list.Exists(delegate(Vector3 other)
				{
					//IL_0000: Unknown result type (might be due to invalid IL or missing references)
					//IL_0002: Unknown result type (might be due to invalid IL or missing references)
					//IL_0007: Unknown result type (might be due to invalid IL or missing references)
					//IL_000c: Unknown result type (might be due to invalid IL or missing references)
					Vector3 val3 = other - position;
					return ((Vector3)(ref val3)).sqrMagnitude < 0.0001f;
				}))
				{
					GameObject val2 = new GameObject("Secret_UpperSnap");
					val2.transform.SetParent(root, false);
					val2.transform.localPosition = position;
					val2.transform.localRotation = item2.localRotation;
					val2.tag = "snappoint";
					snapPoints.Add(val2);
					list.Add(position);
				}
			}
		}

		internal void SyncVisuals()
		{
			foreach (var @object in objects)
			{
				if (Object.op_Implicit((Object)(object)@object.source) && Object.op_Implicit((Object)(object)@object.copy) && @object.copy.activeSelf != @object.source.activeSelf)
				{
					@object.copy.SetActive(@object.source.activeSelf);
				}
			}
			foreach (KeyValuePair<Renderer, Renderer> renderer in renderers)
			{
				if (Object.op_Implicit((Object)(object)renderer.Key) && Object.op_Implicit((Object)(object)renderer.Value))
				{
					renderer.Value.enabled = renderer.Key.enabled;
					renderer.Value.sharedMaterials = renderer.Key.sharedMaterials;
					renderer.Key.GetPropertyBlock(propertyBlock);
					renderer.Value.SetPropertyBlock(propertyBlock);
				}
			}
			foreach (var collider in colliders)
			{
				if (Object.op_Implicit((Object)(object)collider.source) && Object.op_Implicit((Object)(object)collider.copy))
				{
					collider.copy.enabled = collider.source.enabled;
				}
			}
		}

		internal static void RemoveTemporary(GameObject target)
		{
			if (Object.op_Implicit((Object)(object)target))
			{
				target.SetActive(false);
				target.transform.SetParent((Transform)null, false);
				Object.Destroy((Object)(object)target);
			}
		}

		public void Dispose()
		{
			foreach (GameObject snapPoint in snapPoints)
			{
				RemoveTemporary(snapPoint);
			}
			snapPoints.Clear();
			if (Object.op_Implicit((Object)(object)Upper))
			{
				RemoveTemporary(((Component)Upper).gameObject);
			}
		}
	}
	internal static class StoneStackLayout
	{
		internal const string PrefabName = "stone_wall_2x1";

		internal static Vector3 UpperOffset => Vector3.UnitY;

		internal static Vector3 UpperPoint(Vector3 lowerPoint)
		{
			return lowerPoint + UpperOffset;
		}
	}
	[HarmonyPatch(typeof(WearNTear), "UpdateSupport")]
	internal static class SupportPatch
	{
		private static void Prefix(out bool __state)
		{
			__state = SecretDoor.MovingPanels.Count != 0;
			if (!__state)
			{
				return;
			}
			foreach (SecretDoor movingPanel in SecretDoor.MovingPanels)
			{
				movingPanel.StructuralPose(closed: true);
			}
			Physics.SyncTransforms();
		}

		private static void Finalizer(bool __state)
		{
			if (!__state)
			{
				return;
			}
			foreach (SecretDoor movingPanel in SecretDoor.MovingPanels)
			{
				movingPanel.StructuralPose(closed: false);
			}
			Physics.SyncTransforms();
		}
	}
}