Decompiled source of SimpleAccessControl v1.0.9

BepInEx/plugins/SimpleAccessControl/SimpleAccessControl.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("SimpleAccessControl")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SimpleAccessControl")]
[assembly: AssemblyTitle("SimpleAccessControl")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SimpleAccessControl
{
	[BepInPlugin("zephyrfit.simpleaccesscontrol", "Simple Access Control", "1.0.9")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "zephyrfit.simpleaccesscontrol";

		public const string PluginName = "Simple Access Control";

		public const string PluginVersion = "1.0.9";

		internal static ManualLogSource Log;

		internal static ConfigEntry<KeyCode> ManageModifier;

		internal static ConfigEntry<KeyCode> PanelKey;

		internal static ConfigEntry<bool> ProtectConfiguredPieces;

		internal static ConfigEntry<bool> AdminOverride;

		internal static ConfigEntry<bool> ShowHoverStatus;

		internal static ConfigEntry<bool> ShowDestructionOnlyWithBuildTool;

		internal static ConfigEntry<bool> DebugLogging;

		internal static ConfigEntry<bool> AssignedBedsForcePrivate;

		internal static ConfigEntry<bool> ManageContainers;

		internal static ConfigEntry<bool> ManageDoorsAndGates;

		internal static ConfigEntry<bool> ManageBeds;

		internal static ConfigEntry<bool> ManageCraftingStations;

		internal static ConfigEntry<bool> ManageCookingStations;

		internal static ConfigEntry<bool> ManageCartographyTables;

		internal static ConfigEntry<bool> ManageCarts;

		internal static ConfigEntry<bool> ManageShips;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ManageModifier = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "ManageModifier", (KeyCode)304, "Modifier shared by the quick access cycle and the detailed panel. It combines with Valheim's current Use binding for the quick cycle. Restart after changing it.");
			PanelKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "PanelKey", (KeyCode)0, "Key used with ManageModifier to open the detailed ACL panel. None selects A when Valheim is in French and Q for every other game language. Restart after changing it.");
			ProtectConfiguredPieces = ((BaseUnityPlugin)this).Config.Bind<bool>("Security", "ProtectConfiguredPieces", true, "When an access restriction is effective, only the piece owner (or an admin override) may dismantle or damage the piece. Fully public pieces keep vanilla destruction rules.");
			AdminOverride = ((BaseUnityPlugin)this).Config.Bind<bool>("Security", "AdminOverride", true, "Server admins/host may manage and dismantle any supported piece.");
			AssignedBedsForcePrivate = ((BaseUnityPlugin)this).Config.Bind<bool>("Security", "AssignedBedsForcePrivate", true, "A claimed bed is always private to its assigned sleeper, who becomes its access/destruction owner. Admin override still applies.");
			ShowHoverStatus = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowHoverStatus", true, "Show Public/Private/Whitelist state and both access shortcuts in hover text.");
			ShowDestructionOnlyWithBuildTool = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowDestructionOnlyWithBuildTool", true, "Hide destruction status during normal interaction and show it only while a hammer/build tool is equipped.");
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DetailedLogging", false, "Write verbose access decisions to BepInEx/LogOutput.log.");
			ManageContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("Object categories", "Containers", true, "Enable ACLs for player-built containers and chests.");
			ManageDoorsAndGates = ((BaseUnityPlugin)this).Config.Bind<bool>("Object categories", "DoorsAndGates", true, "Enable ACLs for normal doors and physical gates (wood, iron, etc.). This does not include teleport portals.");
			ManageBeds = ((BaseUnityPlugin)this).Config.Bind<bool>("Object categories", "Beds", true, "Enable ACLs for player-built beds.");
			ManageCraftingStations = ((BaseUnityPlugin)this).Config.Bind<bool>("Object categories", "CraftingStations", true, "Enable ACLs for workbenches, forges, cauldrons and other CraftingStation pieces.");
			ManageCookingStations = ((BaseUnityPlugin)this).Config.Bind<bool>("Object categories", "CookingStations", true, "Enable ACLs for cooking stations, including adding and collecting food.");
			ManageCartographyTables = ((BaseUnityPlugin)this).Config.Bind<bool>("Object categories", "CartographyTables", true, "Enable ACLs for both reading and depositing map data at cartography tables.");
			ManageCarts = ((BaseUnityPlugin)this).Config.Bind<bool>("Object categories", "Carts", true, "Enable ACLs for carts and their storage.");
			ManageShips = ((BaseUnityPlugin)this).Config.Bind<bool>("Object categories", "Ships", true, "Enable ACLs for ship controls and onboard storage.");
			_harmony = new Harmony("zephyrfit.simpleaccesscontrol");
			if (!Application.isBatchMode && (Object)(object)((Component)this).GetComponent<AccessUiHost>() == (Object)null)
			{
				((Component)this).gameObject.AddComponent<AccessUiHost>();
			}
			PatchIndependently();
			Log.LogInfo((object)"Simple Access Control v1.0.9 loaded. Supported player-built objects and vehicles are PUBLIC by default.");
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}

		private void PatchIndependently()
		{
			int num = 0;
			int num2 = 0;
			Type[] source;
			try
			{
				source = Assembly.GetExecutingAssembly().GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				source = ex.Types.Where((Type x) => x != null).ToArray();
			}
			foreach (Type item in source.Where((Type t) => t.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).Length != 0))
			{
				try
				{
					_harmony.CreateClassProcessor(item).Patch();
					num++;
				}
				catch (Exception ex2)
				{
					num2++;
					Log.LogError((object)("Harmony patch group skipped (" + item.Name + "): " + ex2));
				}
			}
			Log.LogInfo((object)("Harmony patch groups: " + num + " applied, " + num2 + " skipped."));
		}

		internal static bool ModifierHeld()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0029: Invalid comparison between Unknown and I4
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Invalid comparison between Unknown and I4
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Invalid comparison between Unknown and I4
			KeyCode val = (KeyCode)((ManageModifier == null) ? 304 : ((int)ManageModifier.Value));
			if (Input.GetKey(val))
			{
				return true;
			}
			if ((int)val == 304 && Input.GetKey((KeyCode)303))
			{
				return true;
			}
			if ((int)val == 306 && Input.GetKey((KeyCode)305))
			{
				return true;
			}
			if ((int)val == 308 && Input.GetKey((KeyCode)307))
			{
				return true;
			}
			return false;
		}

		internal static void Debug(string message)
		{
			if (DebugLogging != null && DebugLogging.Value && Log != null)
			{
				Log.LogInfo((object)("[Debug] " + message));
			}
		}

		internal static bool Enabled(ConfigEntry<bool> setting)
		{
			return setting?.Value ?? true;
		}
	}
	internal sealed class AccessUiHost : MonoBehaviour
	{
		private void Update()
		{
			AccessHotkeys.Tick();
			AccessPanel.Tick();
		}

		private void OnGUI()
		{
			AccessPanel.Draw();
		}
	}
	internal enum AccessMode
	{
		Public = 0,
		Private = 2,
		Whitelist = 3
	}
	internal enum PlayerRule
	{
		Default,
		Allow,
		Deny
	}
	internal sealed class RuleEntry
	{
		internal long PlayerId;

		internal string Name;

		internal PlayerRule Rule;
	}
	internal sealed class PlayerRecord
	{
		internal long PlayerId;

		internal string Name;
	}
	internal static class AccessPolicy
	{
		private const string KeyOwner = "sac_owner";

		private const string KeyOwnerName = "sac_owner_name";

		private const string KeyMode = "sac_mode";

		private const string KeyAcl = "sac_acl_v1";

		internal static bool TryContext(Component component, ZNetView preferredView, out Piece piece, out ZNetView view, out ZDO zdo)
		{
			piece = null;
			view = null;
			zdo = null;
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			view = preferredView;
			if ((Object)(object)view == (Object)null)
			{
				view = component.GetComponent<ZNetView>();
			}
			if ((Object)(object)view == (Object)null)
			{
				view = component.GetComponentInParent<ZNetView>();
			}
			piece = component.GetComponentInParent<Piece>();
			if ((Object)(object)piece == (Object)null)
			{
				piece = component.GetComponent<Piece>();
			}
			if ((Object)(object)piece == (Object)null && (Object)(object)view != (Object)null)
			{
				piece = ((Component)view).GetComponent<Piece>();
			}
			if ((Object)(object)piece == (Object)null && (Object)(object)view != (Object)null)
			{
				piece = ((Component)view).GetComponentInChildren<Piece>(true);
			}
			if ((Object)(object)piece == (Object)null && (Object)(object)view != (Object)null)
			{
				piece = ((Component)view).GetComponentInParent<Piece>();
			}
			Transform val = (((Object)(object)component.transform != (Object)null) ? component.transform.root : null);
			if ((Object)(object)piece == (Object)null && (Object)(object)val != (Object)null)
			{
				piece = ((Component)val).GetComponentInChildren<Piece>(true);
			}
			if ((Object)(object)view == (Object)null && (Object)(object)piece != (Object)null)
			{
				view = ((Component)piece).GetComponent<ZNetView>();
			}
			if ((Object)(object)view == (Object)null && (Object)(object)piece != (Object)null)
			{
				view = ((Component)piece).GetComponentInParent<ZNetView>();
			}
			if ((Object)(object)view == (Object)null && (Object)(object)val != (Object)null)
			{
				view = ((Component)val).GetComponentInChildren<ZNetView>(true);
			}
			if ((Object)(object)piece == (Object)null || piece.GetCreator() == 0L)
			{
				return false;
			}
			if ((Object)(object)view == (Object)null || !view.IsValid())
			{
				return false;
			}
			zdo = view.GetZDO();
			return zdo != null;
		}

		internal static bool TryContext(Piece piece, out ZNetView view, out ZDO zdo)
		{
			Piece piece2;
			return TryContext((Component)(object)piece, null, out piece2, out view, out zdo);
		}

		private static T FindRelated<T>(Piece piece) where T : Component
		{
			if ((Object)(object)piece == (Object)null)
			{
				return default(T);
			}
			T val = ((Component)piece).GetComponent<T>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)piece).GetComponentInChildren<T>(true);
			}
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)piece).GetComponentInParent<T>();
			}
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			ZNetView val2 = ((Component)piece).GetComponent<ZNetView>() ?? ((Component)piece).GetComponentInParent<ZNetView>();
			if ((Object)(object)val2 != (Object)null)
			{
				val = ((Component)val2).GetComponent<T>();
				if ((Object)(object)val == (Object)null)
				{
					val = ((Component)val2).GetComponentInChildren<T>(true);
				}
				if ((Object)(object)val == (Object)null)
				{
					val = ((Component)val2).GetComponentInParent<T>();
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			Transform val3 = (((Object)(object)((Component)piece).transform != (Object)null) ? ((Component)piece).transform.root : null);
			if (!((Object)(object)val3 != (Object)null))
			{
				return default(T);
			}
			return ((Component)val3).GetComponentInChildren<T>(true);
		}

		internal static bool IsSupportedPiece(Piece piece)
		{
			if ((Object)(object)piece == (Object)null || piece.GetCreator() == 0L)
			{
				return false;
			}
			if ((Object)(object)FindRelated<Vagon>(piece) != (Object)null)
			{
				return Plugin.Enabled(Plugin.ManageCarts);
			}
			if ((Object)(object)FindRelated<Ship>(piece) != (Object)null || (Object)(object)FindRelated<ShipControlls>(piece) != (Object)null)
			{
				return Plugin.Enabled(Plugin.ManageShips);
			}
			if ((Object)(object)FindRelated<MapTable>(piece) != (Object)null)
			{
				return Plugin.Enabled(Plugin.ManageCartographyTables);
			}
			if ((Object)(object)FindRelated<CookingStation>(piece) != (Object)null)
			{
				return Plugin.Enabled(Plugin.ManageCookingStations);
			}
			if ((!Plugin.Enabled(Plugin.ManageContainers) || !((Object)(object)FindRelated<Container>(piece) != (Object)null)) && (!Plugin.Enabled(Plugin.ManageDoorsAndGates) || !((Object)(object)FindRelated<Door>(piece) != (Object)null)) && (!Plugin.Enabled(Plugin.ManageBeds) || !((Object)(object)FindRelated<Bed>(piece) != (Object)null)))
			{
				if (Plugin.Enabled(Plugin.ManageCraftingStations))
				{
					return (Object)(object)FindRelated<CraftingStation>(piece) != (Object)null;
				}
				return false;
			}
			return true;
		}

		internal static bool IsContainerEnabled(Container container)
		{
			if ((Object)(object)container == (Object)null)
			{
				return false;
			}
			if (TryContext((Component)(object)container, null, out var piece, out var _, out var _))
			{
				if ((Object)(object)FindRelated<Vagon>(piece) != (Object)null)
				{
					return Plugin.Enabled(Plugin.ManageCarts);
				}
				if ((Object)(object)FindRelated<Ship>(piece) != (Object)null || (Object)(object)FindRelated<ShipControlls>(piece) != (Object)null)
				{
					return Plugin.Enabled(Plugin.ManageShips);
				}
			}
			return Plugin.Enabled(Plugin.ManageContainers);
		}

		internal static long GetOwner(Piece piece, ZDO zdo)
		{
			if (TryGetAssignedBedOwner(piece, zdo, out var owner, out var _))
			{
				return owner;
			}
			long result = (((Object)(object)piece != (Object)null) ? piece.GetCreator() : 0);
			if (zdo == null)
			{
				return result;
			}
			long num = zdo.GetLong("sac_owner", 0L);
			if (num == 0L)
			{
				return result;
			}
			return num;
		}

		internal static string GetOwnerName(Piece piece, ZDO zdo)
		{
			if (TryGetAssignedBedOwner(piece, zdo, out var owner, out var ownerName))
			{
				if (!string.IsNullOrEmpty(ownerName))
				{
					return ownerName;
				}
				return PlayerDirectory.ResolveName(owner);
			}
			string text = ((zdo != null) ? zdo.GetString("sac_owner_name", string.Empty) : string.Empty);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			long owner2 = GetOwner(piece, zdo);
			string text2 = PlayerDirectory.ResolveName(owner2);
			if (!string.IsNullOrEmpty(text2))
			{
				return text2;
			}
			return owner2.ToString();
		}

		internal static AccessMode GetMode(ZDO zdo)
		{
			if (zdo == null)
			{
				return AccessMode.Public;
			}
			switch (zdo.GetInt("sac_mode", 0))
			{
			case 2:
				return AccessMode.Private;
			case 3:
				return AccessMode.Whitelist;
			case 1:
				if (!ReadRules(zdo).Any((RuleEntry x) => x.Rule == PlayerRule.Allow))
				{
					return AccessMode.Private;
				}
				return AccessMode.Whitelist;
			default:
				return AccessMode.Public;
			}
		}

		internal static AccessMode GetEffectiveMode(Piece piece, ZDO zdo)
		{
			if (!TryGetAssignedBedOwner(piece, zdo, out var _, out var _))
			{
				return GetMode(zdo);
			}
			return AccessMode.Private;
		}

		internal static bool TryGetAssignedBedOwner(Piece piece, ZDO zdo, out long owner, out string ownerName)
		{
			owner = 0L;
			ownerName = string.Empty;
			if (Plugin.AssignedBedsForcePrivate != null && !Plugin.AssignedBedsForcePrivate.Value)
			{
				return false;
			}
			if ((Object)(object)piece == (Object)null || zdo == null || (Object)(object)FindRelated<Bed>(piece) == (Object)null)
			{
				return false;
			}
			try
			{
				owner = zdo.GetLong("owner", 0L);
				if (owner == 0L)
				{
					return false;
				}
				ownerName = zdo.GetString("ownerName", string.Empty);
				return true;
			}
			catch
			{
				owner = 0L;
				ownerName = string.Empty;
				return false;
			}
		}

		internal static bool Evaluate(Piece piece, ZDO zdo, long playerId, out string reason)
		{
			reason = "public default";
			if ((Object)(object)piece == (Object)null || zdo == null || playerId == 0L)
			{
				return true;
			}
			if (TryGetAssignedBedOwner(piece, zdo, out var owner, out var _))
			{
				bool flag = playerId == owner;
				reason = (flag ? "assigned bed owner" : "bed assigned to another player");
				return flag;
			}
			long owner2 = GetOwner(piece, zdo);
			if (owner2 != 0L && playerId == owner2)
			{
				reason = "owner";
				return true;
			}
			AccessMode effectiveMode = GetEffectiveMode(piece, zdo);
			PlayerRule rule = GetRule(zdo, playerId);
			if (rule == PlayerRule.Deny)
			{
				reason = "explicit deny";
				return false;
			}
			if (effectiveMode == AccessMode.Whitelist && rule == PlayerRule.Allow)
			{
				reason = "explicit allow";
				return true;
			}
			bool flag2 = effectiveMode == AccessMode.Public;
			reason = (flag2 ? "public default" : ((effectiveMode == AccessMode.Whitelist) ? "not on whitelist" : "private owner-only"));
			return flag2;
		}

		internal static bool CanManageLocal(Piece piece, ZDO zdo)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			long playerID = localPlayer.GetPlayerID();
			if (playerID != 0L && playerID == GetOwner(piece, zdo))
			{
				return true;
			}
			if (Plugin.AdminOverride != null && Plugin.AdminOverride.Value)
			{
				return IsLocalAdmin();
			}
			return false;
		}

		internal static bool HasEffectiveRestriction(Piece piece, ZDO zdo)
		{
			if (zdo == null)
			{
				return false;
			}
			if (TryGetAssignedBedOwner(piece, zdo, out var _, out var _))
			{
				return true;
			}
			if (GetEffectiveMode(piece, zdo) != AccessMode.Public)
			{
				return true;
			}
			return ReadRules(zdo).Any((RuleEntry x) => x.Rule == PlayerRule.Deny);
		}

		internal static bool CanRemoveOrDamage(Piece piece, ZDO zdo, long playerId, bool admin)
		{
			if ((Object)(object)piece == (Object)null || zdo == null)
			{
				return true;
			}
			if (!HasEffectiveRestriction(piece, zdo))
			{
				return true;
			}
			if (playerId != 0L && playerId == GetOwner(piece, zdo))
			{
				return true;
			}
			if (admin && Plugin.AdminOverride != null)
			{
				return Plugin.AdminOverride.Value;
			}
			return false;
		}

		internal static bool IsLocalAdmin()
		{
			try
			{
				return (Object)(object)ZNet.instance != (Object)null && ZNet.instance.LocalPlayerIsAdminOrHost();
			}
			catch
			{
				return false;
			}
		}

		internal static void SetMode(Piece piece, ZNetView view, ZDO zdo, AccessMode mode)
		{
			if (CanManageLocal(piece, zdo) && !TryGetAssignedBedOwner(piece, zdo, out var _, out var _))
			{
				EnsureOwnerMetadata(piece, view, zdo);
				Claim(view);
				zdo.Set("sac_mode", (int)mode);
				Plugin.Debug("Mode changed on " + SafePieceName(piece) + " to " + mode);
			}
		}

		internal static bool CycleMode(Piece piece, ZNetView view, ZDO zdo)
		{
			if (!CanManageLocal(piece, zdo))
			{
				return false;
			}
			if (TryGetAssignedBedOwner(piece, zdo, out var _, out var _))
			{
				Messages.Center(UiText.L("Ce lit attribué reste privé.", "This assigned bed remains private."));
				return false;
			}
			AccessMode mode = GetMode(zdo) switch
			{
				AccessMode.Private => AccessMode.Whitelist, 
				AccessMode.Public => AccessMode.Private, 
				_ => AccessMode.Public, 
			};
			SetMode(piece, view, zdo, mode);
			Messages.Center(UiText.L("Accès : ", "Access: ") + UiText.ModeName(mode));
			return true;
		}

		internal static void SetRule(Piece piece, ZNetView view, ZDO zdo, long playerId, string name, PlayerRule rule)
		{
			if (playerId != 0L && CanManageLocal(piece, zdo) && !TryGetAssignedBedOwner(piece, zdo, out var _, out var _) && playerId != GetOwner(piece, zdo))
			{
				EnsureOwnerMetadata(piece, view, zdo);
				List<RuleEntry> list = ReadRules(zdo);
				list.RemoveAll((RuleEntry x) => x.PlayerId == playerId);
				if (rule != PlayerRule.Default)
				{
					list.Add(new RuleEntry
					{
						PlayerId = playerId,
						Name = (name ?? string.Empty),
						Rule = rule
					});
				}
				Claim(view);
				zdo.Set("sac_acl_v1", Serialize(list));
				Plugin.Debug("Rule changed on " + SafePieceName(piece) + ": " + playerId + " -> " + rule);
			}
		}

		internal static void ClearRules(Piece piece, ZNetView view, ZDO zdo)
		{
			if (CanManageLocal(piece, zdo))
			{
				EnsureOwnerMetadata(piece, view, zdo);
				Claim(view);
				zdo.Set("sac_acl_v1", string.Empty);
			}
		}

		internal static PlayerRule GetRule(ZDO zdo, long playerId)
		{
			return ReadRules(zdo).FirstOrDefault((RuleEntry x) => x.PlayerId == playerId)?.Rule ?? PlayerRule.Default;
		}

		internal static List<RuleEntry> ReadRules(ZDO zdo)
		{
			List<RuleEntry> list = new List<RuleEntry>();
			if (zdo == null)
			{
				return list;
			}
			string text = zdo.GetString("sac_acl_v1", string.Empty);
			if (string.IsNullOrEmpty(text))
			{
				return list;
			}
			string[] array = text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { ':' }, 3);
				if (array2.Length < 2 || !long.TryParse(array2[0], out var result) || !int.TryParse(array2[1], out var result2))
				{
					continue;
				}
				string name = string.Empty;
				if (array2.Length == 3)
				{
					try
					{
						name = Encoding.UTF8.GetString(Convert.FromBase64String(array2[2]));
					}
					catch
					{
						name = string.Empty;
					}
				}
				PlayerRule playerRule = result2 switch
				{
					2 => PlayerRule.Deny, 
					1 => PlayerRule.Allow, 
					_ => PlayerRule.Default, 
				};
				if (playerRule != PlayerRule.Default)
				{
					list.Add(new RuleEntry
					{
						PlayerId = result,
						Name = name,
						Rule = playerRule
					});
				}
			}
			return list;
		}

		private static string Serialize(IEnumerable<RuleEntry> entries)
		{
			List<string> list = new List<string>();
			foreach (RuleEntry item in entries.OrderBy((RuleEntry x) => x.PlayerId))
			{
				if (item.PlayerId != 0L && item.Rule != PlayerRule.Default)
				{
					string text = Convert.ToBase64String(Encoding.UTF8.GetBytes(item.Name ?? string.Empty));
					string[] obj = new string[5]
					{
						item.PlayerId.ToString(),
						":",
						null,
						null,
						null
					};
					int rule = (int)item.Rule;
					obj[2] = rule.ToString();
					obj[3] = ":";
					obj[4] = text;
					list.Add(string.Concat(obj));
				}
			}
			return string.Join(";", list.ToArray());
		}

		private static void EnsureOwnerMetadata(Piece piece, ZNetView view, ZDO zdo)
		{
			if (zdo != null && !((Object)(object)piece == (Object)null))
			{
				long owner = GetOwner(piece, zdo);
				Claim(view);
				if (zdo.GetLong("sac_owner", 0L) == 0L)
				{
					zdo.Set("sac_owner", owner);
				}
				if (string.IsNullOrEmpty(zdo.GetString("sac_owner_name", string.Empty)))
				{
					zdo.Set("sac_owner_name", PlayerDirectory.ResolveName(owner));
				}
			}
		}

		private static void Claim(ZNetView view)
		{
			if ((Object)(object)view == (Object)null || !view.IsValid())
			{
				return;
			}
			try
			{
				if (!view.IsOwner())
				{
					view.ClaimOwnership();
				}
			}
			catch (Exception ex)
			{
				Plugin.Debug("ClaimOwnership failed: " + ex.Message);
			}
		}

		internal static string SafePieceName(Piece piece)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return "piece";
			}
			string name = piece.m_name;
			if (string.IsNullOrEmpty(name))
			{
				name = ((Object)piece).name;
			}
			return name ?? "piece";
		}
	}
	internal static class PlayerDirectory
	{
		internal static List<PlayerRecord> GetPlayers(ZDO zdo)
		{
			Dictionary<long, PlayerRecord> dictionary = new Dictionary<long, PlayerRecord>();
			AddConnectedRoster(dictionary);
			try
			{
				List<Player> allPlayers = Player.GetAllPlayers();
				if (allPlayers != null)
				{
					foreach (Player item in allPlayers)
					{
						if (!((Object)(object)item == (Object)null))
						{
							long playerID = item.GetPlayerID();
							if (playerID != 0L)
							{
								dictionary[playerID] = new PlayerRecord
								{
									PlayerId = playerID,
									Name = item.GetPlayerName()
								};
							}
						}
					}
				}
			}
			catch
			{
			}
			try
			{
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					long playerID2 = Player.m_localPlayer.GetPlayerID();
					if (playerID2 != 0L)
					{
						dictionary[playerID2] = new PlayerRecord
						{
							PlayerId = playerID2,
							Name = Player.m_localPlayer.GetPlayerName()
						};
					}
				}
			}
			catch
			{
			}
			foreach (RuleEntry item2 in AccessPolicy.ReadRules(zdo))
			{
				if (!dictionary.ContainsKey(item2.PlayerId))
				{
					dictionary[item2.PlayerId] = new PlayerRecord
					{
						PlayerId = item2.PlayerId,
						Name = (string.IsNullOrEmpty(item2.Name) ? ("Player " + item2.PlayerId) : item2.Name)
					};
				}
			}
			return dictionary.Values.OrderBy<PlayerRecord, string>((PlayerRecord x) => x.Name, StringComparer.OrdinalIgnoreCase).ToList();
		}

		private static void AddConnectedRoster(Dictionary<long, PlayerRecord> map)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (map == null || (Object)(object)ZNet.instance == (Object)null || ZDOMan.instance == null)
				{
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(typeof(ZNet), "GetPlayerList", Type.EmptyTypes, (Type[])null);
				IEnumerable enumerable = ((methodInfo != null) ? (methodInfo.Invoke(ZNet.instance, null) as IEnumerable) : null);
				if (enumerable == null)
				{
					return;
				}
				foreach (object item in enumerable)
				{
					if (item == null)
					{
						continue;
					}
					Type type = item.GetType();
					FieldInfo fieldInfo = AccessTools.Field(type, "m_name");
					FieldInfo fieldInfo2 = AccessTools.Field(type, "m_characterID");
					if (fieldInfo2 == null)
					{
						continue;
					}
					object value = fieldInfo2.GetValue(item);
					if (!(value is ZDOID))
					{
						continue;
					}
					ZDO zDO = ZDOMan.instance.GetZDO((ZDOID)value);
					if (zDO == null)
					{
						continue;
					}
					long num = zDO.GetLong(ZDOVars.s_playerID, 0L);
					if (num != 0L)
					{
						string text = ((fieldInfo != null) ? (fieldInfo.GetValue(item) as string) : null);
						if (string.IsNullOrEmpty(text))
						{
							text = "Player " + num;
						}
						map[num] = new PlayerRecord
						{
							PlayerId = num,
							Name = text
						};
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Debug("Connected roster lookup failed: " + ex.Message);
			}
		}

		internal static string ResolveName(long playerId)
		{
			if (playerId == 0L)
			{
				return string.Empty;
			}
			try
			{
				if ((Object)(object)Player.m_localPlayer != (Object)null && Player.m_localPlayer.GetPlayerID() == playerId)
				{
					return Player.m_localPlayer.GetPlayerName();
				}
				Dictionary<long, PlayerRecord> dictionary = new Dictionary<long, PlayerRecord>();
				AddConnectedRoster(dictionary);
				if (dictionary.TryGetValue(playerId, out var value) && !string.IsNullOrEmpty(value.Name))
				{
					return value.Name;
				}
				List<Player> allPlayers = Player.GetAllPlayers();
				if (allPlayers != null)
				{
					foreach (Player item in allPlayers)
					{
						if ((Object)(object)item != (Object)null && item.GetPlayerID() == playerId)
						{
							return item.GetPlayerName();
						}
					}
				}
			}
			catch
			{
			}
			return "Player " + playerId;
		}
	}
	internal static class RpcIdentity
	{
		internal static long ResolvePlayerId(long rpcSenderUid)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					if (rpcSenderUid == ZNet.GetUID() && (Object)(object)Player.m_localPlayer != (Object)null)
					{
						return Player.m_localPlayer.GetPlayerID();
					}
					ZNetPeer peer = ZNet.instance.GetPeer(rpcSenderUid);
					if (peer != null && ZDOMan.instance != null)
					{
						ZDO zDO = ZDOMan.instance.GetZDO(peer.m_characterID);
						if (zDO != null)
						{
							return zDO.GetLong(ZDOVars.s_playerID, 0L);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Debug("RPC identity resolution failed: " + ex.Message);
			}
			return 0L;
		}

		internal static bool IsAdmin(long rpcSenderUid)
		{
			if (Plugin.AdminOverride == null || !Plugin.AdminOverride.Value)
			{
				return false;
			}
			try
			{
				if ((Object)(object)ZNet.instance == (Object)null)
				{
					return false;
				}
				if (rpcSenderUid == ZNet.GetUID())
				{
					return ZNet.instance.LocalPlayerIsAdminOrHost();
				}
				ZNetPeer peer = ZNet.instance.GetPeer(rpcSenderUid);
				return peer != null && ZNet.instance.IsAdmin(peer.m_socket.GetHostName());
			}
			catch
			{
				return false;
			}
		}
	}
	internal static class Messages
	{
		internal static void Center(string text)
		{
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					return;
				}
				MethodInfo methodInfo = (from m in typeof(Character).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
					where m.Name == "Message"
					orderby m.GetParameters().Length descending
					select m).FirstOrDefault();
				if (methodInfo == null)
				{
					return;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				object[] array = new object[parameters.Length];
				for (int num = 0; num < parameters.Length; num++)
				{
					Type parameterType = parameters[num].ParameterType;
					if (num == 0 && parameterType.IsEnum)
					{
						array[num] = Enum.ToObject(parameterType, 2);
					}
					else if (parameterType == typeof(string))
					{
						array[num] = text;
					}
					else if (parameterType == typeof(int))
					{
						array[num] = 0;
					}
					else if (parameterType == typeof(bool))
					{
						array[num] = false;
					}
					else
					{
						array[num] = null;
					}
				}
				methodInfo.Invoke(localPlayer, array);
			}
			catch
			{
			}
		}
	}
	internal static class UiText
	{
		private static bool _isFrench;

		private static float _nextLanguageRefresh;

		private static string _useKey = "E";

		private static float _nextKeyRefresh;

		internal static string L(string fr, string en)
		{
			RefreshGameLanguage();
			if (!_isFrench)
			{
				return en;
			}
			return fr;
		}

		internal static string CycleShortcut()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			return ModifierName((KeyCode)((Plugin.ManageModifier == null) ? 304 : ((int)Plugin.ManageModifier.Value))) + " + " + BoundUseKey();
		}

		internal static string PanelShortcut()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			return ModifierName((KeyCode)((Plugin.ManageModifier == null) ? 304 : ((int)Plugin.ManageModifier.Value))) + " + " + PanelKeyLabel();
		}

		internal static KeyCode PanelKey()
		{
			//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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			KeyCode val = (KeyCode)((Plugin.PanelKey != null) ? ((int)Plugin.PanelKey.Value) : 0);
			if ((int)val != 0)
			{
				return val;
			}
			return (KeyCode)113;
		}

		private unsafe static string PanelKeyLabel()
		{
			//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_0015: Unknown result type (might be due to invalid IL or missing references)
			KeyCode val = (KeyCode)((Plugin.PanelKey != null) ? ((int)Plugin.PanelKey.Value) : 0);
			if ((int)val != 0)
			{
				return ((object)(*(KeyCode*)(&val))/*cast due to .constrained prefix*/).ToString();
			}
			RefreshGameLanguage();
			if (!_isFrench)
			{
				return "Q";
			}
			return "A";
		}

		internal static bool PanelKeyPressed()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return Input.GetKeyDown(PanelKey());
		}

		internal static string ModeName(AccessMode mode)
		{
			return mode switch
			{
				AccessMode.Private => L("PRIVÉ", "PRIVATE"), 
				AccessMode.Whitelist => L("LISTE BLANCHE", "WHITELIST"), 
				_ => "PUBLIC", 
			};
		}

		private unsafe static string ModifierName(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Invalid comparison between Unknown and I4
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Invalid comparison between Unknown and I4
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Invalid comparison between Unknown and I4
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Invalid comparison between Unknown and I4
			if ((int)key == 304)
			{
				return L("Maj gauche", "Left Shift");
			}
			if ((int)key == 303)
			{
				return L("Maj droite", "Right Shift");
			}
			if ((int)key == 306)
			{
				return L("Ctrl gauche", "Left Ctrl");
			}
			if ((int)key == 305)
			{
				return L("Ctrl droite", "Right Ctrl");
			}
			if ((int)key == 308)
			{
				return L("Alt gauche", "Left Alt");
			}
			if ((int)key == 307)
			{
				return L("Alt droite", "Right Alt");
			}
			return ((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString();
		}

		private static string BoundUseKey()
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup < _nextKeyRefresh)
			{
				return _useKey;
			}
			_nextKeyRefresh = realtimeSinceStartup + 2f;
			try
			{
				Type type = AccessTools.TypeByName("ZInput");
				if (type != null)
				{
					MethodInfo methodInfo = (from m in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
						where m.Name.IndexOf("BoundKeyString", StringComparison.OrdinalIgnoreCase) >= 0
						where m.ReturnType == typeof(string)
						where m.GetParameters().Length != 0 && m.GetParameters()[0].ParameterType == typeof(string)
						orderby m.GetParameters().Length
						select m).FirstOrDefault();
					if (methodInfo != null)
					{
						object obj = null;
						if (!methodInfo.IsStatic)
						{
							FieldInfo fieldInfo = type.GetField("instance", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField("m_instance", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
							PropertyInfo propertyInfo = type.GetProperty("instance", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperty("Instance", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
							obj = ((fieldInfo != null) ? fieldInfo.GetValue(null) : ((propertyInfo != null) ? propertyInfo.GetValue(null, null) : null));
							if (obj == null)
							{
								return _useKey;
							}
						}
						ParameterInfo[] parameters = methodInfo.GetParameters();
						object[] array = new object[parameters.Length];
						array[0] = "Use";
						for (int num = 1; num < parameters.Length; num++)
						{
							if (parameters[num].HasDefaultValue)
							{
								array[num] = parameters[num].DefaultValue;
							}
							else if (parameters[num].ParameterType == typeof(bool))
							{
								array[num] = false;
							}
							else if (parameters[num].ParameterType.IsValueType)
							{
								array[num] = Activator.CreateInstance(parameters[num].ParameterType);
							}
							else
							{
								array[num] = null;
							}
						}
						string text = methodInfo.Invoke(obj, array) as string;
						if (!string.IsNullOrEmpty(text) && text.IndexOf('$') < 0)
						{
							_useKey = text;
						}
					}
				}
			}
			catch
			{
			}
			return _useKey;
		}

		private static void RefreshGameLanguage()
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (!(realtimeSinceStartup < _nextLanguageRefresh))
			{
				_nextLanguageRefresh = realtimeSinceStartup + 2f;
				string text = ReadGameLanguage();
				if (string.IsNullOrEmpty(text))
				{
					_isFrench = false;
					return;
				}
				string text2 = text.Trim().ToLowerInvariant();
				_isFrench = text2 == "fr" || text2.StartsWith("fr-") || text2.StartsWith("french") || text2.StartsWith("français") || text2.StartsWith("francais");
			}
		}

		private static string ReadGameLanguage()
		{
			string[] array = new string[3] { "Localization", "LocalizationManager", "I2.Loc.LocalizationManager" };
			for (int i = 0; i < array.Length; i++)
			{
				string text = ReadLanguageFromType(AccessTools.TypeByName(array[i]));
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
			array = new string[4] { "language", "Language", "selectedLanguage", "SelectedLanguage" };
			foreach (string text2 in array)
			{
				try
				{
					if (PlayerPrefs.HasKey(text2))
					{
						string text3 = PlayerPrefs.GetString(text2, string.Empty);
						if (!string.IsNullOrEmpty(text3))
						{
							return text3;
						}
					}
				}
				catch
				{
				}
			}
			return string.Empty;
		}

		private static string ReadLanguageFromType(Type type)
		{
			if (type == null)
			{
				return string.Empty;
			}
			try
			{
				object obj = null;
				FieldInfo fieldInfo = type.GetField("instance", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField("m_instance", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				PropertyInfo propertyInfo = type.GetProperty("instance", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperty("Instance", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (fieldInfo != null && fieldInfo.IsStatic)
				{
					obj = fieldInfo.GetValue(null);
				}
				else if (propertyInfo != null)
				{
					MethodInfo getMethod = propertyInfo.GetGetMethod(nonPublic: true);
					if (getMethod != null && getMethod.IsStatic)
					{
						obj = propertyInfo.GetValue(null, null);
					}
				}
				string[] array = new string[4] { "CurrentLanguage", "SelectedLanguage", "Language", "m_language" };
				foreach (string name in array)
				{
					PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					if (property == null || property.PropertyType != typeof(string))
					{
						continue;
					}
					MethodInfo getMethod2 = property.GetGetMethod(nonPublic: true);
					object obj2 = ((getMethod2 != null && getMethod2.IsStatic) ? null : obj);
					if (!(getMethod2 == null) && (getMethod2.IsStatic || obj2 != null))
					{
						string text = property.GetValue(obj2, null) as string;
						if (!string.IsNullOrEmpty(text))
						{
							return text;
						}
					}
				}
				array = new string[4] { "m_language", "s_language", "CurrentLanguage", "SelectedLanguage" };
				foreach (string name2 in array)
				{
					FieldInfo field = type.GetField(name2, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					if (field == null || field.FieldType != typeof(string))
					{
						continue;
					}
					object obj3 = (field.IsStatic ? null : obj);
					if (field.IsStatic || obj3 != null)
					{
						string text2 = field.GetValue(obj3) as string;
						if (!string.IsNullOrEmpty(text2))
						{
							return text2;
						}
					}
				}
				array = new string[3] { "GetSelectedLanguage", "GetCurrentLanguage", "GetLanguage" };
				foreach (string name3 in array)
				{
					MethodInfo method = type.GetMethod(name3, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
					if (method == null || method.ReturnType != typeof(string))
					{
						continue;
					}
					object obj4 = (method.IsStatic ? null : obj);
					if (method.IsStatic || obj4 != null)
					{
						string text3 = method.Invoke(obj4, null) as string;
						if (!string.IsNullOrEmpty(text3))
						{
							return text3;
						}
					}
				}
			}
			catch
			{
			}
			return string.Empty;
		}
	}
	internal static class PlayerArguments
	{
		internal static Player Find(object[] args)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			if (args == null)
			{
				return null;
			}
			foreach (object obj in args)
			{
				Player val = (Player)((obj is Player) ? obj : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
				Humanoid val2 = (Humanoid)((obj is Humanoid) ? obj : null);
				if (val2 is Player)
				{
					return (Player)val2;
				}
				Collider val3 = (Collider)((obj is Collider) ? obj : null);
				if ((Object)(object)val3 != (Object)null)
				{
					Player componentInParent = ((Component)val3).GetComponentInParent<Player>();
					if ((Object)(object)componentInParent != (Object)null)
					{
						return componentInParent;
					}
				}
			}
			return null;
		}
	}
	internal static class AccessHotkeys
	{
		private static readonly FieldInfo InteractMaskField = AccessTools.Field(typeof(Player), "m_interactMask");

		private static readonly FieldInfo HoveringField = typeof(Player).GetField("m_hovering", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static readonly MethodInfo HoverObjectMethod = typeof(Player).GetMethod("GetHoverObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);

		internal static void Tick()
		{
			if (AccessPanel.IsOpen || !Plugin.ModifierHeld() || !UiText.PanelKeyPressed())
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)GameCamera.instance == (Object)null) && !((Object)(object)((Character)localPlayer).m_eye == (Object)null))
			{
				if (!TryFindLookTarget(localPlayer, out var piece, out var view, out var zdo))
				{
					Messages.Center(UiText.L("Aucun objet compatible ciblé.", "No supported object targeted."));
				}
				else if (!AccessPolicy.CanManageLocal(piece, zdo))
				{
					Messages.Center(UiText.L("Vous n'êtes pas propriétaire de cet objet.", "You do not own this object."));
				}
				else
				{
					AccessPanel.Open(piece, view, zdo);
				}
			}
		}

		private static bool TryFindLookTarget(Player player, out Piece piece, out ZNetView view, out ZDO zdo)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			piece = null;
			view = null;
			zdo = null;
			Component hoveredComponent = GetHoveredComponent(player);
			if ((Object)(object)hoveredComponent != (Object)null && AccessPolicy.TryContext(hoveredComponent, null, out var piece2, out var view2, out var zdo2) && AccessPolicy.IsSupportedPiece(piece2))
			{
				piece = piece2;
				view = view2;
				zdo = zdo2;
				return true;
			}
			int num = -5;
			try
			{
				if (InteractMaskField != null)
				{
					num = (int)InteractMaskField.GetValue(player);
				}
			}
			catch
			{
			}
			float num2 = Mathf.Max(4f, player.m_maxPlaceDistance);
			foreach (RaycastHit item in from x in Physics.RaycastAll(((Component)GameCamera.instance).transform.position, ((Component)GameCamera.instance).transform.forward, num2, num)
				orderby ((RaycastHit)(ref x)).distance
				select x)
			{
				RaycastHit current = item;
				if (!((Object)(object)((RaycastHit)(ref current)).collider == (Object)null) && AccessPolicy.TryContext((Component)(object)((RaycastHit)(ref current)).collider, null, out var piece3, out var view3, out var zdo3) && AccessPolicy.IsSupportedPiece(piece3))
				{
					piece = piece3;
					view = view3;
					zdo = zdo3;
					return true;
				}
			}
			return false;
		}

		private static Component GetHoveredComponent(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			try
			{
				object obj = ((HoveringField != null) ? HoveringField.GetValue(player) : null);
				if (obj == null && HoverObjectMethod != null)
				{
					obj = HoverObjectMethod.Invoke(player, null);
				}
				Component val = (Component)((obj is Component) ? obj : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
				GameObject val2 = (GameObject)((obj is GameObject) ? obj : null);
				return (Component)(object)(((Object)(object)val2 != (Object)null) ? val2.transform : null);
			}
			catch
			{
				return null;
			}
		}
	}
	internal static class InteractionGuard
	{
		internal static bool Check(Component component, Player player, bool repeat, string label, ref bool result)
		{
			if (repeat || (Object)(object)player == (Object)null)
			{
				return true;
			}
			if (!AccessPolicy.TryContext(component, null, out var piece, out var view, out var zdo))
			{
				return true;
			}
			if ((Object)(object)player == (Object)(object)Player.m_localPlayer && Plugin.ModifierHeld())
			{
				if (!AccessPolicy.CanManageLocal(piece, zdo))
				{
					Messages.Center(UiText.L("Vous n'êtes pas propriétaire de cet objet.", "You do not own this object."));
					result = true;
					return false;
				}
				AccessPolicy.CycleMode(piece, view, zdo);
				result = true;
				return false;
			}
			if (!AccessPolicy.Evaluate(piece, zdo, player.GetPlayerID(), out var reason))
			{
				if ((Object)(object)player == (Object)(object)Player.m_localPlayer)
				{
					Messages.Center(UiText.L("Accès refusé.", "No access."));
				}
				Plugin.Debug(label + " denied player=" + player.GetPlayerID() + " reason=" + reason);
				result = true;
				return false;
			}
			return true;
		}

		internal static bool ManageOnly(Component component, Player player, bool repeat, ref bool result)
		{
			if (repeat || !Plugin.ModifierHeld() || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (!AccessPolicy.TryContext(component, null, out var piece, out var view, out var zdo))
			{
				return true;
			}
			if (!AccessPolicy.CanManageLocal(piece, zdo))
			{
				Messages.Center(UiText.L("Vous n'êtes pas propriétaire de cet objet.", "You do not own this object."));
				result = true;
				return false;
			}
			AccessPolicy.CycleMode(piece, view, zdo);
			result = true;
			return false;
		}
	}
	internal static class AccessPanel
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static WindowFunction <0>__DrawWindow;
		}

		private static bool _open;

		private static Piece _piece;

		private static ZNetView _view;

		private static ZDO _zdo;

		private static Vector2 _scroll;

		private static Rect _window = new Rect(0f, 0f, 820f, 760f);

		internal static bool IsOpen => _open;

		internal static void Open(Piece piece, ZNetView view, ZDO zdo)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)piece == (Object)null) && !((Object)(object)view == (Object)null) && zdo != null && AccessPolicy.CanManageLocal(piece, zdo))
			{
				_piece = piece;
				_view = view;
				_zdo = zdo;
				_open = true;
				_scroll = Vector2.zero;
				((Rect)(ref _window)).width = Mathf.Max(420f, Mathf.Min(820f, (float)Screen.width - 40f));
				((Rect)(ref _window)).height = Mathf.Max(520f, Mathf.Min(760f, (float)Screen.height - 40f));
				((Rect)(ref _window)).x = ((float)Screen.width - ((Rect)(ref _window)).width) * 0.5f;
				((Rect)(ref _window)).y = ((float)Screen.height - ((Rect)(ref _window)).height) * 0.5f;
				Cursor.visible = true;
				Cursor.lockState = (CursorLockMode)0;
			}
		}

		internal static void Close()
		{
			_open = false;
			_piece = null;
			_view = null;
			_zdo = null;
		}

		internal static void Tick()
		{
			if (!_open)
			{
				return;
			}
			if ((Object)(object)_piece == (Object)null || (Object)(object)_view == (Object)null || !_view.IsValid())
			{
				Close();
				return;
			}
			Cursor.visible = true;
			Cursor.lockState = (CursorLockMode)0;
			if (Input.GetKeyDown((KeyCode)27))
			{
				Close();
			}
		}

		internal static void Draw()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			if (_open && !((Object)(object)_piece == (Object)null) && _zdo != null)
			{
				Rect window = _window;
				object obj = <>O.<0>__DrawWindow;
				if (obj == null)
				{
					WindowFunction val = DrawWindow;
					<>O.<0>__DrawWindow = val;
					obj = (object)val;
				}
				_window = GUI.Window(987654, window, (WindowFunction)obj, L("Contrôle d'accès", "Access Control"));
			}
		}

		private static void DrawWindow(int id)
		{
			//IL_07af: Unknown result type (might be due to invalid IL or missing references)
			//IL_050c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0521: Unknown result type (might be due to invalid IL or missing references)
			//IL_0526: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("<b>" + AccessPolicy.SafePieceName(_piece) + "</b>", Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			if (GUILayout.Button(L("X  Fermer", "X  Close"), (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(110f),
				GUILayout.Height(26f)
			}))
			{
				GUILayout.EndHorizontal();
				GUILayout.EndVertical();
				Close();
				return;
			}
			GUILayout.EndHorizontal();
			GUILayout.Label(L("Propriétaire : ", "Owner: ") + AccessPolicy.GetOwnerName(_piece, _zdo), Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			long owner;
			string ownerName;
			bool flag = AccessPolicy.TryGetAssignedBedOwner(_piece, _zdo, out owner, out ownerName);
			AccessMode effectiveMode = AccessPolicy.GetEffectiveMode(_piece, _zdo);
			bool flag2 = AccessPolicy.HasEffectiveRestriction(_piece, _zdo);
			if (flag)
			{
				GUILayout.Label(L("LIT ATTRIBUÉ — mode PRIVÉ forcé", "ASSIGNED BED — PRIVATE mode enforced"), Array.Empty<GUILayoutOption>());
				GUILayout.Label(L("Seul le joueur auquel ce lit est attribué peut y dormir et le détruire. Les administrateurs conservent leur dérogation de gestion/destruction.", "Only the player assigned to this bed can sleep in it or destroy it. Administrators keep their management/destruction override."), Array.Empty<GUILayoutOption>());
				GUILayout.Space(10f);
			}
			else
			{
				GUILayout.Label(L("Politique d'accès", "Access policy"), Array.Empty<GUILayoutOption>());
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUI.enabled = effectiveMode != AccessMode.Public;
				if (GUILayout.Button(L("PUBLIC — tout le monde", "PUBLIC — everyone"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
				{
					AccessPolicy.SetMode(_piece, _view, _zdo, AccessMode.Public);
				}
				GUI.enabled = effectiveMode != AccessMode.Private;
				if (GUILayout.Button(L("PRIVÉ — propriétaire uniquement", "PRIVATE — owner only"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
				{
					AccessPolicy.SetMode(_piece, _view, _zdo, AccessMode.Private);
				}
				GUI.enabled = effectiveMode != AccessMode.Whitelist;
				if (GUILayout.Button(L("LISTE BLANCHE", "WHITELIST"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
				{
					AccessPolicy.SetMode(_piece, _view, _zdo, AccessMode.Whitelist);
				}
				GUI.enabled = true;
				GUILayout.EndHorizontal();
				GUILayout.Space(8f);
			}
			GUILayout.Label(flag2 ? L("Protection destruction : ACTIVE (propriétaire/admin uniquement)", "Destruction protection: ACTIVE (owner/admin only)") : L("Protection destruction : INACTIVE (règles vanilla)", "Destruction protection: INACTIVE (vanilla rules)"), Array.Empty<GUILayoutOption>());
			GUILayout.Label(L("Changement rapide : ", "Quick cycle: ") + UiText.CycleShortcut() + L(" — PUBLIC → PRIVÉ → LISTE BLANCHE", " — PUBLIC → PRIVATE → WHITELIST"), Array.Empty<GUILayoutOption>());
			GUILayout.Label(L("Ouvrir ce panneau : ", "Open this panel: ") + UiText.PanelShortcut() + L(" (A en français, Q dans les autres langues par défaut)", " (A in French, Q in other languages by default)"), Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(L("Modificateur rapide :", "Quick modifier:"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(145f) });
			if (GUILayout.Button(L("Maj", "Shift"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }))
			{
				Plugin.ManageModifier.Value = (KeyCode)304;
			}
			if (GUILayout.Button("Alt", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }))
			{
				Plugin.ManageModifier.Value = (KeyCode)308;
			}
			if (GUILayout.Button("Ctrl", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }))
			{
				Plugin.ManageModifier.Value = (KeyCode)306;
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(8f);
			if (!flag)
			{
				List<PlayerRecord> players = PlayerDirectory.GetPlayers(_zdo);
				long owner2 = AccessPolicy.GetOwner(_piece, _zdo);
				int num = AccessPolicy.ReadRules(_zdo).Count((RuleEntry x) => x.Rule == PlayerRule.Allow);
				string text = effectiveMode switch
				{
					AccessMode.Private => L("PRIVÉ — propriétaire uniquement", "PRIVATE — owner only"), 
					AccessMode.Whitelist => L("LISTE BLANCHE ACTIVE — propriétaire + ", "WHITELIST ACTIVE — owner + ") + num + L(" joueur(s)", " player(s)"), 
					_ => L("PUBLIC — sauf joueurs explicitement interdits", "PUBLIC — except explicitly denied players"), 
				};
				GUILayout.Label(L("État effectif : ", "Effective state: ") + text, Array.Empty<GUILayoutOption>());
				GUILayout.Label(L("Liste blanche : sélectionnez LISTE BLANCHE, puis Autoriser pour chaque joueur admis.", "Whitelist: select WHITELIST, then Allow for each admitted player."), Array.Empty<GUILayoutOption>());
				GUILayout.Label(L("PUBLIC applique Interdire ; PRIVÉ reste propriétaire uniquement ; LISTE BLANCHE applique Interdire puis Autoriser.", "PUBLIC applies Deny; PRIVATE remains owner-only; WHITELIST applies Deny then Allow."), Array.Empty<GUILayoutOption>());
				if (players.All((PlayerRecord x) => x.PlayerId == owner2))
				{
					GUILayout.Label(L("Aucun autre joueur détecté : le joueur à ajouter doit être connecté, puis il restera mémorisé hors ligne.", "No other player detected: the player to add must be connected once, then remains listed while offline."), Array.Empty<GUILayoutOption>());
				}
				GUILayout.Space(4f);
				float num2 = Mathf.Max(100f, ((Rect)(ref _window)).height - 460f);
				_scroll = GUILayout.BeginScrollView(_scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num2) });
				foreach (PlayerRecord item in players)
				{
					GUILayout.BeginHorizontal(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
					GUILayout.Label(item.Name + ((item.PlayerId == owner2) ? L("  (propriétaire)", "  (owner)") : string.Empty), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(260f) });
					if (item.PlayerId == owner2)
					{
						GUILayout.Label(L("Toujours autorisé", "Always allowed"), Array.Empty<GUILayoutOption>());
					}
					else
					{
						PlayerRule rule = AccessPolicy.GetRule(_zdo, item.PlayerId);
						GUI.enabled = rule != PlayerRule.Default;
						if (GUILayout.Button(L("Défaut", "Default"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
						{
							AccessPolicy.SetRule(_piece, _view, _zdo, item.PlayerId, item.Name, PlayerRule.Default);
						}
						GUI.enabled = rule != PlayerRule.Allow;
						if (GUILayout.Button(L("Autoriser", "Allow"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
						{
							AccessPolicy.SetRule(_piece, _view, _zdo, item.PlayerId, item.Name, PlayerRule.Allow);
						}
						GUI.enabled = rule != PlayerRule.Deny;
						if (GUILayout.Button(L("Interdire", "Deny"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) }))
						{
							AccessPolicy.SetRule(_piece, _view, _zdo, item.PlayerId, item.Name, PlayerRule.Deny);
						}
						GUI.enabled = true;
					}
					GUILayout.EndHorizontal();
				}
				GUILayout.EndScrollView();
			}
			GUILayout.FlexibleSpace();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (!flag && GUILayout.Button(L("Réinitialiser les exceptions", "Clear exceptions"), Array.Empty<GUILayoutOption>()))
			{
				AccessPolicy.ClearRules(_piece, _view, _zdo);
			}
			if (GUILayout.Button(L("Fermer", "Close"), (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(140f),
				GUILayout.Height(30f)
			}))
			{
				Close();
			}
			GUILayout.EndHorizontal();
			GUILayout.EndVertical();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 28f));
		}

		private static string L(string fr, string en)
		{
			return UiText.L(fr, en);
		}
	}
	internal static class HoverText
	{
		internal static string Append(string original, Piece piece, ZDO zdo)
		{
			if (Plugin.ShowHoverStatus == null || !Plugin.ShowHoverStatus.Value || (Object)(object)piece == (Object)null || zdo == null)
			{
				return original;
			}
			AccessMode effectiveMode = AccessPolicy.GetEffectiveMode(piece, zdo);
			List<RuleEntry> list = AccessPolicy.ReadRules(zdo);
			bool flag = AccessPolicy.HasEffectiveRestriction(piece, zdo);
			long owner;
			string ownerName;
			bool num = AccessPolicy.TryGetAssignedBedOwner(piece, zdo, out owner, out ownerName);
			bool flag2 = !num && effectiveMode == AccessMode.Whitelist;
			bool flag3 = effectiveMode == AccessMode.Public && list.Any((RuleEntry x) => x.Rule == PlayerRule.Deny);
			string text = (flag ? "#F2B35D" : "#7DCE82");
			string text2 = (num ? UiText.L("LIT ATTRIBUÉ — PRIVÉ", "ASSIGNED BED — PRIVATE") : (flag2 ? UiText.L("LISTE BLANCHE", "WHITELIST") : (flag3 ? UiText.L("PUBLIC AVEC EXCEPTIONS", "PUBLIC WITH EXCEPTIONS") : ((effectiveMode == AccessMode.Private) ? UiText.L("PRIVÉ", "PRIVATE") : "PUBLIC"))));
			string text3 = original + "\n<color=" + text + "><b>" + UiText.L("Accès : ", "Access: ") + text2 + "</b></color>";
			if ((Plugin.ShowDestructionOnlyWithBuildTool != null && !Plugin.ShowDestructionOnlyWithBuildTool.Value) || IsBuildToolEquipped())
			{
				string text4 = (flag ? UiText.L("Destruction : PROTÉGÉE (propriétaire/admin)", "Destruction: PROTECTED (owner/admin)") : UiText.L("Destruction : VANILLA", "Destruction: VANILLA"));
				text3 = text3 + "\n<color=" + text + ">" + text4 + "</color>";
			}
			if (flag || list.Count != 0)
			{
				text3 = text3 + "\n<color=#CFCFCF>" + UiText.L("Propriétaire : ", "Owner: ") + AccessPolicy.GetOwnerName(piece, zdo) + "</color>";
			}
			if (AccessPolicy.CanManageLocal(piece, zdo))
			{
				text3 = text3 + "\n[<color=yellow><b>" + UiText.CycleShortcut() + "</b></color>] " + UiText.L("Changer l'accès", "Cycle access");
				text3 = text3 + "\n[<color=yellow><b>" + UiText.PanelShortcut() + "</b></color>] " + UiText.L("Configurer les accès", "Configure access");
			}
			return text3;
		}

		private static bool IsBuildToolEquipped()
		{
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					return false;
				}
				MethodInfo methodInfo = typeof(Humanoid).GetMethod("GetRightItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) ?? typeof(Player).GetMethod("GetRightItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
				ItemData val = (ItemData)((methodInfo != null) ? /*isinst with value type is only supported in some contexts*/: null);
				if (val == null || val.m_shared == null)
				{
					return false;
				}
				if ((Object)(object)val.m_shared.m_buildPieces != (Object)null)
				{
					return true;
				}
				string text = val.m_shared.m_name ?? string.Empty;
				return text.IndexOf("hammer", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("marteau", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			catch
			{
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(Container), "CheckAccess", new Type[] { typeof(long) })]
	internal static class ContainerCheckAccessPatch
	{
		private static bool Prepare()
		{
			if (!Plugin.Enabled(Plugin.ManageContainers) && !Plugin.Enabled(Plugin.ManageCarts))
			{
				return Plugin.Enabled(Plugin.ManageShips);
			}
			return true;
		}

		private static bool Prefix(Container __instance, long __0, ref bool __result)
		{
			try
			{
				if (!AccessPolicy.IsContainerEnabled(__instance))
				{
					return true;
				}
				long playerId = __0;
				if (!AccessPolicy.TryContext((Component)(object)__instance, null, out var piece, out var _, out var zdo))
				{
					return true;
				}
				__result = AccessPolicy.Evaluate(piece, zdo, playerId, out var reason);
				Plugin.Debug("Container " + AccessPolicy.SafePieceName(piece) + " player=" + playerId + " allowed=" + __result + " reason=" + reason);
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Container access patch failed; falling back to vanilla: " + ex.Message));
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(Container), "Interact")]
	internal static class ContainerInteractPatch
	{
		private static bool Prepare()
		{
			if (!Plugin.Enabled(Plugin.ManageContainers) && !Plugin.Enabled(Plugin.ManageCarts))
			{
				return Plugin.Enabled(Plugin.ManageShips);
			}
			return true;
		}

		private static bool Prefix(Container __instance, Humanoid __0, bool __1, bool __2, ref bool __result)
		{
			if (!AccessPolicy.IsContainerEnabled(__instance))
			{
				return true;
			}
			return InteractionGuard.ManageOnly((Component)(object)__instance, (Player)(object)((__0 is Player) ? __0 : null), __1, ref __result);
		}
	}
	[HarmonyPatch(typeof(Container), "GetHoverText")]
	internal static class ContainerHoverPatch
	{
		private static bool Prepare()
		{
			if (!Plugin.Enabled(Plugin.ManageContainers) && !Plugin.Enabled(Plugin.ManageCarts))
			{
				return Plugin.Enabled(Plugin.ManageShips);
			}
			return true;
		}

		private static void Postfix(Container __instance, ref string __result)
		{
			try
			{
				if (AccessPolicy.IsContainerEnabled(__instance) && AccessPolicy.TryContext((Component)(object)__instance, null, out var piece, out var _, out var zdo))
				{
					__result = HoverText.Append(__result, piece, zdo);
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Door), "Interact")]
	internal static class DoorInteractPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageDoorsAndGates);
		}

		private static bool Prefix(Door __instance, Humanoid __0, bool __1, bool __2, ref bool __result)
		{
			return InteractionGuard.Check((Component)(object)__instance, (Player)(object)((__0 is Player) ? __0 : null), __1, "Door", ref __result);
		}
	}
	[HarmonyPatch(typeof(Door), "GetHoverText")]
	internal static class DoorHoverPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageDoorsAndGates);
		}

		private static void Postfix(Door __instance, ref string __result)
		{
			try
			{
				if (AccessPolicy.TryContext((Component)(object)__instance, null, out var piece, out var _, out var zdo))
				{
					__result = HoverText.Append(__result, piece, zdo);
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Door), "RPC_UseDoor")]
	internal static class DoorRpcPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageDoorsAndGates);
		}

		private static bool Prefix(Door __instance, long __0, bool __1)
		{
			try
			{
				long rpcSenderUid = __0;
				if ((Object)(object)__instance == (Object)null)
				{
					return true;
				}
				if (!AccessPolicy.TryContext((Component)(object)__instance, null, out var piece, out var view, out var zdo))
				{
					return true;
				}
				if (!view.IsOwner())
				{
					return true;
				}
				long num = RpcIdentity.ResolvePlayerId(rpcSenderUid);
				if (num == 0L)
				{
					return true;
				}
				string reason;
				bool flag = AccessPolicy.Evaluate(piece, zdo, num, out reason);
				if (!flag)
				{
					Plugin.Debug("RPC_UseDoor denied sender=" + rpcSenderUid + " player=" + num + " reason=" + reason);
				}
				return flag;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Door RPC access check failed; falling back to vanilla: " + ex.Message));
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(Bed), "Interact")]
	internal static class BedInteractPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageBeds);
		}

		private static bool Prefix(Bed __instance, Humanoid __0, bool __1, bool __2, ref bool __result)
		{
			return InteractionGuard.Check((Component)(object)__instance, (Player)(object)((__0 is Player) ? __0 : null), __1, "Bed", ref __result);
		}
	}
	[HarmonyPatch(typeof(Bed), "GetHoverText")]
	internal static class BedHoverPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageBeds);
		}

		private static void Postfix(Bed __instance, ref string __result)
		{
			try
			{
				if (AccessPolicy.TryContext((Component)(object)__instance, null, out var piece, out var _, out var zdo))
				{
					__result = HoverText.Append(__result, piece, zdo);
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(CraftingStation), "Interact")]
	internal static class CraftingStationInteractPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageCraftingStations);
		}

		private static bool Prefix(CraftingStation __instance, Humanoid __0, bool __1, bool __2, ref bool __result)
		{
			return InteractionGuard.Check((Component)(object)__instance, (Player)(object)((__0 is Player) ? __0 : null), __1, "Crafting station", ref __result);
		}
	}
	[HarmonyPatch(typeof(CraftingStation), "GetHoverText")]
	internal static class CraftingStationHoverPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageCraftingStations);
		}

		private static void Postfix(CraftingStation __instance, ref string __result)
		{
			try
			{
				if (AccessPolicy.TryContext((Component)(object)__instance, null, out var piece, out var _, out var zdo))
				{
					__result = HoverText.Append(__result, piece, zdo);
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(CookingStation), "Interact")]
	internal static class CookingStationInteractPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageCookingStations);
		}

		private static bool Prefix(CookingStation __instance, Humanoid __0, bool __1, bool __2, ref bool __result)
		{
			return InteractionGuard.Check((Component)(object)__instance, (Player)(object)((__0 is Player) ? __0 : null), __1, "Cooking station collect", ref __result);
		}
	}
	[HarmonyPatch(typeof(CookingStation), "UseItem")]
	internal static class CookingStationUseItemPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageCookingStations);
		}

		private static bool Prefix(CookingStation __instance, Humanoid __0, ItemData __1, ref bool __result)
		{
			return InteractionGuard.Check((Component)(object)__instance, (Player)(object)((__0 is Player) ? __0 : null), repeat: false, "Cooking station add", ref __result);
		}
	}
	[HarmonyPatch(typeof(CookingStation), "GetHoverText")]
	internal static class CookingStationHoverPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageCookingStations);
		}

		private static void Postfix(CookingStation __instance, ref string __result)
		{
			try
			{
				if (AccessPolicy.TryContext((Component)(object)__instance, null, out var piece, out var _, out var zdo))
				{
					__result = HoverText.Append(__result, piece, zdo);
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch]
	internal static class MapTableActionPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageCartographyTables);
		}

		private static IEnumerable<MethodBase> TargetMethods()
		{
			return (from m in typeof(MapTable).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
				where (m.Name == "OnRead" || m.Name == "OnWrite") && m.ReturnType == typeof(bool)
				select m).Cast<MethodBase>();
		}

		private static bool Prefix(MapTable __instance, MethodBase __originalMethod, object[] __args, ref bool __result)
		{
			Player player = PlayerArguments.Find(__args);
			string label = ((__originalMethod != null && __originalMethod.Name == "OnWrite") ? "Cartography deposit" : "Cartography read");
			return InteractionGuard.Check((Component)(object)__instance, player, repeat: false, label, ref __result);
		}
	}
	[HarmonyPatch(typeof(Switch), "GetHoverText")]
	internal static class MapTableSwitchHoverPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageCartographyTables);
		}

		private static void Postfix(Switch __instance, ref string __result)
		{
			try
			{
				if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponentInParent<MapTable>() == (Object)null) && AccessPolicy.TryContext((Component)(object)__instance, null, out var piece, out var _, out var zdo))
				{
					__result = HoverText.Append(__result, piece, zdo);
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Vagon), "Interact")]
	internal static class VagonInteractPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageCarts);
		}

		private static bool Prefix(Vagon __instance, Humanoid __0, bool __1, bool __2, ref bool __result)
		{
			return InteractionGuard.Check((Component)(object)__instance, (Player)(object)((__0 is Player) ? __0 : null), __1, "Cart", ref __result);
		}
	}
	[HarmonyPatch(typeof(Vagon), "GetHoverText")]
	internal static class VagonHoverPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageCarts);
		}

		private static void Postfix(Vagon __instance, ref string __result)
		{
			try
			{
				if (AccessPolicy.TryContext((Component)(object)__instance, null, out var piece, out var _, out var zdo))
				{
					__result = HoverText.Append(__result, piece, zdo);
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(ShipControlls), "Interact")]
	internal static class ShipControlsInteractPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageShips);
		}

		private static bool Prefix(ShipControlls __instance, Humanoid __0, bool __1, bool __2, ref bool __result)
		{
			return InteractionGuard.Check((Component)(object)__instance, (Player)(object)((__0 is Player) ? __0 : null), __1, "Ship controls", ref __result);
		}
	}
	[HarmonyPatch(typeof(ShipControlls), "GetHoverText")]
	internal static class ShipControlsHoverPatch
	{
		private static bool Prepare()
		{
			return Plugin.Enabled(Plugin.ManageShips);
		}

		private static void Postfix(ShipControlls __instance, ref string __result)
		{
			try
			{
				if (AccessPolicy.TryContext((Component)(object)__instance, null, out var piece, out var _, out var zdo))
				{
					__result = HoverText.Append(__result, piece, zdo);
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Player), "RemovePiece")]
	internal static class RemovePiecePatch
	{
		private static readonly FieldInfo RemoveRayMaskField = AccessTools.Field(typeof(Player), "m_removeRayMask");

		private static bool Prefix(Player __instance, ref bool __result)
		{
			//IL_0080: 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_00ad: 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)
			try
			{
				if (Plugin.ProtectConfiguredPieces == null || !Plugin.ProtectConfiguredPieces.Value || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
				{
					return true;
				}
				if ((Object)(object)GameCamera.instance == (Object)null || (Object)(object)((Character)__instance).m_eye == (Object)null)
				{
					return true;
				}
				int num = ((RemoveRayMaskField != null) ? ((int)RemoveRayMaskField.GetValue(__instance)) : (-5));
				RaycastHit val = default(RaycastHit);
				if (!Physics.Raycast(((Component)GameCamera.instance).transform.position, ((Component)GameCamera.instance).transform.forward, ref val, 50f, num))
				{
					return true;
				}
				if (Vector3.Distance(((RaycastHit)(ref val)).point, ((Character)__instance).m_eye.position) >= __instance.m_maxPlaceDistance)
				{
					return true;
				}
				Piece piece = (((Object)(object)((RaycastHit)(ref val)).collider != (Object)null) ? ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Piece>() : null);
				if (!AccessPolicy.IsSupportedPiece(piece))
				{
					return true;
				}
				if (!AccessPolicy.TryContext(piece, out var _, out var zdo))
				{
					return true;
				}
				if (AccessPolicy.CanRemoveOrDamage(piece, zdo, __instance.GetPlayerID(), AccessPolicy.IsLocalAdmin()))
				{
					return true;
				}
				Messages.Center("This protected object can only be dismantled by its owner.");
				__result = false;
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Hammer removal guard failed; falling back to vanilla: " + ex.Message));
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(WearNTear), "RPC_Remove")]
	internal static class WearNTearRemovePatch
	{
		private static bool Prefix(WearNTear __instance, long __0, bool __1)
		{
			try
			{
				long rpcSenderUid = __0;
				if (Plugin.ProtectConfiguredPieces == null || !Plugin.ProtectConfiguredPieces.Value || (Object)(object)__instance == (Object)null)
				{
					return true;
				}
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner())
				{
					return true;
				}
				Piece component2 = ((Component)__instance).GetComponent<Piece>();
				if (!AccessPolicy.IsSupportedPiece(component2))
				{
					return true;
				}
				ZDO zDO = component.GetZDO();
				if (zDO == null)
				{
					return true;
				}
				long num = RpcIdentity.ResolvePlayerId(rpcSenderUid);
				if (num == 0L)
				{
					return true;
				}
				bool num2 = AccessPolicy.CanRemoveOrDamage(component2, zDO, num, RpcIdentity.IsAdmin(rpcSenderUid));
				if (!num2)
				{
					Plugin.Debug("RPC_Remove denied sender=" + rpcSenderUid + " player=" + num);
				}
				return num2;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Server removal guard failed; falling back to vanilla: " + ex.Message));
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(WearNTear), "RPC_Damage")]
	internal static class WearNTearDamagePatch
	{
		private static bool Prefix(WearNTear __instance, long __0, HitData __1)
		{
			try
			{
				long rpcSenderUid = __0;
				if (Plugin.ProtectConfiguredPieces == null || !Plugin.ProtectConfiguredPieces.Value || (Object)(object)__instance == (Object)null)
				{
					return true;
				}
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner())
				{
					return true;
				}
				Piece component2 = ((Component)__instance).GetComponent<Piece>();
				if (!AccessPolicy.IsSupportedPiece(component2))
				{
					return true;
				}
				ZDO zDO = component.GetZDO();
				if (zDO == null || !AccessPolicy.HasEffectiveRestriction(component2, zDO))
				{
					return true;
				}
				long num = RpcIdentity.ResolvePlayerId(rpcSenderUid);
				if (num == 0L && __1 != null)
				{
					Character attacker = __1.GetAttacker();
					Player val = (Player)(object)((attacker is Player) ? attacker : null);
					if ((Object)(object)val != (Object)null)
					{
						num = val.GetPlayerID();
					}
				}
				if (num == 0L)
				{
					return true;
				}
				bool num2 = AccessPolicy.CanRemoveOrDamage(component2, zDO, num, RpcIdentity.IsAdmin(rpcSenderUid));
				if (!num2)
				{
					Plugin.Debug("RPC_Damage denied sender=" + rpcSenderUid + " player=" + num);
				}
				return num2;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Server damage guard failed; falling back to vanilla: " + ex.Message));
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "TakeInput")]
	internal static class PlayerTakeInputPatch
	{
		private static void Postfix(Player __instance, ref bool __result)
		{
			if (AccessPanel.IsOpen && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerController), "TakeInput", new Type[] { typeof(bool) })]
	internal static class PlayerControllerTakeInputPatch
	{
		private static void Postfix(ref bool __result)
		{
			if (AccessPanel.IsOpen)
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
	internal static class MouseCapturePatch
	{
		private static bool Prefix()
		{
			if (!AccessPanel.IsOpen)
			{
				return true;
			}
			Cursor.visible = true;
			Cursor.lockState = (CursorLockMode)0;
			return false;
		}
	}
}