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