Decompiled source of EasyBackpack Fix v1.1.8

EasyBackpack.dll

Decompiled 3 weeks ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;

[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("EasyBackpack")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("EasyBackpack")]
[assembly: AssemblyTitle("EasyBackpack")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 EasyBackpack
{
	[BepInPlugin("nickklmao.easybackpack", "EasyBackpack", "1.1.8")]
	internal sealed class Entry : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(GUIManager), "CloseBackpackWheel")]
		private static class WheelClosedPatch
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				ReleaseWheel();
			}
		}

		[HarmonyPatch(typeof(BackpackWheel), "Update")]
		private static class BackpackWheelUpdatePatch
		{
			private static bool s_forced;

			private static bool s_savedInteract;

			[HarmonyPrefix]
			private static void Prefix()
			{
				s_forced = false;
				try
				{
					if (isAccessingBackpack)
					{
						Character localCharacter = Character.localCharacter;
						if (!((Object)(object)localCharacter == (Object)null) && !((Object)(object)localCharacter.input == (Object)null))
						{
							s_savedInteract = localCharacter.input.interactIsPressed;
							localCharacter.input.interactIsPressed = true;
							s_forced = true;
						}
					}
				}
				catch (Exception e)
				{
					s_forced = false;
					LogPatchError("BackpackWheel.Update prefix", e);
				}
			}

			[HarmonyFinalizer]
			private static Exception Finalizer(Exception __exception)
			{
				try
				{
					if (s_forced)
					{
						s_forced = false;
						Character localCharacter = Character.localCharacter;
						if ((Object)(object)localCharacter != (Object)null && (Object)(object)localCharacter.input != (Object)null)
						{
							localCharacter.input.interactIsPressed = s_savedInteract;
						}
					}
				}
				catch (Exception e)
				{
					LogPatchError("BackpackWheel.Update finalizer", e);
				}
				return __exception;
			}
		}

		[HarmonyPatch(typeof(CharacterBackpackHandler), "AddFuelToJetpack")]
		private static class SelfRefuelRollbackFix
		{
			private static float s_beforeFuel = float.NaN;

			private static Guid s_beforeGuid = Guid.Empty;

			[HarmonyPrefix]
			private static void Prefix(CharacterBackpackHandler __instance, Character interactor, ref float addedFuel)
			{
				s_beforeFuel = float.NaN;
				s_beforeGuid = Guid.Empty;
				try
				{
					if ((Object)(object)interactor == (Object)null || (Object)(object)__instance == (Object)null || interactor.refs == null || (Object)(object)interactor.refs.backpackHandler != (Object)(object)__instance)
					{
						return;
					}
					int num = 25;
					Item currentItem = interactor.data.currentItem;
					if ((Object)(object)currentItem != (Object)null)
					{
						RopeSpool val = default(RopeSpool);
						if (((Component)currentItem).TryGetComponent<RopeSpool>(ref val))
						{
							num = Mathf.CeilToInt(val.RopeFuel);
						}
						else if (currentItem.HasData((DataEntryKey)10))
						{
							num = currentItem.overrideJetpackFuelAmount + Mathf.RoundToInt(currentItem.GetData<FloatItemData>((DataEntryKey)10).Value * currentItem.overrideJetpackFuelPerFuelMult);
						}
						else if (currentItem is Backpack)
						{
							num = currentItem.overrideJetpackFuelAmount;
						}
						else if (currentItem.overrideJetpackFuel)
						{
							num = (currentItem.HasData((DataEntryKey)2) ? (currentItem.overrideJetpackFuelAmount + currentItem.GetData<OptionableIntItemData>((DataEntryKey)2).Value * currentItem.overrideJetpackFuelPerUse) : currentItem.overrideJetpackFuelAmount);
						}
					}
					addedFuel = num;
					if (!PhotonNetwork.IsMasterClient)
					{
						Player player = interactor.player;
						FloatItemData val2 = default(FloatItemData);
						if (!((Object)(object)player == (Object)null) && player.backpackSlot != null && ((ItemSlot)player.backpackSlot).data != null && ((ItemSlot)player.backpackSlot).data.TryGetDataEntry<FloatItemData>((DataEntryKey)10, ref val2))
						{
							s_beforeFuel = val2.Value;
							s_beforeGuid = ((ItemSlot)player.backpackSlot).data.guid;
						}
					}
				}
				catch (Exception e)
				{
					s_beforeFuel = float.NaN;
					s_beforeGuid = Guid.Empty;
					LogPatchError("AddFuelToJetpack prefix", e);
				}
			}

			[HarmonyPostfix]
			private static void Postfix(CharacterBackpackHandler __instance, Character interactor)
			{
				float num = s_beforeFuel;
				Guid guid = s_beforeGuid;
				s_beforeFuel = float.NaN;
				s_beforeGuid = Guid.Empty;
				try
				{
					if (!float.IsNaN(num) && !((Object)(object)interactor == (Object)null) && !((Object)(object)__instance == (Object)null) && interactor.refs != null && !((Object)(object)interactor.refs.backpackHandler != (Object)(object)__instance))
					{
						Player player = interactor.player;
						FloatItemData val = default(FloatItemData);
						if (!((Object)(object)player == (Object)null) && player.backpackSlot != null && ((ItemSlot)player.backpackSlot).data != null && !(((ItemSlot)player.backpackSlot).data.guid != guid) && ((ItemSlot)player.backpackSlot).data.TryGetDataEntry<FloatItemData>((DataEntryKey)10, ref val) && !(val.Value <= num + 0.01f))
						{
							s_pendingArmed = true;
							s_pendingBaseFuel = num;
							s_pendingPlayer = player;
							s_pendingDataGuid = guid;
							s_pendingLastRefuelTime = Time.unscaledTime;
						}
					}
				}
				catch (Exception e)
				{
					ClearPendingRefuel();
					LogPatchError("AddFuelToJetpack postfix", e);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "SyncInventoryRPC")]
		private static class SyncInventoryRefuelFix
		{
			[HarmonyPrefix]
			private static void Prefix(Player __instance)
			{
				s_pendingPreSyncFuel = float.NaN;
				try
				{
					if ((Object)(object)__instance == (Object)null || !s_pendingArmed || PhotonNetwork.IsMasterClient || (Object)(object)__instance != (Object)(object)s_pendingPlayer)
					{
						return;
					}
					BackpackSlot backpackSlot = __instance.backpackSlot;
					if (backpackSlot != null && !((ItemSlot)backpackSlot).IsEmpty())
					{
						ItemInstanceData data = ((ItemSlot)backpackSlot).data;
						FloatItemData val = default(FloatItemData);
						if (data != null && !(data.guid != s_pendingDataGuid) && data.TryGetDataEntry<FloatItemData>((DataEntryKey)10, ref val))
						{
							s_pendingPreSyncFuel = val.Value;
						}
					}
				}
				catch (Exception e)
				{
					s_pendingPreSyncFuel = float.NaN;
					LogPatchError("SyncInventoryRPC prefix", e);
				}
			}

			[HarmonyPostfix]
			private static void Postfix(Player __instance)
			{
				float s_pendingPreSyncFuel = Entry.s_pendingPreSyncFuel;
				Entry.s_pendingPreSyncFuel = float.NaN;
				try
				{
					if (float.IsNaN(s_pendingPreSyncFuel) || (Object)(object)__instance == (Object)null)
					{
						return;
					}
					BackpackSlot backpackSlot = __instance.backpackSlot;
					if (backpackSlot == null)
					{
						return;
					}
					if (((ItemSlot)backpackSlot).IsEmpty())
					{
						ClearPendingRefuel();
						return;
					}
					ItemInstanceData data = ((ItemSlot)backpackSlot).data;
					if (data == null)
					{
						return;
					}
					if (data.guid != s_pendingDataGuid)
					{
						ClearPendingRefuel();
					}
					else
					{
						FloatItemData val = default(FloatItemData);
						if (!data.TryGetDataEntry<FloatItemData>((DataEntryKey)10, ref val))
						{
							return;
						}
						if (val.Value > s_pendingBaseFuel + 0.01f)
						{
							ClearPendingRefuel();
							return;
						}
						val.Value = s_pendingPreSyncFuel;
						FloatItemData val2 = default(FloatItemData);
						if (data.TryGetDataEntry<FloatItemData>((DataEntryKey)11, ref val2))
						{
							val2.Value = Mathf.Clamp01(s_pendingPreSyncFuel / 100f);
						}
					}
				}
				catch (Exception e)
				{
					ClearPendingRefuel();
					LogPatchError("SyncInventoryRPC postfix", e);
				}
			}
		}

		private static readonly ManualLogSource logger = Logger.CreateLogSource("EasyBackpack");

		private static ConfigEntry<KeyCode> backpackKey;

		private static ConfigEntry<KeyCode> alternativeBackpackKey;

		private static bool isAccessingBackpack;

		private static bool isAccessingCarriedPlayersBackpack;

		private static KeyCode s_activeKey = (KeyCode)0;

		private static float s_lastOpenWarn = float.MinValue;

		private static float s_lastPatchWarn = float.MinValue;

		private static KeyCode s_cachedMainKey = (KeyCode)0;

		private static KeyCode s_cachedAltKey = (KeyCode)0;

		private static bool s_mainKeyPollable;

		private static bool s_altKeyPollable;

		private static bool s_quitting;

		private static bool s_pendingArmed;

		private static float s_pendingBaseFuel;

		private static float s_pendingPreSyncFuel;

		private static Player s_pendingPlayer;

		private static Guid s_pendingDataGuid;

		private static float s_pendingLastRefuelTime;

		private const float s_pendingCleanupSeconds = 30f;

		private readonly Harmony m_harmony = new Harmony("nickklmao.easybackpack");

		private void Awake()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			logger.LogInfo((object)"Creating config entries");
			backpackKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keybinds", "Backpack Key", (KeyCode)98, new ConfigDescription("The key you want to use to access the backpack while it's on your back", (AcceptableValueBase)null, Array.Empty<object>()));
			alternativeBackpackKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keybinds", "Alternative Backpack Key", (KeyCode)0, new ConfigDescription("An optional alternative key for accessing the backpack while it's on your back", (AcceptableValueBase)null, Array.Empty<object>()));
			ReleaseWheel();
			ClearPendingRefuel();
			s_quitting = false;
			s_cachedAltKey = (KeyCode)0;
			s_cachedMainKey = (KeyCode)0;
			s_mainKeyPollable = (s_altKeyPollable = false);
			logger.LogInfo((object)"Hooking BackpackWheel.Update");
			ApplyPatch(typeof(BackpackWheelUpdatePatch), "BackpackWheel.Update");
			ApplyPatch(typeof(WheelClosedPatch), "GUIManager.CloseBackpackWheel");
			ApplyPatch(typeof(SelfRefuelRollbackFix), "CharacterBackpackHandler.AddFuelToJetpack");
			ApplyPatch(typeof(SyncInventoryRefuelFix), "Player.SyncInventoryRPC");
		}

		private void ApplyPatch(Type patchClass, string target)
		{
			try
			{
				m_harmony.PatchAll(patchClass);
			}
			catch (Exception arg)
			{
				logger.LogError((object)$"Failed to patch {target}: {arg}");
			}
		}

		private void OnApplicationQuit()
		{
			s_quitting = true;
		}

		private void OnDestroy()
		{
			ReleaseWheel();
			ClearPendingRefuel();
			if (s_quitting)
			{
				return;
			}
			try
			{
				m_harmony.UnpatchSelf();
			}
			catch (Exception arg)
			{
				logger.LogWarning((object)$"Failed to remove patches on unload: {arg}");
			}
		}

		private void Update()
		{
			try
			{
				UpdateInternal();
			}
			catch (Exception e)
			{
				ReleaseWheel();
				LogPatchError("Update", e);
			}
		}

		private void UpdateInternal()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: 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_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: 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_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			if (s_pendingArmed && Time.unscaledTime - s_pendingLastRefuelTime > 30f)
			{
				ClearPendingRefuel();
			}
			Character localCharacter = Character.localCharacter;
			if (!Application.isFocused || (Object)(object)localCharacter == (Object)null)
			{
				ReleaseWheel();
				return;
			}
			if (isAccessingBackpack && !IsBackpackWheelActive())
			{
				ReleaseWheel();
			}
			if (isAccessingBackpack && ((int)s_activeKey == 0 || !Input.GetKey(s_activeKey)))
			{
				ReleaseWheel();
				return;
			}
			if (isAccessingCarriedPlayersBackpack)
			{
				if ((Object)(object)localCharacter.data.carriedPlayer == (Object)null)
				{
					ReleaseWheel();
					return;
				}
			}
			else if (localCharacter.data.passedOut || localCharacter.data.fullyPassedOut || localCharacter.data.dead || localCharacter.data.currentItem is Backpack)
			{
				ReleaseWheel();
				return;
			}
			KeyCode value = backpackKey.Value;
			KeyCode value2 = alternativeBackpackKey.Value;
			if (value != s_cachedMainKey)
			{
				s_cachedMainKey = value;
				s_mainKeyPollable = IsPollableKey(value, "Backpack Key");
			}
			if (value2 != s_cachedAltKey)
			{
				s_cachedAltKey = value2;
				s_altKeyPollable = IsPollableKey(value2, "Alternative Backpack Key");
			}
			KeyCode val = (KeyCode)0;
			if (s_mainKeyPollable && Input.GetKeyDown(value))
			{
				val = value;
			}
			else if (s_altKeyPollable && Input.GetKeyDown(value2))
			{
				val = value2;
			}
			if ((int)val == 0)
			{
				return;
			}
			try
			{
				Player player = localCharacter.player;
				if ((Object)(object)player != (Object)null)
				{
					BackpackSlot backpackSlot = player.backpackSlot;
					if (backpackSlot != null && !((ItemSlot)backpackSlot).IsEmpty())
					{
						TryOpenWheel(localCharacter, backpackSlot.backpackType, val, carried: false);
						return;
					}
				}
				Character carriedPlayer = localCharacter.data.carriedPlayer;
				if ((Object)(object)carriedPlayer == (Object)null)
				{
					return;
				}
				Player player2 = carriedPlayer.player;
				if (!((Object)(object)player2 == (Object)null))
				{
					BackpackSlot backpackSlot2 = player2.backpackSlot;
					if (backpackSlot2 != null && !((ItemSlot)backpackSlot2).IsEmpty())
					{
						TryOpenWheel(carriedPlayer, backpackSlot2.backpackType, val, carried: true);
					}
				}
			}
			catch (Exception e)
			{
				LogOpenFailure(e);
			}
		}

		private static void ReleaseWheel()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			isAccessingCarriedPlayersBackpack = (isAccessingBackpack = false);
			s_activeKey = (KeyCode)0;
		}

		private static bool IsPollableKey(KeyCode key, string configName)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected I4, but got Unknown
			if ((int)key == 0)
			{
				return false;
			}
			if (!Enum.IsDefined(typeof(KeyCode), key))
			{
				logger.LogWarning((object)$"Config entry \"{configName}\" holds an invalid KeyCode value ({(int)key}); this key is ignored.");
				return false;
			}
			return true;
		}

		private static void TryOpenWheel(Character owner, BackpackType backpackType, KeyCode openedWith, bool carried)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_003c: 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_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if ((int)backpackType == 4 || IsBackpackWheelActive())
			{
				return;
			}
			int num = 4;
			CharacterBackpackHandler backpackHandler = owner.refs.backpackHandler;
			if ((Object)(object)backpackHandler != (Object)null)
			{
				BackpackOnBackVisuals activeBackpackVisuals = backpackHandler.activeBackpackVisuals;
				if ((Object)(object)activeBackpackVisuals != (Object)null)
				{
					num = activeBackpackVisuals.slotCount;
				}
			}
			BackpackReference fromEquippedBackpack = BackpackReference.GetFromEquippedBackpack(owner);
			GUIManager.instance.OpenBackpackWheel(fromEquippedBackpack, num, backpackType);
			if (IsBackpackWheelActive())
			{
				isAccessingBackpack = true;
				s_activeKey = openedWith;
				if (carried)
				{
					isAccessingCarriedPlayersBackpack = true;
				}
			}
		}

		private static bool IsBackpackWheelActive()
		{
			GUIManager instance = GUIManager.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			BackpackWheel backpackWheel = instance.backpackWheel;
			if ((Object)(object)backpackWheel != (Object)null)
			{
				return ((Component)backpackWheel).gameObject.activeSelf;
			}
			return false;
		}

		private static void LogOpenFailure(Exception e)
		{
			if (Time.unscaledTime - s_lastOpenWarn > 5f)
			{
				s_lastOpenWarn = Time.unscaledTime;
				logger.LogWarning((object)$"Failed to open the backpack wheel (player, backpack visuals or ragdoll not ready); the wheel was not opened. {e}");
			}
		}

		private static void LogPatchError(string where, Exception e)
		{
			if (Time.unscaledTime - s_lastPatchWarn > 5f)
			{
				s_lastPatchWarn = Time.unscaledTime;
				logger.LogWarning((object)$"Unexpected error in {where}: {e}");
			}
		}

		private static void ClearPendingRefuel()
		{
			s_pendingArmed = false;
			s_pendingPlayer = null;
			s_pendingDataGuid = Guid.Empty;
			s_pendingPreSyncFuel = float.NaN;
		}
	}
}