Decompiled source of BackpackPermission v1.1.0

BackpackPermission.dll

Decompiled a week ago
using System;
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 BackpackPermission.Localization;
using BackpackPermission.Permissions;
using BackpackPermission.UI;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.UI;
using Zorro.Core.Serizalization;

[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("PeakCode")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("PEAK mod: decide who may open the backpack on your back.")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+1354f76f2b319cd81337273ba70748df19af5043")]
[assembly: AssemblyProduct("BackpackPermission")]
[assembly: AssemblyTitle("BackpackPermission")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ThomasAusHH/BackpackPermission")]
[assembly: AssemblyVersion("1.1.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 BackpackPermission
{
	internal sealed class ModConfig
	{
		private readonly ConfigEntry<bool> _unlockWhilePassedOut;

		private readonly ConfigEntry<bool> _protectDroppedPack;

		private readonly ConfigEntry<bool> _protectDeathDrop;

		private readonly ConfigEntry<bool> _rememberAllowedPlayers;

		private readonly ConfigEntry<Language> _language;

		private readonly ConfigEntry<float> _panelOffsetX;

		private readonly ConfigEntry<float> _panelWidth;

		private readonly ConfigEntry<float> _panelScale;

		private readonly ConfigEntry<Key> _panelHotkey;

		private readonly ConfigEntry<string> _allowedPlayers;

		private readonly ConfigEntry<bool> _allowEveryone;

		private readonly ConfigEntry<LobbyMode> _lobbyMode;

		private readonly ConfigEntry<string> _hostTeams;

		private readonly ConfigEntry<bool> _hostUnlockWhilePassedOut;

		private readonly ConfigEntry<bool> _hostAllowEveryone;

		private readonly ConfigEntry<bool> _hostDroppedPacksTeamOnly;

		private readonly ConfigEntry<bool> _hostDeathDropsTeamOnly;

		private readonly ConfigEntry<bool> _verbose;

		public bool UnlockWhilePassedOut
		{
			get
			{
				return _unlockWhilePassedOut.Value;
			}
			set
			{
				_unlockWhilePassedOut.Value = value;
			}
		}

		public bool ProtectDroppedPack
		{
			get
			{
				return _protectDroppedPack.Value;
			}
			set
			{
				_protectDroppedPack.Value = value;
			}
		}

		public bool ProtectDeathDrop
		{
			get
			{
				return _protectDeathDrop.Value;
			}
			set
			{
				_protectDeathDrop.Value = value;
			}
		}

		public bool RememberAllowedPlayers => _rememberAllowedPlayers.Value;

		public Language Language => _language.Value;

		public float PanelOffsetX => _panelOffsetX.Value;

		public float PanelWidth => _panelWidth.Value;

		public float PanelScale => _panelScale.Value;

		public Key PanelHotkey => _panelHotkey.Value;

		public string AllowedPlayers
		{
			get
			{
				return _allowedPlayers.Value;
			}
			set
			{
				_allowedPlayers.Value = value;
			}
		}

		public bool AllowEveryone
		{
			get
			{
				return _allowEveryone.Value;
			}
			set
			{
				_allowEveryone.Value = value;
			}
		}

		public LobbyMode LobbyMode
		{
			get
			{
				return _lobbyMode.Value;
			}
			set
			{
				_lobbyMode.Value = value;
			}
		}

		public string HostTeams
		{
			get
			{
				return _hostTeams.Value;
			}
			set
			{
				_hostTeams.Value = value;
			}
		}

		public bool HostUnlockWhilePassedOut
		{
			get
			{
				return _hostUnlockWhilePassedOut.Value;
			}
			set
			{
				_hostUnlockWhilePassedOut.Value = value;
			}
		}

		public bool HostAllowEveryone
		{
			get
			{
				return _hostAllowEveryone.Value;
			}
			set
			{
				_hostAllowEveryone.Value = value;
			}
		}

		public bool HostDroppedPacksTeamOnly
		{
			get
			{
				return _hostDroppedPacksTeamOnly.Value;
			}
			set
			{
				_hostDroppedPacksTeamOnly.Value = value;
			}
		}

		public bool HostDeathDropsTeamOnly
		{
			get
			{
				return _hostDeathDropsTeamOnly.Value;
			}
			set
			{
				_hostDeathDropsTeamOnly.Value = value;
			}
		}

		public bool Verbose => _verbose.Value;

		public ModConfig(ConfigFile file)
		{
			_unlockWhilePassedOut = file.Bind<bool>("General", "UnlockWhilePassedOut", true, "While you are passed out on the ground, everyone may access your backpack (for example to help you). Can also be toggled inside the backpack wheel.");
			_protectDroppedPack = file.Bind<bool>("General", "ProtectDroppedPack", true, "Your permission list keeps applying to your pack after you put it down. Off = anyone may open a pack you dropped.");
			_protectDeathDrop = file.Bind<bool>("General", "ProtectPackAfterDeath", false, "Your permission list keeps applying to your pack after you died. Off = anyone may loot it, as in the base game.");
			_rememberAllowedPlayers = file.Bind<bool>("General", "RememberAllowedPlayers", true, "Remember allowed players and host team assignments by Steam ID so they apply again in the next session.");
			_language = file.Bind<Language>("General", "Language", Language.English, "Language of the in-game texts: English (default), Deutsch, or Auto (follows the game language).");
			_panelOffsetX = file.Bind<float>("UI", "PanelOffsetX", 340f, "Horizontal distance of the access panel from the wheel center (UI pixels).");
			_panelWidth = file.Bind<float>("UI", "PanelWidth", 380f, "Width of the access panel.");
			_panelScale = file.Bind<float>("UI", "PanelScale", 1f, "Scale of the access panel.");
			_panelHotkey = file.Bind<Key>("UI", "PanelHotkey", (Key)100, "Key that opens the Backpack Access panel without a backpack, for example as host without a pack. Press again to close. None disables the hotkey.");
			_allowedPlayers = file.Bind<string>("Saved", "AllowedPlayers", "", "Managed by the mod: comma separated keys (u:<UserId>) of allowed players.");
			_allowEveryone = file.Bind<bool>("Saved", "AllowEveryone", false, "Managed by the mod: true = everyone may access your backpack.");
			_lobbyMode = file.Bind<LobbyMode>("Host", "LobbyMode", LobbyMode.Individual, "Applies when you are the host. Individual: every wearer manages their own list. HostControlled: you assign teams, team mates may access each other's packs and individual lists are ignored. Can also be toggled inside the backpack wheel.");
			_hostTeams = file.Bind<string>("Host", "Teams", "", "Managed by the mod: comma separated team assignments (u:<UserId>=1..4).");
			_hostUnlockWhilePassedOut = file.Bind<bool>("Host", "UnlockWhilePassedOut", true, "Host controlled lobbies: everyone may access the pack of a passed out player.");
			_hostAllowEveryone = file.Bind<bool>("Host", "AllowEveryone", false, "Host controlled lobbies: everyone may access every pack.");
			_hostDroppedPacksTeamOnly = file.Bind<bool>("Host", "DroppedPacksTeamOnly", true, "Host controlled lobbies: a pack a player put down stays restricted to that player's team.");
			_hostDeathDropsTeamOnly = file.Bind<bool>("Host", "DeathDropsTeamOnly", false, "Host controlled lobbies: a pack dropped on death stays restricted to that player's team. Off = anyone may loot it.");
			_verbose = file.Bind<bool>("Debug", "Verbose", false, "Verbose logging, including a UI hierarchy dump.");
		}
	}
	[BepInPlugin("com.peakcode.backpackpermission", "BackpackPermission", "1.1.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.peakcode.backpackpermission";

		public const string Name = "BackpackPermission";

		public const string Version = "1.1.0";

		private RuleSync _ruleSync;

		private LobbySync _lobbySync;

		private Harmony _harmony;

		internal static ManualLogSource Log { get; private set; }

		internal static ModConfig Settings { get; private set; }

		internal static LocalPermissions Permissions { get; private set; }

		internal static HostSettings Host { get; private set; }

		internal static DroppedPackRegistry DroppedPacks { get; private set; }

		private void Awake()
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Settings = new ModConfig(((BaseUnityPlugin)this).Config);
			Permissions = new LocalPermissions(Settings);
			Host = new HostSettings(Settings);
			DroppedPacks = new DroppedPackRegistry();
			_ruleSync = new RuleSync(Permissions);
			_lobbySync = new LobbySync(Host);
			_harmony = new Harmony("com.peakcode.backpackpermission");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"BackpackPermission 1.1.0 loaded. Default: nobody may access your backpack.");
		}

		private void Update()
		{
			_ruleSync.Tick();
			_lobbySync.Tick();
			DroppedPacks.Tick();
			StandalonePanel.Tick();
		}

		private void OnDestroy()
		{
			_ruleSync?.Dispose();
			_lobbySync?.Dispose();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		internal static void LogVerbose(string message)
		{
			if (Settings != null && Settings.Verbose)
			{
				Log.LogInfo((object)message);
			}
		}
	}
}
namespace BackpackPermission.UI
{
	internal static class HudStyle
	{
		private const string OutlineSpriteName = "UI_Blur_Outlne";

		private const float OutlineBorderFraction = 0.45f;

		private const int FillSpriteSize = 64;

		private const float FillCornerRadius = 25f;

		public static readonly Color Shadow = new Color(0f, 0f, 0f, 0.345f);

		public static readonly Color Green = new Color(0.55f, 0.82f, 0.4f, 1f);

		public static readonly Color Red = new Color(0.972f, 0.375f, 0.27f, 1f);

		private static TMP_FontAsset _font;

		private static Material _fontMaterial;

		private static Sprite _outlineSprite;

		private static Sprite _roundedFillSprite;

		private static bool _outlineSearched;

		public static Color Cream { get; private set; } = new Color(0.874f, 0.857f, 0.762f, 1f);

		public static Color Muted => WithAlpha(Cream, 0.8f);

		public static Color TeamColor(int team)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_0068: 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)
			return (Color)(team switch
			{
				1 => Green, 
				2 => new Color(0.45f, 0.72f, 0.95f, 1f), 
				3 => new Color(0.98f, 0.72f, 0.3f, 1f), 
				4 => new Color(0.8f, 0.55f, 0.95f, 1f), 
				_ => Muted, 
			});
		}

		public static void EnsureCaptured(BackpackWheel wheel)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI val = (((Object)(object)wheel != (Object)null) ? wheel.chosenItemText : null);
			if ((Object)(object)val != (Object)null && (Object)(object)((TMP_Text)val).font != (Object)null)
			{
				_font = ((TMP_Text)val).font;
				_fontMaterial = ((TMP_Text)val).fontSharedMaterial;
				Cream = WithAlpha(((Graphic)val).color, 1f);
			}
			else if ((Object)(object)_font == (Object)null)
			{
				_font = TMP_Settings.defaultFontAsset;
				_fontMaterial = null;
			}
			if (!_outlineSearched)
			{
				_outlineSearched = true;
				Sprite val2 = FindSprite("UI_Blur_Outlne");
				_outlineSprite = (((Object)(object)val2 != (Object)null) ? Reslice(val2) : null);
				Plugin.LogVerbose(((Object)(object)_outlineSprite != (Object)null) ? ("Outline sprite: " + ((Object)val2).name + " (resliced)") : "Outline sprite not found, falling back to a plain frame.");
			}
		}

		public static TextMeshProUGUI CreateText(Transform parent, string text, float fontSize, TextAlignmentOptions alignment)
		{
			//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_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)
			GameObject val = new GameObject("Text", new Type[2]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer)
			});
			val.transform.SetParent(parent, false);
			TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val2).font = _font;
			if ((Object)(object)_fontMaterial != (Object)null)
			{
				((TMP_Text)val2).fontSharedMaterial = _fontMaterial;
			}
			((TMP_Text)val2).text = text;
			((TMP_Text)val2).fontSize = fontSize;
			((Graphic)val2).color = Cream;
			((TMP_Text)val2).alignment = alignment;
			((TMP_Text)val2).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)val2).overflowMode = (TextOverflowModes)0;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}

		public static void ApplyOutline(Image image, Color color, float targetHeight)
		{
			//IL_005f: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_outlineSprite == (Object)null)
			{
				image.sprite = null;
				((Graphic)image).color = WithAlpha(color, 0f);
				Outline obj = ((Component)image).gameObject.AddComponent<Outline>();
				((Shadow)obj).effectColor = color;
				((Shadow)obj).effectDistance = new Vector2(2f, -2f);
			}
			else
			{
				image.sprite = _outlineSprite;
				image.type = (Type)1;
				((Graphic)image).color = color;
				image.pixelsPerUnitMultiplier = MultiplierForHeight(image, _outlineSprite, targetHeight);
			}
		}

		private static float MultiplierForHeight(Image image, Sprite sprite, float targetHeight)
		{
			//IL_0033: 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)
			float num = (((Object)(object)((Graphic)image).canvas != (Object)null) ? ((Graphic)image).canvas.referencePixelsPerUnit : 100f);
			float num2 = Mathf.Max(1f, sprite.pixelsPerUnit);
			Rect rect = sprite.rect;
			float num3 = ((Rect)(ref rect)).height * num / (num2 * Mathf.Max(1f, targetHeight));
			return Mathf.Max(0.01f, num3);
		}

		private static Sprite CreateRoundedFillSprite()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_012c: 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_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			int num = 64;
			float num2 = 25f;
			Texture2D val = new Texture2D(num, num, (TextureFormat)4, false)
			{
				wrapMode = (TextureWrapMode)1,
				filterMode = (FilterMode)1,
				name = "BackpackPermission_RoundedFill"
			};
			Color32[] array = (Color32[])(object)new Color32[num * num];
			for (int i = 0; i < num; i++)
			{
				for (int j = 0; j < num; j++)
				{
					float num3 = (float)j + 0.5f;
					float num4 = (float)i + 0.5f;
					float num5 = Mathf.Max(new float[3]
					{
						num2 - num3,
						num3 - ((float)num - num2),
						0f
					});
					float num6 = Mathf.Max(new float[3]
					{
						num2 - num4,
						num4 - ((float)num - num2),
						0f
					});
					float num7 = Mathf.Sqrt(num5 * num5 + num6 * num6);
					float num8 = Mathf.Clamp01(num2 - num7 + 0.5f);
					array[i * num + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)Mathf.RoundToInt(num8 * 255f));
				}
			}
			val.SetPixels32(array);
			val.Apply(false, true);
			float num9 = num2 + 1f;
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4(num9, num9, num9, num9));
			((Object)obj).name = ((Object)val).name;
			return obj;
		}

		public static void ApplyRoundedFill(Image image, Color color, float targetHeight)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_roundedFillSprite == (Object)null)
			{
				_roundedFillSprite = CreateRoundedFillSprite();
			}
			image.sprite = _roundedFillSprite;
			image.type = (Type)1;
			((Graphic)image).color = color;
			image.pixelsPerUnitMultiplier = MultiplierForHeight(image, _roundedFillSprite, targetHeight);
		}

		public static Color WithAlpha(Color color, float alpha)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			color.a = alpha;
			return color;
		}

		private static Sprite FindSprite(string name)
		{
			try
			{
				GUIManager instance = GUIManager.instance;
				if ((Object)(object)instance != (Object)null && instance.items != null)
				{
					InventoryItemUI[] items = instance.items;
					foreach (InventoryItemUI val in items)
					{
						if ((Object)(object)val == (Object)null)
						{
							continue;
						}
						Image[] componentsInChildren = ((Component)val).GetComponentsInChildren<Image>(true);
						foreach (Image val2 in componentsInChildren)
						{
							if ((Object)(object)val2.sprite != (Object)null && ((Object)val2.sprite).name == name)
							{
								return val2.sprite;
							}
						}
					}
				}
				Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>();
				foreach (Sprite val3 in array)
				{
					if ((Object)(object)val3 != (Object)null && ((Object)val3).name == name)
					{
						return val3;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.LogVerbose("Sprite lookup for '" + name + "' failed: " + ex.Message);
			}
			return null;
		}

		private static Sprite Reslice(Sprite source)
		{
			//IL_0001: 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_0023: 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_0039: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Rect rect = source.rect;
				Vector4 val = new Vector4(((Rect)(ref rect)).width, ((Rect)(ref rect)).height, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height) * 0.45f;
				Sprite obj = Sprite.Create(source.texture, rect, new Vector2(0.5f, 0.5f), source.pixelsPerUnit, 0u, (SpriteMeshType)0, val);
				((Object)obj).name = ((Object)source).name + "_Sliced";
				return obj;
			}
			catch (Exception ex)
			{
				Plugin.LogVerbose("Reslicing '" + ((Object)source).name + "' failed: " + ex.Message);
				return source;
			}
		}
	}
	internal sealed class PermissionPanel : MonoBehaviour
	{
		private const float Padding = 12f;

		private const float RowHeight = 46f;

		private const float RowGap = 10f;

		private const float SectionGap = 18f;

		private const float RowTextInset = 18f;

		private const float StatusWidth = 130f;

		private const float OutlineBleed = 4f;

		private const float MinWidth = 260f;

		private const float LineHeightFactor = 1.3f;

		private static bool _hierarchyDumped;

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

		private BackpackWheel _wheel;

		private RectTransform _rect;

		private bool _centered;

		private float _width;

		private float _inner;

		public static PermissionPanel Instance { get; private set; }

		public PermissionRow HoveredRow { get; private set; }

		public static void ShowFor(BackpackWheel wheel)
		{
			if ((Object)(object)wheel == (Object)null)
			{
				return;
			}
			try
			{
				HudStyle.EnsureCaptured(wheel);
				if (Plugin.Settings.Verbose && !_hierarchyDumped)
				{
					_hierarchyDumped = true;
					UiHierarchyDump.Log(wheel);
				}
				PermissionPanel orCreate = GetOrCreate(wheel);
				orCreate.Rebuild();
				((Component)orCreate).gameObject.SetActive(true);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Failed to build the access panel: {arg}");
			}
		}

		public static void HideIfOpen()
		{
			if ((Object)(object)Instance != (Object)null)
			{
				Instance.Hide();
			}
		}

		public void Hide()
		{
			ClearWheelCaption();
			HoveredRow = null;
			((Component)this).gameObject.SetActive(false);
		}

		internal void OnRowClicked(PermissionRow row)
		{
			row.Activate();
			Rebuild();
		}

		internal void OnRowEntered(PermissionRow row)
		{
			HoveredRow = row;
			SetWheelCaption(row.Caption);
		}

		internal void OnRowExited(PermissionRow row)
		{
			if ((Object)(object)HoveredRow == (Object)(object)row)
			{
				HoveredRow = null;
				ClearWheelCaption();
			}
		}

		public void ShowCentered()
		{
			_centered = true;
			Rebuild();
			((Component)this).gameObject.SetActive(true);
		}

		public static PermissionPanel Create(Transform parent, BackpackWheel wheel, string name)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0069: 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_009d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(PermissionPanel)
			});
			val.transform.SetParent(parent, false);
			val.AddComponent<LayoutElement>().ignoreLayout = true;
			PermissionPanel component = val.GetComponent<PermissionPanel>();
			component._wheel = wheel;
			component._rect = val.GetComponent<RectTransform>();
			component._rect.anchorMin = new Vector2(0.5f, 0.5f);
			component._rect.anchorMax = new Vector2(0.5f, 0.5f);
			component._rect.pivot = new Vector2(0f, 0.5f);
			val.SetActive(false);
			return component;
		}

		private static PermissionPanel GetOrCreate(BackpackWheel wheel)
		{
			if ((Object)(object)Instance != (Object)null && (Object)(object)Instance._wheel == (Object)(object)wheel)
			{
				return Instance;
			}
			if ((Object)(object)Instance != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)Instance).gameObject);
			}
			Instance = Create(((Component)wheel).transform, wheel, "BackpackPermissionPanel");
			return Instance;
		}

		private void Rebuild()
		{
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: 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)
			HoveredRow = null;
			foreach (GameObject item in _content)
			{
				if ((Object)(object)item != (Object)null)
				{
					Object.Destroy((Object)(object)item);
				}
			}
			_content.Clear();
			_width = Mathf.Max(260f, Plugin.Settings.PanelWidth);
			_inner = _width - 24f;
			float num = 0f;
			num -= AddLabel(Strings.Title, 32f, num, 1f) + 2f;
			bool num2 = PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient;
			LobbyRule rule;
			bool flag = LobbySync.TryReadRule(out rule);
			bool flag2 = flag && rule.Mode == LobbyMode.HostControlled;
			num = (num2 ? BuildHostView(num, Plugin.Host.Mode == LobbyMode.HostControlled) : ((!flag2) ? BuildIndividualView(num, flag) : BuildTeamOverview(num, rule)));
			if ((Object)(object)_wheel == (Object)null)
			{
				num -= 18f;
				num -= AddLabel(Strings.CloseHint(((object)Plugin.Settings.PanelHotkey/*cast due to .constrained prefix*/).ToString()), 15f, num, 0.7f);
			}
			_rect.sizeDelta = new Vector2(_width, 0f - num);
			_rect.anchoredPosition = new Vector2(_centered ? ((0f - _width) / 2f) : Plugin.Settings.PanelOffsetX, 0f);
			((Component)this).transform.localScale = Vector3.one * Mathf.Max(0.3f, Plugin.Settings.PanelScale);
		}

		private float BuildIndividualView(float y, bool showModeRow)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			LocalPermissions permissions = Plugin.Permissions;
			y -= AddLabel(Strings.Hint, 16f, y, 0.75f) + 14f;
			if (showModeRow)
			{
				y -= AddRow(Strings.LobbyMode, Strings.ModeIndividual, HudStyle.Muted, null, null, y) + 10f;
			}
			return BuildIndividualRows(y, permissions);
		}

		private float BuildIndividualRows(float y, LocalPermissions permissions)
		{
			y -= AddChoiceRow(Strings.WornPack, !permissions.AllowEveryone, Strings.MyList, Strings.Everyone, permissions.ToggleAllowEveryone, y) + 10f;
			y -= AddChoiceRow(Strings.WhilePassedOut, !permissions.UnlockWhilePassedOut, Strings.MyList, Strings.Everyone, permissions.ToggleUnlockWhilePassedOut, y) + 10f;
			y -= AddChoiceRow(Strings.DroppedPack, permissions.ProtectDroppedPack, Strings.MyList, Strings.Everyone, permissions.ToggleProtectDroppedPack, y) + 10f;
			y -= AddChoiceRow(Strings.AfterDeath, permissions.ProtectDeathDrop, Strings.MyList, Strings.Everyone, permissions.ToggleProtectDeathDrop, y) + 18f;
			y -= AddLabel(Strings.Players, 22f, y, 1f) + 8f;
			List<Player> list = OtherPlayers();
			if (list.Count == 0)
			{
				return y - AddLabel(Strings.NoOtherPlayers, 17f, y, 0.75f);
			}
			foreach (Player item in list)
			{
				y -= AddPlayerPermissionRow(item, permissions, y) + 10f;
			}
			return y - AddLabel(Strings.Summary(permissions.CountGranted(list), list.Count), 16f, y, 0.75f);
		}

		private float BuildHostView(float y, bool hostControlled)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			HostSettings host = Plugin.Host;
			y -= AddLabel(hostControlled ? Strings.HostHint : Strings.Hint, 16f, y, 0.75f) + 14f;
			y -= AddRow(Strings.LobbyMode, hostControlled ? Strings.ModeHost : Strings.ModeIndividual, hostControlled ? HudStyle.Green : HudStyle.Muted, hostControlled ? Strings.SwitchToIndividualMode : Strings.SwitchToHostMode, host.ToggleMode, y) + 10f;
			if (!hostControlled)
			{
				return BuildIndividualRows(y, Plugin.Permissions);
			}
			y -= AddChoiceRow(Strings.WornPack, !host.AllowEveryone, Strings.TeamOnly, Strings.Everyone, host.ToggleAllowEveryone, y) + 10f;
			y -= AddChoiceRow(Strings.WhilePassedOut, !host.UnlockWhilePassedOut, Strings.TeamOnly, Strings.Everyone, host.ToggleUnlockWhilePassedOut, y) + 10f;
			y -= AddChoiceRow(Strings.DroppedPack, host.DroppedPacksTeamOnly, Strings.TeamOnly, Strings.Everyone, host.ToggleDroppedPacksTeamOnly, y) + 10f;
			y -= AddChoiceRow(Strings.AfterDeath, host.DeathDropsTeamOnly, Strings.TeamOnly, Strings.Everyone, host.ToggleDeathDropsTeamOnly, y) + 18f;
			y -= AddLabel(Strings.Teams, 22f, y, 1f) + 8f;
			foreach (Player player in AllPlayers())
			{
				int num = host.TeamOf(player);
				int team = (num + 1) % 5;
				string text = DisplayName(player);
				y -= AddRow(text, Strings.TeamOrNone(LobbyRule.TeamName(num)), HudStyle.TeamColor(num), Strings.MoveToTeam(text, LobbyRule.TeamName(team)), delegate
				{
					host.CycleTeam(player);
				}, y) + 10f;
			}
			return y;
		}

		private float BuildTeamOverview(float y, LobbyRule lobby)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			y -= AddLabel(Strings.HostManagesHint, 16f, y, 0.75f) + 14f;
			y -= AddRow(Strings.LobbyMode, Strings.ModeHost, HudStyle.Green, null, null, y) + 10f;
			y -= AddReadOnlyChoiceRow(Strings.WornPack, !lobby.AllowEveryone, y) + 10f;
			y -= AddReadOnlyChoiceRow(Strings.WhilePassedOut, !lobby.UnlockWhilePassedOut, y) + 10f;
			y -= AddReadOnlyChoiceRow(Strings.DroppedPack, lobby.DroppedPacksTeamOnly, y) + 10f;
			y -= AddReadOnlyChoiceRow(Strings.AfterDeath, lobby.DeathDropsTeamOnly, y) + 18f;
			y -= AddLabel(Strings.YourTeam(LobbyRule.TeamName(lobby.TeamOf(PhotonNetwork.LocalPlayer))), 22f, y, 1f) + 8f;
			foreach (Player item in AllPlayers())
			{
				int team = lobby.TeamOf(item);
				y -= AddRow(DisplayName(item), Strings.TeamOrNone(LobbyRule.TeamName(team)), HudStyle.TeamColor(team), null, null, y) + 10f;
			}
			return y;
		}

		private float AddReadOnlyChoiceRow(string label, bool teamOnly, float y)
		{
			//IL_001b: 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)
			return AddRow(label, teamOnly ? Strings.TeamOnly : Strings.Everyone, teamOnly ? HudStyle.Green : HudStyle.Muted, null, null, y);
		}

		private float AddChoiceRow(string label, bool restricted, string restrictedText, string openText, Action toggle, float y)
		{
			//IL_001f: 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)
			string status = (restricted ? restrictedText : openText);
			string value = (restricted ? openText : restrictedText);
			return AddRow(label, status, restricted ? HudStyle.Green : HudStyle.Muted, Strings.SetTo(label, value), toggle, y);
		}

		private float AddPlayerPermissionRow(Player player, LocalPermissions permissions, float y)
		{
			//IL_003e: 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_0043: 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_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_008a: Unknown result type (might be due to invalid IL or missing references)
			bool flag = permissions.IsListed(player);
			bool flag2 = permissions.AllowEveryone || flag;
			Color val = (flag2 ? HudStyle.Green : HudStyle.Red);
			if (flag2 && !flag)
			{
				val = HudStyle.WithAlpha(val, 0.6f);
			}
			string text = DisplayName(player);
			string caption = (flag ? Strings.LockPlayer(text) : Strings.AllowPlayer(text));
			return AddRow(text, flag2 ? Strings.Allowed : Strings.Locked, val, caption, delegate
			{
				permissions.Toggle(player);
			}, y);
		}

		private float AddRow(string label, string status, Color statusColor, string caption, Action onActivate, float y)
		{
			//IL_0056: 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_00cb: 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_0138: 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_01bb: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = CreateRect("Row", ((Component)this).transform, 12f, y, _inner, 46f, typeof(CanvasRenderer), typeof(Image));
			_content.Add(val);
			Image component = val.GetComponent<Image>();
			HudStyle.ApplyRoundedFill(component, HudStyle.Shadow, 46f);
			((Graphic)component).raycastTarget = onActivate != null;
			Image component2 = CreateRect("Fill", val.transform, 3f, -3f, _inner - 6f, 40f, typeof(CanvasRenderer), typeof(Image)).GetComponent<Image>();
			HudStyle.ApplyRoundedFill(component2, HudStyle.WithAlpha(HudStyle.Cream, 0f), 40f);
			((Graphic)component2).raycastTarget = false;
			float num = 54f;
			Image component3 = CreateRect("Outline", val.transform, -4f, 4f, _inner + 8f, num, typeof(CanvasRenderer), typeof(Image)).GetComponent<Image>();
			HudStyle.ApplyOutline(component3, (onActivate != null) ? HudStyle.Cream : HudStyle.WithAlpha(HudStyle.Cream, 0.6f), num);
			((Graphic)component3).raycastTarget = false;
			float width = _inner - 130f - 36f;
			TextMeshProUGUI obj = HudStyle.CreateText(val.transform, label, 21f, (TextAlignmentOptions)4097);
			((TMP_Text)obj).overflowMode = (TextOverflowModes)1;
			Place(((TMP_Text)obj).rectTransform, 18f, 0f, width, 46f);
			TextMeshProUGUI obj2 = HudStyle.CreateText(val.transform, status, 20f, (TextAlignmentOptions)4100);
			((Graphic)obj2).color = statusColor;
			Place(((TMP_Text)obj2).rectTransform, _inner - 18f - 2f - 130f, 0f, 130f, 46f);
			val.AddComponent<PermissionRow>().Initialize(this, component2, caption, onActivate);
			return 46f;
		}

		private float AddLabel(string text, float fontSize, float y, float alpha)
		{
			//IL_001d: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			float num = fontSize * 1.3f;
			TextMeshProUGUI val = HudStyle.CreateText(((Component)this).transform, text, fontSize, (TextAlignmentOptions)4097);
			((Graphic)val).color = HudStyle.WithAlpha(((Graphic)val).color, ((Graphic)val).color.a * alpha);
			Place(((TMP_Text)val).rectTransform, 12f, y, _inner, num);
			_content.Add(((Component)val).gameObject);
			return num;
		}

		private void SetWheelCaption(string text)
		{
			if ((Object)(object)_wheel != (Object)null && (Object)(object)_wheel.chosenItemText != (Object)null)
			{
				((TMP_Text)_wheel.chosenItemText).text = text ?? string.Empty;
			}
		}

		private void ClearWheelCaption()
		{
			if ((Object)(object)_wheel != (Object)null && (Object)(object)_wheel.chosenItemText != (Object)null && _wheel.chosenSlice.IsNone)
			{
				((TMP_Text)_wheel.chosenItemText).text = string.Empty;
			}
		}

		private static List<Player> OtherPlayers()
		{
			if (!PhotonNetwork.InRoom)
			{
				return new List<Player>();
			}
			return PhotonNetwork.PlayerListOthers.OrderBy((Player p) => p.ActorNumber).ToList();
		}

		private static List<Player> AllPlayers()
		{
			if (!PhotonNetwork.InRoom)
			{
				return new List<Player>();
			}
			return PhotonNetwork.PlayerList.OrderBy((Player p) => p.ActorNumber).ToList();
		}

		private static GameObject CreateRect(string name, Transform parent, float x, float y, float width, float height, params Type[] components)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_004d: Expected O, but got Unknown
			Type[] array = new Type[components.Length + 1];
			array[0] = typeof(RectTransform);
			Array.Copy(components, 0, array, 1, components.Length);
			GameObject val = new GameObject(name, array);
			val.transform.SetParent(parent, false);
			Place(val.GetComponent<RectTransform>(), x, y, width, height);
			return val;
		}

		private static void Place(RectTransform rect, float x, float y, float width, float height)
		{
			//IL_000b: 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_0035: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(0f, 1f);
			rect.anchorMax = new Vector2(0f, 1f);
			rect.pivot = new Vector2(0f, 1f);
			rect.anchoredPosition = new Vector2(x, y);
			rect.sizeDelta = new Vector2(width, height);
		}

		private static string DisplayName(Player player)
		{
			string text = null;
			try
			{
				Character playerCharacter = PlayerHandler.GetPlayerCharacter(player);
				if ((Object)(object)playerCharacter != (Object)null && !string.IsNullOrEmpty(playerCharacter.characterName))
				{
					text = playerCharacter.characterName;
				}
			}
			catch
			{
			}
			if (string.IsNullOrEmpty(text))
			{
				text = (string.IsNullOrEmpty(player.NickName) ? Strings.FallbackPlayerName(player.ActorNumber) : player.NickName);
			}
			if (!player.IsLocal)
			{
				return text;
			}
			return text + " (" + Strings.You + ")";
		}
	}
	internal sealed class PermissionRow : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler, IPointerClickHandler
	{
		private const float HoverFillAlpha = 0.35f;

		private const float HoverScale = 1.04f;

		private PermissionPanel _panel;

		private Image _fill;

		private Action _onActivate;

		public string Caption { get; private set; }

		public bool Interactive => _onActivate != null;

		public void Initialize(PermissionPanel panel, Image fill, string caption, Action onActivate)
		{
			_panel = panel;
			_fill = fill;
			Caption = caption;
			_onActivate = onActivate;
		}

		public void OnPointerClick(PointerEventData eventData)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (Interactive && (int)eventData.button == 0)
			{
				_panel?.OnRowClicked(this);
			}
		}

		public void Activate()
		{
			_onActivate?.Invoke();
		}

		public void OnPointerEnter(PointerEventData eventData)
		{
			if (Interactive)
			{
				SetHighlighted(highlighted: true);
				_panel?.OnRowEntered(this);
			}
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			Leave();
		}

		private void OnDisable()
		{
			Leave();
		}

		private void Leave()
		{
			SetHighlighted(highlighted: false);
			_panel?.OnRowExited(this);
		}

		private void SetHighlighted(bool highlighted)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_fill != (Object)null)
			{
				((Graphic)_fill).color = HudStyle.WithAlpha(((Graphic)_fill).color, highlighted ? 0.35f : 0f);
			}
			((Component)this).transform.localScale = (highlighted ? (Vector3.one * 1.04f) : Vector3.one);
		}
	}
	internal static class StandalonePanel
	{
		private static PermissionPanel _panel;

		public static bool IsOpen
		{
			get
			{
				if ((Object)(object)_panel != (Object)null)
				{
					return ((Component)_panel).gameObject.activeSelf;
				}
				return false;
			}
		}

		public static void Tick()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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)
			if (IsOpen && (!PhotonNetwork.InRoom || (Object)(object)Character.localCharacter == (Object)null))
			{
				Close();
				return;
			}
			Key panelHotkey = Plugin.Settings.PanelHotkey;
			if ((int)panelHotkey != 0 && Keyboard.current != null && ((ButtonControl)Keyboard.current[panelHotkey]).wasPressedThisFrame)
			{
				if (IsOpen)
				{
					Close();
				}
				else
				{
					TryOpen();
				}
			}
		}

		public static void Close()
		{
			if ((Object)(object)_panel != (Object)null)
			{
				_panel.Hide();
			}
		}

		private static void TryOpen()
		{
			GUIManager instance = GUIManager.instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.backpackWheel == (Object)null) && !((Object)(object)Character.localCharacter == (Object)null) && !instance.wheelActive && !instance.windowBlockingInput && !GUIManager.InPauseMenu && !Character.localCharacter.data.dead)
			{
				BackpackWheel backpackWheel = instance.backpackWheel;
				HudStyle.EnsureCaptured(backpackWheel);
				Transform parent = (((Object)(object)((Component)backpackWheel).transform.parent != (Object)null) ? ((Component)backpackWheel).transform.parent : ((Component)backpackWheel).transform);
				if ((Object)(object)_panel == (Object)null)
				{
					_panel = PermissionPanel.Create(parent, null, "BackpackPermissionStandalonePanel");
				}
				_panel.ShowCentered();
			}
		}
	}
	internal static class UiHierarchyDump
	{
		private const int MaxDepth = 4;

		public static void Log(BackpackWheel wheel)
		{
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("=== BackpackWheel hierarchy ===");
				Append(((Component)wheel).transform, 0, stringBuilder);
				GUIManager instance = GUIManager.instance;
				if ((Object)(object)instance != (Object)null && instance.items != null && instance.items.Length != 0 && (Object)(object)instance.items[0] != (Object)null)
				{
					stringBuilder.AppendLine("=== Hotbar slot 0 ===");
					Append(((Component)instance.items[0]).transform, 0, stringBuilder);
				}
				Plugin.Log.LogInfo((object)stringBuilder.ToString());
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("UI hierarchy dump failed: " + ex.Message));
			}
		}

		private static void Append(Transform node, int depth, StringBuilder sb)
		{
			//IL_0046: 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)
			//IL_005c: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			if (depth <= 4)
			{
				sb.Append(' ', depth * 2).Append(((Object)node).name);
				if (!((Component)node).gameObject.activeSelf)
				{
					sb.Append(" (inactive)");
				}
				RectTransform val = (RectTransform)(object)((node is RectTransform) ? node : null);
				if (val != null)
				{
					sb.Append($" size={val.sizeDelta} pos={val.anchoredPosition} scale={((Transform)val).localScale}");
				}
				Image val2 = default(Image);
				if (((Component)node).TryGetComponent<Image>(ref val2))
				{
					sb.Append($" | Image sprite={NameOf((Object)(object)val2.sprite)} type={val2.type} color={((Graphic)val2).color}");
				}
				RawImage val3 = default(RawImage);
				if (((Component)node).TryGetComponent<RawImage>(ref val3))
				{
					sb.Append(" | RawImage tex=" + NameOf((Object)(object)val3.texture));
				}
				TextMeshProUGUI val4 = default(TextMeshProUGUI);
				if (((Component)node).TryGetComponent<TextMeshProUGUI>(ref val4))
				{
					sb.Append($" | TMP font={NameOf((Object)(object)((TMP_Text)val4).font)} mat={NameOf((Object)(object)((TMP_Text)val4).fontSharedMaterial)} size={((TMP_Text)val4).fontSize} color={((Graphic)val4).color} text='{((TMP_Text)val4).text}'");
				}
				sb.AppendLine();
				for (int i = 0; i < node.childCount; i++)
				{
					Append(node.GetChild(i), depth + 1, sb);
				}
			}
		}

		private static string NameOf(Object obj)
		{
			if (!(obj != (Object)null))
			{
				return "null";
			}
			return obj.name;
		}
	}
}
namespace BackpackPermission.Permissions
{
	internal enum AccessVerdict
	{
		GrantedByRule,
		GrantedByTeam,
		GrantedSelf,
		GrantedNoRule,
		GrantedDead,
		GrantedPassedOut,
		GrantedUnprotectedDrop,
		Denied
	}
	internal static class AccessVerdictExtensions
	{
		public static bool IsGranted(this AccessVerdict verdict)
		{
			return verdict != AccessVerdict.Denied;
		}
	}
	internal static class AccessPolicy
	{
		public static AccessVerdict Evaluate(Character wearer, Player requester)
		{
			if ((Object)(object)wearer == (Object)null || requester == null || wearer.isBot)
			{
				return AccessVerdict.GrantedNoRule;
			}
			Player val = (((Object)(object)((MonoBehaviourPun)wearer).photonView != (Object)null) ? ((MonoBehaviourPun)wearer).photonView.Owner : null);
			if (val == null)
			{
				return AccessVerdict.GrantedNoRule;
			}
			if (val.ActorNumber == requester.ActorNumber)
			{
				return AccessVerdict.GrantedSelf;
			}
			CharacterData data = wearer.data;
			if ((Object)(object)data != (Object)null && data.dead)
			{
				return AccessVerdict.GrantedDead;
			}
			bool flag = (Object)(object)data != (Object)null && (data.passedOut || data.fullyPassedOut);
			if (LobbySync.IsHostControlled(out var rule))
			{
				if (rule.UnlockWhilePassedOut && flag)
				{
					return AccessVerdict.GrantedPassedOut;
				}
				if (!rule.Grants(val, requester))
				{
					return AccessVerdict.Denied;
				}
				return AccessVerdict.GrantedByTeam;
			}
			if (!RuleSync.TryReadRule(val, out var rule2))
			{
				return AccessVerdict.GrantedNoRule;
			}
			if (rule2.UnlockWhilePassedOut && flag)
			{
				return AccessVerdict.GrantedPassedOut;
			}
			if (!rule2.Grants(requester))
			{
				return AccessVerdict.Denied;
			}
			return AccessVerdict.GrantedByRule;
		}

