Decompiled source of Backpack Lock v1.2.0

BepInEx\plugins\BackpackLock\Vector.BackpackLock.dll

Decompiled 19 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Vector.BackpackLock;

public static class BackpackLockConfig
{
	public const string General = "General";

	public const string Advanced = "Advanced";

	public static void Bind(BackpackLockPlugin plugin)
	{
		plugin.Enabled = ((BaseUnityPlugin)plugin).Config.Bind<bool>("General", "Enabled", true, "Master switch for backpack protection. Everything else is ignored while OFF.");
		plugin.Hotkey = ((BaseUnityPlugin)plugin).Config.Bind<string>("General", "Hotkey", "B", "Key to toggle protection ON/OFF at runtime (Unity KeyCode, e.g. F8, H, B).");
		plugin.Scope = ((BaseUnityPlugin)plugin).Config.Bind<string>("General", "Scope", "HostOnly", "Who is covered: 'HostOnly' = only the host's own backpack is protected, 'Everyone' = every player's backpack is protected from other players.");
		plugin.OwnershipMode = ((BaseUnityPlugin)plugin).Config.Bind<string>("General", "OwnershipMode", "First", "Who owns a dropped backpack: 'First' = the first person to pick it up keeps ownership, 'Last' = the most recent person to touch it now owns it.");
		plugin.ShowInGameAlert = ((BaseUnityPlugin)plugin).Config.Bind<bool>("General", "ShowInGameAlert", true, "Show a short toast (top-left) when protection is toggled with the hotkey.");
		plugin.LoseOwnershipOnFaint = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Advanced", "LoseOwnershipOnFaint", true, "When the owner is passed out for FaintGraceSeconds (or dies), their backpack loses protection and becomes lootable by anyone.");
		plugin.FaintGraceSeconds = ((BaseUnityPlugin)plugin).Config.Bind<float>("Advanced", "FaintGraceSeconds", 3f, "Seconds an owner must be passed out before their backpack loses ownership.");
		plugin.ProtectDropped = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Advanced", "ProtectDropped", true, "Protect backpacks lying on the ground (dropped).");
		plugin.ProtectWorn = ((BaseUnityPlugin)plugin).Config.Bind<bool>("Advanced", "ProtectWorn", true, "Protect backpacks worn on the back.");
	}
}
[HarmonyPatch(typeof(Item), "RequestPickup")]
public static class ItemRequestPickupPatch
{
	[HarmonyPrefix]
	public static bool Prefix(Item __instance, PhotonView characterView)
	{
		BackpackLockPlugin instance = BackpackLockPlugin.Instance;
		if ((Object)(object)instance == (Object)null)
		{
			return true;
		}
		instance.LogRequestPickup(__instance, characterView);
		if (!instance.ShouldBlock(__instance, characterView))
		{
			return true;
		}
		string[] obj = new string[5]
		{
			"[BackpackLock] BLOCKED pickup of '",
			((Object)__instance).name,
			"' from backpack by ",
			null,
			null
		};
		object obj2;
		if (characterView == null)
		{
			obj2 = null;
		}
		else
		{
			Player owner = characterView.Owner;
			obj2 = ((owner != null) ? owner.NickName : null);
		}
		if (obj2 == null)
		{
			obj2 = "?";
		}
		obj[3] = (string)obj2;
		obj[4] = " (not the owner).";
		instance.LogWarningText(string.Concat(obj));
		if ((Object)(object)((MonoBehaviourPun)__instance).photonView != (Object)null && (Object)(object)characterView != (Object)null && characterView.Owner != null)
		{
			((MonoBehaviourPun)__instance).photonView.RPC("DenyPickupRPC", characterView.Owner, Array.Empty<object>());
		}
		return false;
	}
}
[BepInPlugin("Vector.BackpackLock", "BackpackLock", "1.1.0")]
public class BackpackLockPlugin : BaseUnityPlugin
{
	public ConfigEntry<bool> Enabled;

	public ConfigEntry<string> Hotkey;

	public ConfigEntry<bool> ProtectDropped;

