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("General", "Enabled", true, "Master switch for backpack protection. Everything else is ignored while OFF."); plugin.Hotkey = ((BaseUnityPlugin)plugin).Config.Bind("General", "Hotkey", "B", "Key to toggle protection ON/OFF at runtime (Unity KeyCode, e.g. F8, H, B)."); plugin.Scope = ((BaseUnityPlugin)plugin).Config.Bind("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("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("General", "ShowInGameAlert", true, "Show a short toast (top-left) when protection is toggled with the hotkey."); plugin.LoseOwnershipOnFaint = ((BaseUnityPlugin)plugin).Config.Bind("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("Advanced", "FaintGraceSeconds", 3f, "Seconds an owner must be passed out before their backpack loses ownership."); plugin.ProtectDropped = ((BaseUnityPlugin)plugin).Config.Bind("Advanced", "ProtectDropped", true, "Protect backpacks lying on the ground (dropped)."); plugin.ProtectWorn = ((BaseUnityPlugin)plugin).Config.Bind("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()); } return false; } } [BepInPlugin("Vector.BackpackLock", "BackpackLock", "1.1.0")] public class BackpackLockPlugin : BaseUnityPlugin { public ConfigEntry Enabled; public ConfigEntry Hotkey; public ConfigEntry ProtectDropped; public ConfigEntry ProtectWorn; public ConfigEntry Scope; public ConfigEntry OwnershipMode; public ConfigEntry LoseOwnershipOnFaint; public ConfigEntry FaintGraceSeconds; public ConfigEntry ShowInGameAlert; private KeyCode _hotkey = (KeyCode)98; private readonly Dictionary _owners = new Dictionary(); private readonly HashSet _released = new HashSet(); 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() != (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(); 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(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); } }