		public static AccessVerdict EvaluateDropped(int packViewId, Player requester)
		{
			if (requester == null || !TryGetDroppedPackOwner(packViewId, out var owner, out var cause))
			{
				return AccessVerdict.GrantedNoRule;
			}
			if (owner.ActorNumber == requester.ActorNumber)
			{
				return AccessVerdict.GrantedSelf;
			}
			if (LobbySync.IsHostControlled(out var rule))
			{
				if (!rule.Protects(cause))
				{
					return AccessVerdict.GrantedUnprotectedDrop;
				}
				if (!rule.Grants(owner, requester))
				{
					return AccessVerdict.Denied;
				}
				return AccessVerdict.GrantedByTeam;
			}
			if (!RuleSync.TryReadRule(owner, out var rule2))
			{
				return AccessVerdict.GrantedNoRule;
			}
			if (!rule2.Protects(cause))
			{
				return AccessVerdict.GrantedUnprotectedDrop;
			}
			if (!rule2.Grants(requester))
			{
				return AccessVerdict.Denied;
			}
			return AccessVerdict.GrantedByRule;
		}

		public static bool TryGetDroppedPackOwner(int packViewId, out Player owner, out DropCause cause)
		{
			owner = null;
			if (!DroppedPackRegistry.TryGet(packViewId, out var ownerActor, out cause))
			{
				return false;
			}
			Room currentRoom = PhotonNetwork.CurrentRoom;
			owner = ((currentRoom != null) ? currentRoom.GetPlayer(ownerActor, false) : null);
			return owner != null;
		}