	public ConfigEntry<bool> ProtectWorn;

	public ConfigEntry<string> Scope;

	public ConfigEntry<string> OwnershipMode;

	public ConfigEntry<bool> LoseOwnershipOnFaint;

	public ConfigEntry<float> FaintGraceSeconds;

	public ConfigEntry<bool> ShowInGameAlert;

	private KeyCode _hotkey = (KeyCode)98;

	private readonly Dictionary<string, int> _owners = new Dictionary<string, int>();

	private readonly HashSet<string> _released = new HashSet<string>();

	private const string NO_KEY = "";

	private string _alertText = "";

	private float _alertUntil = 0f;

	public static BackpackLockPlugin Instance { get; private set; }

	public Harmony Harmony { get; private set; }

	public bool ProtectionOn { get; private set; }

	private void Awake()
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Expected O, but got Unknown
		Instance = this;
		BackpackLockConfig.Bind(this);
		ProtectionOn = Enabled.Value;
		LoadHotkey();
		Harmony = new Harmony("Vector.BackpackLock");
		Harmony.PatchAll(typeof(BackpackLockPlugin).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"BackpackLock loaded.");
		((BaseUnityPlugin)this).Logger.LogInfo((object)("[BackpackLock] Protection=" + (ProtectionOn ? "ON" : "OFF") + " | Hotkey=" + Hotkey.Value + " | Scope=" + Scope.Value + " | OwnershipMode=" + OwnershipMode.Value + " | " + $"ProtectDropped={ProtectDropped.Value} | ProtectWorn={ProtectWorn.Value} | " + $"LoseOwnershipOnFaint={LoseOwnershipOnFaint.Value} | FaintGraceSeconds={FaintGraceSeconds.Value}"));
	}

	private void Update()
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		if (Input.GetKeyDown(_hotkey))
		{
			ProtectionOn = !ProtectionOn;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[BackpackLock] Protection " + (ProtectionOn ? "ON" : "OFF")));
			if (ShowInGameAlert.Value)
			{
				_alertText = "Backpack Lock: " + (ProtectionOn ? "ON" : "OFF");
				_alertUntil = Time.realtimeSinceStartup + 3f;
			}
		}
	}

	private void OnGUI()
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Expected O, but got Unknown
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Expected O, but got Unknown
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		if (ShowInGameAlert.Value && !string.IsNullOrEmpty(_alertText))
		{
			if (Time.realtimeSinceStartup > _alertUntil)
			{
				_alertText = "";
				return;
			}
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				fontSize = 20,
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)0
			};
			val.normal.textColor = new Color(0f, 0f, 0f, 0.8f);
			GUIStyle val2 = new GUIStyle(val);
			val2.normal.textColor = new Color(1f, 0.9f, 0.3f, 1f);
			GUI.Label(new Rect(11f, 12f, (float)Screen.width - 24f, 32f), _alertText, val);
			GUI.Label(new Rect(12f, 12f, (float)Screen.width - 24f, 32f), _alertText, val2);
		}
	}

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

	public void LogRequestPickup(Item item, PhotonView characterView)
	{
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Invalid comparison between Unknown and I4
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		bool flag = (Object)(object)item != (Object)null && item.backpackReference.IsSome;
		if ((Object)(object)item == (Object)null)
		{
			return;
		}
		if (!flag)
		{
			RegisterBackpackPickup(item, characterView);
			return;
		}
		byte item2 = item.backpackReference.Value.Item1;
		BackpackReference item3 = item.backpackReference.Value.Item2;
		bool flag2 = (int)item3.type == 1;
		string text = (((Object)(object)characterView != (Object)null) ? PhotonViewName(characterView) : "unknown");
		object obj;
		if (!((Object)(object)item3.view != (Object)null))
		{
			obj = "no-view";
		}
		else
		{
			object arg;
			if (!item3.view.IsMine)
			{
				Player owner = item3.view.Owner;
				arg = ((owner != null) ? owner.NickName : null) ?? "?";
			}
			else
			{
				arg = "me";
			}
			obj = $"{arg} (viewId={item3.view.ViewID}, isMine={item3.view.IsMine})";
		}
		string text2 = (string)obj;
		string text3 = BackpackKey(item3);
		((BaseUnityPlugin)this).Logger.LogInfo((object)("[BackpackLock] INTERCEPT method=Item::RequestPickup rpcName=RequestPickup | " + $"item={((Object)item).name} itemID={item.itemID} slotID={item2} key={text3} " + "backpackType=" + (flag2 ? "Equipped(worn)" : "Item(dropped)") + " | localPlayer=" + LocalPlayerName() + " | interactingPlayer=" + text + " | backpackOwner=" + text2));
	}

	private void RegisterBackpackPickup(Item item, PhotonView characterView)
	{
		try
		{
			if (!((Object)(object)((Component)item).GetComponent<Backpack>() != (Object)null))
			{
				return;
			}
			string text = BackpackKeyFromItem(item);
			if (text == "")
			{
				return;
			}
			int? obj;
			if (characterView == null)
			{
				obj = null;
			}
			else
			{
				Player owner = characterView.Owner;
				obj = ((owner != null) ? new int?(owner.ActorNumber) : ((int?)null));
			}
			int num = obj ?? (-1);
			if (num == -1)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[BackpackLock] backpack pickup by unknown owner (key=" + text + ")."));
				return;
			}
			if (string.Equals(OwnershipMode.Value, "Last", StringComparison.OrdinalIgnoreCase))
			{
				_owners[text] = num;
			}
			else if (!_owners.ContainsKey(text))
			{
				_owners[text] = num;
			}
			_released.Remove(text);
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[BackpackLock] Backpack picked up -> owner={num} key={text} mode={OwnershipMode.Value}");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("[BackpackLock] RegisterBackpackPickup error: " + ex.Message));
		}
	}

	public bool ShouldBlock(Item item, PhotonView characterView)
	{
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Invalid comparison between Unknown and I4
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		if (!Enabled.Value || !ProtectionOn)
		{
			return false;
		}
		if ((Object)(object)item == (Object)null || !item.backpackReference.IsSome)
		{
			return false;
		}
		BackpackReference item2 = item.backpackReference.Value.Item2;
		bool flag = (int)item2.type == 1;
		if (flag && !ProtectWorn.Value)
		{
			return false;
		}
		if (!flag && !ProtectDropped.Value)
		{
			return false;
		}
		if (IsScopeHostOnly() && ((Object)(object)item2.view == (Object)null || !item2.view.IsMine))
		{
			return false;
		}
		if ((Object)(object)characterView == (Object)null)
		{
			return false;
		}
		Player owner = characterView.Owner;
		int num = ((owner != null) ? owner.ActorNumber : (-1));
		string text = BackpackKey(item2);
		int num2 = ResolveOwner(item, item2, text);
		if (text != "" && _released.Contains(text))
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[BackpackLock] backpack " + text + " released (ownership lost) -> allowing"));
			return false;
		}
		if (num2 != -1 && num2 == num)
		{
			return false;
		}
		if (LoseOwnershipOnFaint.Value && num2 != -1 && OwnerLostOwnershipPastGrace(num2, text))
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)$"[BackpackLock] owner {num2} passed out past grace -> releasing backpack {text}");
			if (text != "")
			{
				_released.Add(text);
			}
			if (text != "")
			{
				_owners.Remove(text);
			}
			return false;
		}
		ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
		string name = ((Object)item).name;
		Player owner2 = characterView.Owner;
		logger.LogWarning((object)("[BackpackLock] BLOCKED pickup of '" + name + "' from backpack by " + string.Format("{0} (not the owner {1}).", ((owner2 != null) ? owner2.NickName : null) ?? "?", num2)));
		return true;
	}

	private int ResolveOwner(Item item, BackpackReference backpack, string key)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Invalid comparison between Unknown and I4
		//IL_0012: 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_00c2: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		if ((int)backpack.type == 1)
		{
			if ((Object)(object)backpack.view != (Object)null && backpack.view.Owner != null)
			{
				return backpack.view.Owner.ActorNumber;
			}
			try
			{
				if ((Object)(object)item.wearerCharacter != (Object)null)
				{
					PhotonView component = ((Component)item.wearerCharacter).GetComponent<PhotonView>();
					if (component != null && component.Owner != null)
					{
						return component.Owner.ActorNumber;
					}
				}
			}
			catch
			{
			}
			return -1;
		}
		if (key != "" && _owners.TryGetValue(key, out var value))
		{
			return value;
		}
		if ((Object)(object)backpack.view != (Object)null && backpack.view.Owner != null)
		{
			return backpack.view.Owner.ActorNumber;
		}
		return -1;
	}

	private bool OwnerLostOwnershipPastGrace(int ownerActor, string key)
	{
		try
		{
			if (!LoseOwnershipOnFaint.Value)
			{
				return false;
			}
			Character val = null;
			if (!PlayerHandler.TryGetCharacter(ownerActor, ref val) || (Object)(object)val == (Object)null || (Object)(object)val.data == (Object)null)
			{
				return false;
			}
			bool flag = val.data.passedOut || val.data.fullyPassedOut;
			if (val.data.dead)
			{
				return true;
			}
			if (!flag)
			{
				return false;
			}
			float lastPassedOut = val.data.lastPassedOut;
			return lastPassedOut > 0f && Time.time - lastPassedOut >= FaintGraceSeconds.Value;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("[BackpackLock] faint check error: " + ex.Message));
			return false;
		}
	}

	private bool IsScopeHostOnly()
	{
		return !string.Equals(Scope.Value, "Everyone", StringComparison.OrdinalIgnoreCase);
	}

	private string BackpackKey(BackpackReference backpack)
	{
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			ItemInstanceData itemInstanceData = ((BackpackReference)(ref backpack)).GetItemInstanceData();
			if (itemInstanceData != null && itemInstanceData.guid != Guid.Empty)
			{
				Guid guid = itemInstanceData.guid;
				return "g:" + guid;
			}
		}
		catch
		{
		}
		return ((Object)(object)backpack.view != (Object)null) ? ("v:" + backpack.view.ViewID) : "";
	}

	private string BackpackKeyFromItem(Item item)
	{
		try
		{
			if (item.data != null && item.data.guid != Guid.Empty)
			{
				Guid guid = item.data.guid;
				return "g:" + guid;
			}
		}
		catch
		{
		}
		if ((Object)(object)((MonoBehaviourPun)item).photonView != (Object)null)
		{
			return "v:" + ((MonoBehaviourPun)item).photonView.ViewID;
		}
		return "";
	}

	private void LoadHotkey()
	{
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: 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_002c: Unknown result type (might be due to invalid IL or missing references)
		if (Enum.TryParse<KeyCode>(Hotkey.Value, ignoreCase: true, out KeyCode result))
		{
			_hotkey = result;
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[BackpackLock] Hotkey mapped to {_hotkey} (from cfg '{Hotkey.Value}')");
		}
		else
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("[BackpackLock] Invalid Hotkey '" + Hotkey.Value + "', falling back to B"));
			_hotkey = (KeyCode)98;
		}
	}

	private string LocalPlayerName()
	{
		try
		{
			Player localPlayer = PhotonNetwork.LocalPlayer;
			return (localPlayer == null) ? "?" : $"{localPlayer.NickName} (actor {localPlayer.ActorNumber})";
		}
		catch
		{
			return "?";
		}
	}

	private static string PhotonViewName(PhotonView v)
	{
		try
		{
			Player owner = v.Owner;
			return (owner != null) ? $"{owner.NickName} (actor {owner.ActorNumber})" : $"view {v.ViewID}";
		}
		catch
		{
			return $"view {v.ViewID}";
		}
	}

	public void LogInfoText(string msg)
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)msg);
	}

	public void LogWarningText(string msg)
	{
		((BaseUnityPlugin)this).Logger.LogWarning((object)msg);
	}

	public void LogErrorText(string msg)
	{
		((BaseUnityPlugin)this).Logger.LogError((object)msg);
	}
}