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;
}
}
}