		public static bool IsAllowed(Character wearer, Player requester)
		{
			return Evaluate(wearer, requester).IsGranted();
		}

		public static bool LocalPlayerMayAccess(Character wearer)
		{
			return IsAllowed(wearer, PhotonNetwork.LocalPlayer);
		}

		public static bool LocalPlayerMayAccess(BackpackReference reference)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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)
			if ((Object)(object)reference.view == (Object)null)
			{
				return true;
			}
			if ((int)reference.type == 0)
			{
				return EvaluateDropped(reference.view.ViewID, PhotonNetwork.LocalPlayer).IsGranted();
			}
			Character component = ((Component)reference.view).GetComponent<Character>();
			if (!((Object)(object)component == (Object)null) && !component.IsLocal)
			{
				return LocalPlayerMayAccess(component);
			}
			return true;
		}

		public static bool IsLockedForLocalPlayer(Character wearer)
		{
			if ((Object)(object)wearer != (Object)null && !wearer.IsLocal)
			{
				return !LocalPlayerMayAccess(wearer);
			}
			return false;
		}

		public static bool IsDroppedPackLockedForLocalPlayer(Backpack pack)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)pack != (Object)null && (int)((Item)pack).itemState == 0 && (Object)(object)((MonoBehaviourPun)pack).photonView != (Object)null)
			{
				return !EvaluateDropped(((MonoBehaviourPun)pack).photonView.ViewID, PhotonNetwork.LocalPlayer).IsGranted();
			}
			return false;
		}
	}
	internal sealed class AccessRule
	{
		public const int FormatVersion = 1;

		private const char FieldSeparator = '|';

		private const char KeySeparator = ',';

		private readonly HashSet<PlayerKey> _allowedPlayers;

		public bool AllowEveryone { get; }

		public bool UnlockWhilePassedOut { get; }

		public bool ProtectDroppedPack { get; }

		public bool ProtectDeathDrop { get; }

		public IReadOnlyCollection<PlayerKey> AllowedPlayers => _allowedPlayers;

		public AccessRule(bool allowEveryone, bool unlockWhilePassedOut, IEnumerable<PlayerKey> allowedPlayers, bool protectDroppedPack = true, bool protectDeathDrop = false)
		{
			AllowEveryone = allowEveryone;
			UnlockWhilePassedOut = unlockWhilePassedOut;
			ProtectDroppedPack = protectDroppedPack;
			ProtectDeathDrop = protectDeathDrop;
			_allowedPlayers = new HashSet<PlayerKey>(allowedPlayers ?? Enumerable.Empty<PlayerKey>());
		}

		public bool Protects(DropCause cause)
		{
			if (cause != DropCause.Death)
			{
				return ProtectDroppedPack;
			}
			return ProtectDeathDrop;
		}

		public bool Grants(Player requester)
		{
			if (AllowEveryone)
			{
				return true;
			}
			if (!PlayerKey.TryFrom(requester, out var key))
			{
				return false;
			}
			if (!_allowedPlayers.Contains(key))
			{
				return _allowedPlayers.Contains(PlayerKey.ForActor(requester.ActorNumber));
			}
			return true;
		}

		public string Serialize()
		{
			string text = string.Join(','.ToString(), _allowedPlayers.Select((PlayerKey k) => k.Value));
			return string.Join('|'.ToString(), 1.ToString(), Flag(AllowEveryone), Flag(UnlockWhilePassedOut), text, Flag(ProtectDroppedPack), Flag(ProtectDeathDrop));
		}

		public static bool TryParse(string raw, out AccessRule rule)
		{
			rule = null;
			if (string.IsNullOrEmpty(raw))
			{
				return false;
			}
			string[] array = raw.Split('|');
			if (array.Length < 4 || array[0] != 1.ToString())
			{
				return false;
			}
			List<PlayerKey> list = new List<PlayerKey>();
			string[] array2 = array[3].Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array2.Length; i++)
			{
				if (PlayerKey.TryParse(array2[i], out var key))
				{
					list.Add(key);
				}
			}
			bool protectDroppedPack = array.Length > 4 && array[4] == "1";
			bool protectDeathDrop = array.Length > 5 && array[5] == "1";
			rule = new AccessRule(array[1] == "1", array[2] == "1", list, protectDroppedPack, protectDeathDrop);
			return true;
		}

		private static string Flag(bool value)
		{
			if (!value)
			{
				return "0";
			}
			return "1";
		}
	}
	internal enum DropCause
	{
		Manual,
		Death
	}
	internal sealed class DroppedPackRegistry
	{
		private struct Entry
		{
			public int OwnerActor;

			public DropCause Cause;
		}

		public const string PropertyKey = "bpk_drops";

		private const float CleanupIntervalSeconds = 2f;

		private const char EntrySeparator = ',';

		private const char FieldSeparator = ':';

		private readonly Dictionary<int, Entry> _local = new Dictionary<int, Entry>();

		private bool _dirty;

		private float _lastCleanupTime;

		private static string _cachedRaw;

		private static Dictionary<int, Entry> _cachedEntries = new Dictionary<int, Entry>();

		public void Register(int viewId, int ownerActor, DropCause cause)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				_local[viewId] = new Entry
				{
					OwnerActor = ownerActor,
					Cause = cause
				};
				_dirty = true;
				Plugin.LogVerbose($"Dropped pack {viewId} registered: owner actor {ownerActor}, cause {cause}");
			}
		}

		public static bool TryGet(int viewId, out int ownerActor, out DropCause cause)
		{
			ownerActor = 0;
			cause = DropCause.Manual;
			Dictionary<int, Entry> dictionary = ((!PhotonNetwork.IsMasterClient || Plugin.DroppedPacks == null) ? ReadShared() : Plugin.DroppedPacks._local);
			if (dictionary == null || !dictionary.TryGetValue(viewId, out var value))
			{
				return false;
			}
			ownerActor = value.OwnerActor;
			cause = value.Cause;
			return true;
		}

		public void Tick()
		{
			if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient)
			{
				if (_local.Count > 0)
				{
					_local.Clear();
				}
				return;
			}
			if (Time.unscaledTime - _lastCleanupTime > 2f)
			{
				_lastCleanupTime = Time.unscaledTime;
				RemoveStaleEntries();
			}
			if (_dirty)
			{
				Publish();
			}
		}

		private void RemoveStaleEntries()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			List<int> list = null;
			foreach (int key in _local.Keys)
			{
				PhotonView val = PhotonView.Find(key);
				Item val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Item>() : null);
				if ((Object)(object)val2 == (Object)null || (int)val2.itemState != 0)
				{
					(list ?? (list = new List<int>())).Add(key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (int item in list)
			{
				_local.Remove(item);
			}
			_dirty = true;
		}

		private void Publish()
		{
			//IL_003f: 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_0050: Expected O, but got Unknown
			//IL_0057: Expected O, but got Unknown
			string text = string.Join(','.ToString(), _local.Select((KeyValuePair<int, Entry> e) => $"{e.Key}{':'}{e.Value.OwnerActor}{':'}{(int)e.Value.Cause}"));
			Room currentRoom = PhotonNetwork.CurrentRoom;
			Hashtable val = new Hashtable();
			((Dictionary<object, object>)val).Add((object)"bpk_drops", (object)text);
			currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
			_dirty = false;
			Plugin.LogVerbose("Dropped packs published: " + ((text.Length == 0) ? "(none)" : text));
		}

		private static Dictionary<int, Entry> ReadShared()
		{
			Room currentRoom = PhotonNetwork.CurrentRoom;
			Hashtable val = ((currentRoom != null) ? ((RoomInfo)currentRoom).CustomProperties : null);
			if (val == null || !((Dictionary<object, object>)(object)val).TryGetValue((object)"bpk_drops", out object value) || !(value is string text))
			{
				return null;
			}
			if ((object)text == _cachedRaw || text == _cachedRaw)
			{
				return _cachedEntries;
			}
			Dictionary<int, Entry> dictionary = new Dictionary<int, Entry>();
			string[] array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(':');
				if (array2.Length == 3 && int.TryParse(array2[0], out var result) && int.TryParse(array2[1], out var result2) && int.TryParse(array2[2], out var result3) && Enum.IsDefined(typeof(DropCause), result3))
				{
					dictionary[result] = new Entry
					{
						OwnerActor = result2,
						Cause = (DropCause)result3
					};
				}
			}
			_cachedRaw = text;
			_cachedEntries = dictionary;
			return dictionary;
		}
	}
	internal sealed class HostSettings
	{
		private const char EntrySeparator = ',';

		private const char AssignmentSeparator = '=';

		private readonly ModConfig _config;

		private readonly Dictionary<PlayerKey, int> _teams = new Dictionary<PlayerKey, int>();

		public LobbyMode Mode
		{
			get
			{
				return _config.LobbyMode;
			}
			private set
			{
				_config.LobbyMode = value;
				this.Changed?.Invoke();
			}
		}

		public bool UnlockWhilePassedOut
		{
			get
			{
				return _config.HostUnlockWhilePassedOut;
			}
			private set
			{
				_config.HostUnlockWhilePassedOut = value;
				this.Changed?.Invoke();
			}
		}

		public bool AllowEveryone
		{
			get
			{
				return _config.HostAllowEveryone;
			}
			private set
			{
				_config.HostAllowEveryone = value;
				this.Changed?.Invoke();
			}
		}

		public bool DroppedPacksTeamOnly
		{
			get
			{
				return _config.HostDroppedPacksTeamOnly;
			}
			private set
			{
				_config.HostDroppedPacksTeamOnly = value;
				this.Changed?.Invoke();
			}
		}

		public bool DeathDropsTeamOnly
		{
			get
			{
				return _config.HostDeathDropsTeamOnly;
			}
			private set
			{
				_config.HostDeathDropsTeamOnly = value;
				this.Changed?.Invoke();
			}
		}

		public event Action Changed;

		public HostSettings(ModConfig config)
		{
			_config = config ?? throw new ArgumentNullException("config");
			Load();
		}

		public void ToggleDroppedPacksTeamOnly()
		{
			DroppedPacksTeamOnly = !DroppedPacksTeamOnly;
			Plugin.Log.LogInfo((object)("Host: dropped packs " + (DroppedPacksTeamOnly ? "team only" : "open to everyone")));
		}

		public void ToggleDeathDropsTeamOnly()
		{
			DeathDropsTeamOnly = !DeathDropsTeamOnly;
			Plugin.Log.LogInfo((object)("Host: packs dropped on death " + (DeathDropsTeamOnly ? "team only" : "open to everyone")));
		}

		public int TeamOf(Player player)
		{
			if (!PlayerKey.TryFrom(player, out var key) || !_teams.TryGetValue(key, out var value))
			{
				return 0;
			}
			return value;
		}

		public void CycleTeam(Player player)
		{
			if (PlayerKey.TryFrom(player, out var key))
			{
				int num = (TeamOf(player) + 1) % 5;
				if (num == 0)
				{
					_teams.Remove(key);
				}
				else
				{
					_teams[key] = num;
				}
				Plugin.Log.LogInfo((object)("Team for " + player.NickName + ": " + (LobbyRule.TeamName(num) ?? "none")));
				Save();
				this.Changed?.Invoke();
			}
		}

		public void ToggleMode()
		{
			Mode = ((Mode == LobbyMode.Individual) ? LobbyMode.HostControlled : LobbyMode.Individual);
			Plugin.Log.LogInfo((object)$"Lobby mode: {Mode}");
		}

		public void ToggleAllowEveryone()
		{
			AllowEveryone = !AllowEveryone;
			Plugin.Log.LogInfo((object)("Host: allow everyone " + (AllowEveryone ? "on" : "off")));
		}

		public void ToggleUnlockWhilePassedOut()
		{
			UnlockWhilePassedOut = !UnlockWhilePassedOut;
			Plugin.Log.LogInfo((object)("Host: unlock while passed out " + (UnlockWhilePassedOut ? "on" : "off")));
		}

		public LobbyRule ToRule(int hostActorNumber)
		{
			return new LobbyRule(Mode, hostActorNumber, UnlockWhilePassedOut, AllowEveryone, _teams, DroppedPacksTeamOnly, DeathDropsTeamOnly);
		}

		private void Load()
		{
			_teams.Clear();
			string[] array = _config.HostTeams.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text in array)
			{
				int num = text.LastIndexOf('=');
				if (num > 0 && PlayerKey.TryParse(text.Substring(0, num), out var key) && int.TryParse(text.Substring(num + 1), out var result) && result > 0 && result <= 4)
				{
					_teams[key] = result;
				}
			}
			Plugin.LogVerbose($"Host settings loaded: mode={Mode}, {_teams.Count} team assignments");
		}

		private void Save()
		{
			_config.HostTeams = string.Join(','.ToString(), from t in _teams
				where t.Key.IsPersistent
				select t.Key.Value + "=" + t.Value);
		}
	}
	public enum LobbyMode
	{
		Individual,
		HostControlled
	}
	internal sealed class LobbyRule
	{
		public const int FormatVersion = 1;

		public const int TeamCount = 4;

		public const int NoTeam = 0;

		private const char FieldSeparator = '|';

		private const char EntrySeparator = ',';

		private const char AssignmentSeparator = '=';

		private readonly Dictionary<PlayerKey, int> _teams;

		public LobbyMode Mode { get; }

		public int HostActorNumber { get; }

		public bool UnlockWhilePassedOut { get; }

		public bool AllowEveryone { get; }

		public bool DroppedPacksTeamOnly { get; }

		public bool DeathDropsTeamOnly { get; }

		public IReadOnlyDictionary<PlayerKey, int> Teams => _teams;

		public LobbyRule(LobbyMode mode, int hostActorNumber, bool unlockWhilePassedOut, bool allowEveryone, IEnumerable<KeyValuePair<PlayerKey, int>> teams, bool droppedPacksTeamOnly, bool deathDropsTeamOnly)
		{
			Mode = mode;
			HostActorNumber = hostActorNumber;
			UnlockWhilePassedOut = unlockWhilePassedOut;
			AllowEveryone = allowEveryone;
			DroppedPacksTeamOnly = droppedPacksTeamOnly;
			DeathDropsTeamOnly = deathDropsTeamOnly;
			_teams = new Dictionary<PlayerKey, int>();
			foreach (KeyValuePair<PlayerKey, int> item in teams ?? Enumerable.Empty<KeyValuePair<PlayerKey, int>>())
			{
				if (item.Value != 0)
				{
					_teams[item.Key] = item.Value;
				}
			}
		}

		public bool Protects(DropCause cause)
		{
			if (cause != DropCause.Death)
			{
				return DroppedPacksTeamOnly;
			}
			return DeathDropsTeamOnly;
		}

		public int TeamOf(Player player)
		{
			if (player == null || !PlayerKey.TryFrom(player, out var key))
			{
				return 0;
			}
			if (_teams.TryGetValue(key, out var value))
			{
				return value;
			}
			if (!_teams.TryGetValue(PlayerKey.ForActor(player.ActorNumber), out value))
			{
				return 0;
			}
			return value;
		}

		public bool Grants(Player wearer, Player requester)
		{
			if (AllowEveryone)
			{
				return true;
			}
			int num = TeamOf(wearer);
			if (num != 0)
			{
				return num == TeamOf(requester);
			}
			return false;
		}

		public static string TeamName(int team)
		{
			if (team != 0)
			{
				return ((char)(65 + team - 1)).ToString();
			}
			return null;
		}

		public string Serialize()
		{
			string text = string.Join(','.ToString(), _teams.Select((KeyValuePair<PlayerKey, int> t) => t.Key.Value + "=" + t.Value));
			return string.Join('|'.ToString(), 1.ToString(), ((int)Mode).ToString(), HostActorNumber.ToString(), Flag(UnlockWhilePassedOut), Flag(AllowEveryone), text, Flag(DroppedPacksTeamOnly), Flag(DeathDropsTeamOnly));
		}

		public static bool TryParse(string raw, out LobbyRule rule)
		{
			rule = null;
			if (string.IsNullOrEmpty(raw))
			{
				return false;
			}
			string[] array = raw.Split('|');
			if (array.Length < 8 || array[0] != 1.ToString() || !int.TryParse(array[1], out var result) || !Enum.IsDefined(typeof(LobbyMode), result) || !int.TryParse(array[2], out var result2))
			{
				return false;
			}
			List<KeyValuePair<PlayerKey, int>> list = new List<KeyValuePair<PlayerKey, int>>();
			string[] array2 = array[5].Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text in array2)
			{
				int num = text.LastIndexOf('=');
				if (num > 0 && PlayerKey.TryParse(text.Substring(0, num), out var key) && int.TryParse(text.Substring(num + 1), out var result3) && result3 >= 0 && result3 <= 4)
				{
					list.Add(new KeyValuePair<PlayerKey, int>(key, result3));
				}
			}
			rule = new LobbyRule((LobbyMode)result, result2, array[3] == "1", array[4] == "1", list, array[6] == "1", array[7] == "1");
			return true;
		}

		private static string Flag(bool value)
		{
			if (!value)
			{
				return "0";
			}
			return "1";
		}
	}
	internal sealed class LobbySync : IDisposable
	{
		public const string PropertyKey = "bpk_lobby";

		private const float VerifyIntervalSeconds = 3f;

		private readonly HostSettings _settings;

		private string _publishedRule;

		private float _lastPublishTime;

		private bool _dirty = true;

		public LobbySync(HostSettings settings)
		{
			_settings = settings ?? throw new ArgumentNullException("settings");
			_settings.Changed += MarkDirty;
		}

		public void Dispose()
		{
			_settings.Changed -= MarkDirty;
		}

		public static bool TryReadRule(out LobbyRule rule)
		{
			rule = null;
			if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null || PhotonNetwork.MasterClient == null)
			{
				return false;
			}
			Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties;
			if (customProperties == null || !((Dictionary<object, object>)(object)customProperties).TryGetValue((object)"bpk_lobby", out object value) || !(value is string raw))
			{
				return false;
			}
			if (!LobbyRule.TryParse(raw, out var rule2) || rule2.HostActorNumber != PhotonNetwork.MasterClient.ActorNumber)
			{
				return false;
			}
			rule = rule2;
			return true;
		}

		public static bool IsHostControlled(out LobbyRule rule)
		{
			if (TryReadRule(out rule))
			{
				return rule.Mode == LobbyMode.HostControlled;
			}
			return false;
		}

		public void Tick()
		{
			if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient || PhotonNetwork.LocalPlayer == null)
			{
				_publishedRule = null;
				_dirty = true;
			}
			else if (_dirty)
			{
				Publish();
			}
			else if (Time.unscaledTime - _lastPublishTime > 3f && !IsPropertyUpToDate())
			{
				Publish();
			}
		}

		private void MarkDirty()
		{
			_dirty = true;
		}

		private bool IsPropertyUpToDate()
		{
			Room currentRoom = PhotonNetwork.CurrentRoom;
			Hashtable val = ((currentRoom != null) ? ((RoomInfo)currentRoom).CustomProperties : null);
			if (val != null && ((Dictionary<object, object>)(object)val).TryGetValue((object)"bpk_lobby", out object value) && value is string text)
			{
				return text == _publishedRule;
			}
			return false;
		}

		private void Publish()
		{
			//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_0031: Expected O, but got Unknown
			//IL_0038: Expected O, but got Unknown
			string text = _settings.ToRule(PhotonNetwork.LocalPlayer.ActorNumber).Serialize();
			Room currentRoom = PhotonNetwork.CurrentRoom;
			Hashtable val = new Hashtable();
			((Dictionary<object, object>)val).Add((object)"bpk_lobby", (object)text);
			currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
			_publishedRule = text;
			_lastPublishTime = Time.unscaledTime;
			_dirty = false;
			Plugin.LogVerbose("Lobby rule published: " + text);
		}
	}
	internal sealed class LocalPermissions
	{
		private const char KeySeparator = ',';

		private readonly ModConfig _config;

		private readonly HashSet<PlayerKey> _allowed = new HashSet<PlayerKey>();

		public bool AllowEveryone
		{
			get
			{
				return _config.AllowEveryone;
			}
			private set
			{
				_config.AllowEveryone = value;
				this.Changed?.Invoke();
			}
		}

		public bool UnlockWhilePassedOut
		{
			get
			{
				return _config.UnlockWhilePassedOut;
			}
			private set
			{
				_config.UnlockWhilePassedOut = value;
				this.Changed?.Invoke();
			}
		}

		public bool ProtectDroppedPack
		{
			get
			{
				return _config.ProtectDroppedPack;
			}
			private set
			{
				_config.ProtectDroppedPack = value;
				this.Changed?.Invoke();
			}
		}

		public bool ProtectDeathDrop
		{
			get
			{
				return _config.ProtectDeathDrop;
			}
			private set
			{
				_config.ProtectDeathDrop = value;
				this.Changed?.Invoke();
			}
		}

		public event Action Changed;

		public LocalPermissions(ModConfig config)
		{
			_config = config ?? throw new ArgumentNullException("config");
			Load();
		}

		public void ToggleProtectDroppedPack()
		{
			ProtectDroppedPack = !ProtectDroppedPack;
			Plugin.Log.LogInfo((object)("Protect dropped pack: " + (ProtectDroppedPack ? "on" : "off")));
		}

		public void ToggleProtectDeathDrop()
		{
			ProtectDeathDrop = !ProtectDeathDrop;
			Plugin.Log.LogInfo((object)("Protect pack after death: " + (ProtectDeathDrop ? "on" : "off")));
		}

		public bool IsListed(Player player)
		{
			if (PlayerKey.TryFrom(player, out var key))
			{
				return _allowed.Contains(key);
			}
			return false;
		}

		public bool IsGranted(Player player)
		{
			if (!AllowEveryone)
			{
				return IsListed(player);
			}
			return true;
		}

		public int CountGranted(IEnumerable<Player> players)
		{
			return players.Count(IsGranted);
		}

		public void Toggle(Player player)
		{
			if (PlayerKey.TryFrom(player, out var key))
			{
				bool flag = _allowed.Add(key);
				if (!flag)
				{
					_allowed.Remove(key);
				}
				Plugin.Log.LogInfo((object)("Backpack access for " + player.NickName + ": " + (flag ? "allowed" : "locked")));
				Save();
				this.Changed?.Invoke();
			}
		}

		public void ToggleAllowEveryone()
		{
			AllowEveryone = !AllowEveryone;
			Plugin.Log.LogInfo((object)("Allow everyone: " + (AllowEveryone ? "on" : "off")));
		}

		public void ToggleUnlockWhilePassedOut()
		{
			UnlockWhilePassedOut = !UnlockWhilePassedOut;
			Plugin.Log.LogInfo((object)("Unlock while passed out: " + (UnlockWhilePassedOut ? "on" : "off")));
		}

		public AccessRule ToRule()
		{
			return new AccessRule(AllowEveryone, UnlockWhilePassedOut, _allowed, ProtectDroppedPack, ProtectDeathDrop);
		}

		private void Load()
		{
			_allowed.Clear();
			if (!_config.RememberAllowedPlayers)
			{
				return;
			}
			string[] array = _config.AllowedPlayers.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				if (PlayerKey.TryParse(array[i], out var key))
				{
					_allowed.Add(key);
				}
			}
			Plugin.LogVerbose($"Allow list loaded: {_allowed.Count} entries, everyone={AllowEveryone}");
		}

		private void Save()
		{
			if (_config.RememberAllowedPlayers)
			{
				_config.AllowedPlayers = string.Join(','.ToString(), from k in _allowed
					where k.IsPersistent
					select k.Value);
			}
		}
	}
	internal readonly struct PlayerKey : IEquatable<PlayerKey>
	{
		private const string UserPrefix = "u:";

		private const string ActorPrefix = "a:";

		public string Value { get; }

		public bool IsPersistent
		{
			get
			{
				if (Value != null)
				{
					return Value.StartsWith("u:", StringComparison.Ordinal);
				}
				return false;
			}
		}

		private PlayerKey(string value)
		{
			Value = value;
		}

		public static PlayerKey ForActor(int actorNumber)
		{
			return new PlayerKey("a:" + actorNumber);
		}

		public static bool TryFrom(Player player, out PlayerKey key)
		{
			if (player == null)
			{
				key = default(PlayerKey);
				return false;
			}
			key = (string.IsNullOrEmpty(player.UserId) ? ForActor(player.ActorNumber) : new PlayerKey("u:" + player.UserId));
			return true;
		}

		public static bool TryParse(string raw, out PlayerKey key)
		{
			string text = raw?.Trim();
			if (!string.IsNullOrEmpty(text) && (text.StartsWith("u:", StringComparison.Ordinal) || text.StartsWith("a:", StringComparison.Ordinal)) && text.Length > "u:".Length)
			{
				key = new PlayerKey(text);
				return true;
			}
			key = default(PlayerKey);
			return false;
		}

		public bool Equals(PlayerKey other)
		{
			return string.Equals(Value, other.Value, StringComparison.Ordinal);
		}

		public override bool Equals(object obj)
		{
			if (obj is PlayerKey other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			if (Value == null)
			{
				return 0;
			}
			return StringComparer.Ordinal.GetHashCode(Value);
		}

		public override string ToString()
		{
			return Value ?? string.Empty;
		}
	}
	internal sealed class RuleSync : IDisposable
	{
		public const string PropertyKey = "bpk";

		private const float VerifyIntervalSeconds = 3f;

		private readonly LocalPermissions _permissions;

		private string _publishedRule;

		private string _publishedRoom;

		private float _lastPublishTime;

		private bool _dirty = true;

		public RuleSync(LocalPermissions permissions)
		{
			_permissions = permissions ?? throw new ArgumentNullException("permissions");
			_permissions.Changed += MarkDirty;
		}

		public void Dispose()
		{
			_permissions.Changed -= MarkDirty;
		}

		public static bool TryReadRule(Player player, out AccessRule rule)
		{
			rule = null;
			Hashtable val = ((player != null) ? player.CustomProperties : null);
			if (val == null || !((Dictionary<object, object>)(object)val).TryGetValue((object)"bpk", out object value) || !(value is string raw))
			{
				return false;
			}
			return AccessRule.TryParse(raw, out rule);
		}

		public void Tick()
		{
			if (!PhotonNetwork.InRoom || PhotonNetwork.LocalPlayer == null)
			{
				_publishedRule = null;
				_publishedRoom = null;
				_dirty = true;
				return;
			}
			Room currentRoom = PhotonNetwork.CurrentRoom;
			string text = ((currentRoom != null) ? currentRoom.Name : null) ?? string.Empty;
			if (_dirty || text != _publishedRoom)
			{
				Publish(text);
			}
			else if (Time.unscaledTime - _lastPublishTime > 3f && !IsPropertyUpToDate())
			{
				Publish(text);
			}
		}

		private void MarkDirty()
		{
			_dirty = true;
		}

		private bool IsPropertyUpToDate()
		{
			Hashtable customProperties = PhotonNetwork.LocalPlayer.CustomProperties;
			if (customProperties != null && ((Dictionary<object, object>)(object)customProperties).TryGetValue((object)"bpk", out object value) && value is string text)
			{
				return text == _publishedRule;
			}
			return false;
		}

		private void Publish(string room)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_002e: Expected O, but got Unknown
			string text = _permissions.ToRule().Serialize();
			Player localPlayer = PhotonNetwork.LocalPlayer;
			Hashtable val = new Hashtable();
			((Dictionary<object, object>)val).Add((object)"bpk", (object)text);
			localPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
			_publishedRule = text;
			_publishedRoom = room;
			_lastPublishTime = Time.unscaledTime;
			_dirty = false;
			Plugin.LogVerbose("Access rule published: " + text);
		}
	}
}
namespace BackpackPermission.Patches
{
	[HarmonyPatch(typeof(Backpack))]
	internal static class BackpackItemPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("GetInteractionText")]
		private static void GetInteractionText_Postfix(Backpack __instance, ref string __result)
		{
			if (AccessPolicy.IsDroppedPackLockedForLocalPlayer(__instance))
			{
				__result = Strings.LockedPrompt;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("Interact")]
		private static bool Interact_Prefix(Backpack __instance, Character interactor)
		{
			if ((Object)(object)interactor == (Object)null || !interactor.IsLocal || !AccessPolicy.IsDroppedPackLockedForLocalPlayer(__instance))
			{
				return true;
			}
			Plugin.LogVerbose("Blocked opening a dropped pack (local check).");
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch("Stash")]
		private static bool Stash_Prefix(Backpack __instance, Character interactor)
		{
			if ((Object)(object)interactor == (Object)null || !interactor.IsLocal || !AccessPolicy.IsDroppedPackLockedForLocalPlayer(__instance))
			{
				return true;
			}
			Plugin.LogVerbose("Blocked stashing into a dropped pack (local check).");
			return false;
		}
	}
	[HarmonyPatch(typeof(BackpackOnBackVisuals))]
	internal static class BackpackOnBackVisualsPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("IsConstantlyInteractable")]
		private static void IsConstantlyInteractable_Postfix(BackpackOnBackVisuals __instance, ref bool __result)
		{
			if (__result && IsLocked(__instance))
			{
				__result = false;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("GetInteractionText")]
		private static void GetInteractionText_Postfix(BackpackOnBackVisuals __instance, ref string __result)
		{
			if (IsLocked(__instance))
			{
				__result = Strings.LockedPrompt;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("Interact_CastFinished")]
		private static bool Interact_CastFinished_Prefix(BackpackOnBackVisuals __instance)
		{
			if (!IsLocked(__instance))
			{
				return true;
			}
			Plugin.LogVerbose("Blocked opening " + __instance.character.characterName + "'s backpack (local check).");
			return false;
		}

		private static bool IsLocked(BackpackOnBackVisuals visuals)
		{
			if ((Object)(object)visuals != (Object)null)
			{
				return AccessPolicy.IsLockedForLocalPlayer(visuals.character);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(CharacterBackpackHandler), "StashInBackpack")]
	internal static class BackpackStashPatches
	{
		private static bool Prefix(CharacterBackpackHandler __instance, Character interactor)
		{
			if ((Object)(object)interactor == (Object)null || !interactor.IsLocal)
			{
				return true;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			if (AccessPolicy.LocalPlayerMayAccess(component))
			{
				return true;
			}
			Plugin.LogVerbose("Blocked stashing into " + component.characterName + "'s backpack (local check).");
			return false;
		}
	}
	[HarmonyPatch(typeof(BackpackWheel))]
	internal static class BackpackWheelPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("InitWheel")]
		private static void InitWheel_Postfix(BackpackWheel __instance, BackpackReference bp)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			StandalonePanel.Close();
			if (IsSomeoneElsesPack(bp))
			{
				PermissionPanel.HideIfOpen();
				if (!AccessPolicy.LocalPlayerMayAccess(bp))
				{
					GUIManager.instance.CloseBackpackWheel();
				}
			}
			else
			{
				PermissionPanel.ShowFor(__instance);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("Update")]
		private static bool Update_Prefix(BackpackWheel __instance)
		{
			//IL_0001: 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_0010: 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)
			BackpackReference backpack = __instance.backpack;
			if (((BackpackReference)(ref backpack)).exists && IsSomeoneElsesPack(backpack) && !AccessPolicy.LocalPlayerMayAccess(backpack))
			{
				GUIManager.instance.CloseBackpackWheel();
				return false;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch("Choose")]
		private static bool Choose_Prefix(BackpackWheel __instance)
		{
			//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)
			if (__instance.chosenSlice.IsSome)
			{
				return AccessPolicy.LocalPlayerMayAccess(__instance.chosenSlice.Value.backpackReference);
			}
			return true;
		}

		private static bool IsSomeoneElsesPack(BackpackReference reference)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)reference.view == (Object)null)
			{
				return false;
			}
			if ((int)reference.type == 1)
			{
				return !((BackpackReference)(ref reference)).IsOnMyBack();
			}
			if (AccessPolicy.TryGetDroppedPackOwner(reference.view.ViewID, out var owner, out var _) && PhotonNetwork.LocalPlayer != null)
			{
				return owner.ActorNumber != PhotonNetwork.LocalPlayer.ActorNumber;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(GUIManager))]
	internal static class GuiManagerPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("CloseBackpackWheel")]
		private static void CloseBackpackWheel_Postfix()
		{
			PermissionPanel.HideIfOpen();
		}

		[HarmonyPostfix]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		private static void WheelActive_Postfix(ref bool __result)
		{
			if (StandalonePanel.IsOpen)
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch(typeof(CharacterItems))]
	internal static class DropTrackingPatches
	{
		private const byte BackpackSlot = 3;

		[HarmonyPrefix]
		[HarmonyPatch("DropItemRpc")]
		private static void DropItemRpc_Prefix()
		{
			SpawnTracker.Reset();
		}

		[HarmonyPostfix]
		[HarmonyPatch("DropItemRpc")]
		private static void DropItemRpc_Postfix(CharacterItems __instance, byte slotID)
		{
			RegisterIfBackpack(__instance, slotID, DropCause.Manual);
		}

		[HarmonyPrefix]
		[HarmonyPatch("DropItemFromSlotRPC")]
		private static void DropItemFromSlotRPC_Prefix()
		{
			SpawnTracker.Reset();
		}

		[HarmonyPostfix]
		[HarmonyPatch("DropItemFromSlotRPC")]
		private static void DropItemFromSlotRPC_Postfix(CharacterItems __instance, byte slotID)
		{
			RegisterIfBackpack(__instance, slotID, DropCause.Death);
		}

		private static void RegisterIfBackpack(CharacterItems items, byte slotID, DropCause cause)
		{
			if (PhotonNetwork.IsMasterClient && slotID == 3 && Plugin.DroppedPacks != null)
			{
				GameObject val = SpawnTracker.Take();
				Backpack val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Backpack>() : null);
				PhotonView val3 = (((Object)(object)val2 != (Object)null) ? ((MonoBehaviourPun)val2).photonView : null);
				PhotonView val4 = (((Object)(object)items != (Object)null) ? ((Component)items).GetComponent<PhotonView>() : null);
				Player val5 = (((Object)(object)val4 != (Object)null) ? val4.Owner : null);
				if (!((Object)(object)val3 == (Object)null) && val5 != null)
				{
					Plugin.DroppedPacks.Register(val3.ViewID, val5.ActorNumber, cause);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PhotonNetwork), "InstantiateItemRoom")]
	internal static class SpawnTracker
	{
		private static GameObject _last;

		private static void Postfix(GameObject __result)
		{
			_last = __result;
		}

		public static void Reset()
		{
			_last = null;
		}

		public static GameObject Take()
		{
			GameObject last = _last;
			_last = null;
			return last;
		}
	}
	[HarmonyPatch(typeof(Item), "RequestPickup")]
	internal static class ItemPickupPatches
	{
		private static bool Prefix(Item __instance, PhotonView characterView)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Invalid comparison between Unknown and I4
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			Player val = (((Object)(object)characterView != (Object)null) ? characterView.Owner : null);
			if (val == null)
			{
				return true;
			}
			AccessVerdict verdict;
			string text;
			if ((int)__instance.itemState == 2 && __instance.backpackReference.IsSome)
			{
				BackpackReference item = __instance.backpackReference.Value.Item2;
				if ((Object)(object)item.view == (Object)null)
				{
					return true;
				}
				if ((int)item.type == 1)
				{
					Character component = ((Component)item.view).GetComponent<Character>();
					verdict = AccessPolicy.Evaluate(component, val);
					text = ((component != null) ? component.characterName : null) + "'s backpack";
				}
				else
				{
					verdict = AccessPolicy.EvaluateDropped(item.view.ViewID, val);
					text = "a dropped pack";
				}
			}
			else
			{
				if (!(__instance is Backpack) || (int)__instance.itemState != 0 || !((Object)(object)((MonoBehaviourPun)__instance).photonView != (Object)null))
				{
					return true;
				}
				verdict = AccessPolicy.EvaluateDropped(((MonoBehaviourPun)__instance).photonView.ViewID, val);
				text = "a dropped pack (wearing it)";
			}
			if (verdict.IsGranted())
			{
				return true;
			}
			Plugin.Log.LogInfo((object)("Denied " + val.NickName + " taking from " + text + " (host check)."));
			((MonoBehaviourPun)__instance).photonView.RPC("DenyPickupRPC", val, Array.Empty<object>());
			return false;
		}
	}
	internal static class StashRollback
	{
		public static bool TryBounce(PhotonView stasherView, byte inventorySlotID, AccessVerdict verdict, string target)
		{
			if (!PhotonNetwork.IsMasterClient || verdict.IsGranted() || (Object)(object)stasherView == (Object)null)
			{
				return false;
			}
			Player owner = stasherView.Owner;
			Player component = ((Component)stasherView).GetComponent<Player>();
			ItemSlot val = (((Object)(object)component != (Object)null) ? component.GetItemSlot(inventorySlotID) : null);
			Plugin.Log.LogInfo((object)("Denied " + ((owner != null) ? owner.NickName : null) + " stashing into " + target + " (host check), returning the item."));
			if (val != null && !val.IsEmpty())
			{
				RespawnNearStasher(val, owner);
			}
			return true;
		}

		public static void ResyncWornPack(Character wearer)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			Player val = (((Object)(object)wearer != (Object)null) ? wearer.player : null);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)((MonoBehaviourPun)val).photonView == (Object)null))
			{
				byte[] array = IBinarySerializable.ToManagedArray<InventorySyncData>(new InventorySyncData(val.itemSlots, val.backpackSlot, val.tempFullSlot));
				((MonoBehaviourPun)val).photonView.RPC("SyncInventoryRPC", (RpcTarget)1, new object[2] { array, false });
			}
		}

		public static void ResyncGroundPack(Backpack pack)
		{
			if ((Object)(object)pack != (Object)null && (Object)(object)((MonoBehaviourPun)pack).photonView != (Object)null && ((Item)pack).data != null)
			{
				((MonoBehaviourPun)pack).photonView.RPC("SetItemInstanceDataRPC", (RpcTarget)1, new object[1] { ((Item)pack).data });
			}
		}

		private static void RespawnNearStasher(ItemSlot slot, Player stasher)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			string prefabName = slot.GetPrefabName();
			if (!string.IsNullOrEmpty(prefabName))
			{
				Character val = ((stasher != null) ? PlayerHandler.GetPlayerCharacter(stasher) : null);
				Vector3 val2 = (((Object)(object)val != (Object)null) ? (val.Center + Vector3.up * 0.5f + ((Component)val).transform.forward * 0.5f) : Vector3.zero);
				GameObject val3 = PhotonNetwork.InstantiateItemRoom(prefabName, val2, Quaternion.identity, true);
				PhotonView val4 = (((Object)(object)val3 != (Object)null) ? val3.GetComponent<PhotonView>() : null);
				if (!((Object)(object)val4 == (Object)null))
				{
					val4.RPC("SetItemInstanceDataRPC", (RpcTarget)0, new object[1] { slot.data });
					val4.RPC("SetKinematicRPC", (RpcTarget)0, new object[3]
					{
						false,
						val2,
						Quaternion.identity
					});
				}
			}
		}
	}
	[HarmonyPatch(typeof(CharacterBackpackHandler), "RPCAddItemToCharacterBackpack")]
	internal static class WornPackStashRollbackPatch
	{
		private static bool Prefix(CharacterBackpackHandler __instance, PhotonView playerView, byte inventorySlotID)
		{
			if (!PhotonNetwork.IsMasterClient)
			{
				return true;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			AccessVerdict verdict = AccessPolicy.Evaluate(component, ((Object)(object)playerView != (Object)null) ? playerView.Owner : null);
			if (!StashRollback.TryBounce(playerView, inventorySlotID, verdict, ((component != null) ? component.characterName : null) + "'s backpack"))
			{
				return true;
			}
			StashRollback.ResyncWornPack(component);
			return false;
		}
	}
	[HarmonyPatch(typeof(Backpack), "RPCAddItemToBackpack")]
	internal static class GroundPackStashRollbackPatch
	{
		private static bool Prefix(Backpack __instance, PhotonView playerView, byte slotID)
		{
			if (!PhotonNetwork.IsMasterClient || (Object)(object)((MonoBehaviourPun)__instance).photonView == (Object)null)
			{
				return true;
			}
			AccessVerdict verdict = AccessPolicy.EvaluateDropped(((MonoBehaviourPun)__instance).photonView.ViewID, ((Object)(object)playerView != (Object)null) ? playerView.Owner : null);
			if (!StashRollback.TryBounce(playerView, slotID, verdict, "a dropped pack"))
			{
				return true;
			}
			StashRollback.ResyncGroundPack(__instance);
			return false;
		}
	}
}
namespace BackpackPermission.Localization
{
	public enum Language
	{
		English,
		Deutsch,
		Auto
	}
	internal static class Strings
	{
		public static string Title => Pick("Backpack Access", "Rucksack-Zugriff");

		public static string Hint => Pick("Click a row to toggle", "Zeile anklicken zum Umschalten");

		public static string WornPack => Pick("Worn pack", "Getragener Rucksack");

		public static string WhilePassedOut => Pick("While passed out", "Bei Ohnmacht");

		public static string Allowed => Pick("Allowed", "Erlaubt");

		public static string Locked => Pick("Locked", "Gesperrt");

		public static string LockedPrompt => Pick("Locked", "Gesperrt");

		public static string Players => Pick("Players", "Mitspieler");

		public static string NoOtherPlayers => Pick("No other players in the lobby", "Keine anderen Spieler in der Runde");

		public static string DroppedPack => Pick("Dropped pack", "Abgelegter Rucksack");

		public static string AfterDeath => Pick("After death", "Nach dem Tod");

		public static string Everyone => Pick("Everyone", "Alle");

		public static string MyList => Pick("My list", "Meine Liste");

		public static string TeamOnly => Pick("Team only", "Nur Team");

		public static string LobbyMode => Pick("Lobby mode", "Lobby-Modus");

		public static string ModeIndividual => Pick("Individual", "Jeder für sich");

		public static string ModeHost => Pick("Host decides", "Host entscheidet");

		public static string SwitchToHostMode => Pick("Lobby mode: host decides", "Lobby-Modus: Host entscheidet");

		public static string SwitchToIndividualMode => Pick("Lobby mode: everyone for themselves", "Lobby-Modus: jeder für sich");

		public static string HostHint => Pick("Click a player to change their team", "Spieler anklicken, um das Team zu wechseln");

		public static string HostManagesHint => Pick("The host manages access in this lobby", "Der Host verwaltet den Zugriff in dieser Runde");

		public static string Teams => Pick("Teams", "Teams");

		public static string NoTeam => Pick("No team", "Kein Team");

		public static string You => Pick("you", "du");

		private static bool UseGerman => ((Plugin.Settings != null) ? Plugin.Settings.Language : Language.English) switch
		{
			Language.Deutsch => true, 
			Language.Auto => (int)LocalizedText.CURRENT_LANGUAGE == 3, 
			_ => false, 
		};

		public static string SetTo(string label, string value)
		{
			return Pick(label + ": " + value, label + ": " + value);
		}

		public static string Team(string name)
		{
			return Pick("Team " + name, "Team " + name);
		}

		public static string TeamOrNone(string name)
		{
			if (name != null)
			{
				return Team(name);
			}
			return NoTeam;
		}

		public static string YourTeam(string name)
		{
			return Pick("Your team: " + TeamOrNone(name), "Dein Team: " + TeamOrNone(name));
		}

		public static string MoveToTeam(string player, string team)
		{
			return Pick("Move " + player + " to " + TeamOrNone(team), player + " nach " + TeamOrNone(team) + " verschieben");
		}

		public static string Summary(int allowed, int total)
		{
			return Pick($"{allowed} of {total} players allowed", $"{allowed} von {total} Spielern erlaubt");
		}

		public static string AllowPlayer(string name)
		{
			return Pick("Allow " + name, name + " erlauben");
		}

		public static string LockPlayer(string name)
		{
			return Pick("Lock " + name, name + " sperren");
		}

		public static string CloseHint(string key)
		{
			return Pick("Press " + key + " to close", key + " drücken zum Schließen");
		}

		public static string FallbackPlayerName(int actorNumber)
		{
			return Pick($"Player {actorNumber}", $"Spieler {actorNumber}");
		}

		private static string Pick(string english, string german)
		{
			if (!UseGerman)
			{
				return english;
			}
			return german;
		}
	}
}