Decompiled source of Piggyback v1.4.2

Piggyback.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;
using UnityEngine.InputSystem;
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("nakazora.peak.piggyback")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.4.2.0")]
[assembly: AssemblyInformationalVersion("1.4.2+66865b3932060eacaf84e84533a141136e00fd26")]
[assembly: AssemblyProduct("Piggyback")]
[assembly: AssemblyTitle("nakazora.peak.piggyback")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 Piggyback
{
	public static class ExpressionUtils
	{
		public static Func<T, TResult> CreateFieldGetter<T, TResult>(string fieldName)
		{
			ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "instance");
			return Expression.Lambda<Func<T, TResult>>(Expression.Field(parameterExpression, fieldName), new ParameterExpression[1] { parameterExpression }).Compile();
		}
	}
	[BepInPlugin("nakazora.peak.piggyback", "Piggyback", "1.4.2")]
	public class Piggyback : BaseUnityPlugin
	{
		private class CanBeCarriedPatch
		{
			[CompilerGenerated]
			private sealed class <RefreshPromptCoroutine>d__2 : IEnumerator<object>, IEnumerator, IDisposable
			{
				private int <>1__state;

				private object <>2__current;

				public CharacterInteractible interactible;

				object IEnumerator<object>.Current
				{
					[DebuggerHidden]
					get
					{
						return <>2__current;
					}
				}

				object IEnumerator.Current
				{
					[DebuggerHidden]
					get
					{
						return <>2__current;
					}
				}

				[DebuggerHidden]
				public <RefreshPromptCoroutine>d__2(int <>1__state)
				{
					this.<>1__state = <>1__state;
				}

				[DebuggerHidden]
				void IDisposable.Dispose()
				{
					<>1__state = -2;
				}

				private bool MoveNext()
				{
					int num = <>1__state;
					if (num != 0)
					{
						if (num != 1)
						{
							return false;
						}
						<>1__state = -1;
					}
					else
					{
						<>1__state = -1;
					}
					if (GetCurrentInteractable(GUIManager.instance) == interactible)
					{
						GUIManager.instance.RefreshInteractablePrompt();
					}
					<>2__current = null;
					<>1__state = 1;
					return true;
				}

				bool IEnumerator.MoveNext()
				{
					//ILSpy generated this explicit interface implementation from .override directive in MoveNext
					return this.MoveNext();
				}

				[DebuggerHidden]
				void IEnumerator.Reset()
				{
					throw new NotSupportedException();
				}
			}

			private static readonly Func<GUIManager, IInteractible> GetCurrentInteractable = (Func<GUIManager, IInteractible>)Delegate.CreateDelegate(typeof(Func<GUIManager, IInteractible>), AccessTools.PropertyGetter(typeof(GUIManager), "currentInteractable"));

			private static readonly Dictionary<CharacterInteractible, Coroutine> s_refreshCoroutines = new Dictionary<CharacterInteractible, Coroutine>();

			[IteratorStateMachine(typeof(<RefreshPromptCoroutine>d__2))]
			private static IEnumerator RefreshPromptCoroutine(CharacterInteractible interactible)
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <RefreshPromptCoroutine>d__2(0)
				{
					interactible = interactible
				};
			}

			[HarmonyPatch(typeof(CharacterInteractible), "CanBeCarried")]
			[HarmonyPostfix]
			private static void CanBeCarriedPostfix(ref bool __result, Character ___character)
			{
				if (__result || ___character.IsLocal || ___character.data.dead)
				{
					return;
				}
				if (s_swapBackpackSetting.Value)
				{
					if (Player.localPlayer.backpackSlot.hasBackpack && ___character.player.backpackSlot.hasBackpack)
					{
						return;
					}
				}
				else if (Player.localPlayer.backpackSlot.hasBackpack)
				{
					return;
				}
				if (!Character.localCharacter.data.isClimbingAnything && !Object.op_Implicit((Object)(object)___character.data.currentItem) && !IsCharacterDoingIllegalCarryActions(___character) && !Object.op_Implicit((Object)(object)___character.data.carrier) && (!Object.op_Implicit((Object)(object)Character.localCharacter.data.currentItem) || !Character.localCharacter.data.currentItem.canUseOnFriend) && !___character.refs.customization.isCannibalizable)
				{
					__result = true;
				}
			}

			[HarmonyPatch(typeof(CharacterInteractible), "IsInteractible")]
			[HarmonyPostfix]
			private static bool IsInteractablePostfix(bool originalResult, CharacterInteractible __instance, Character interactor)
			{
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				if (interactor.data.isCarried || !originalResult)
				{
					return false;
				}
				if (__instance.character.refs.customization.isCannibalizable)
				{
					return true;
				}
				if (CarriedByLocalCharacterDelegate(__instance))
				{
					return true;
				}
				if (!CanBeCarriedDelegate(__instance))
				{
					return true;
				}
				if (__instance.character.data.fullyPassedOut)
				{
					return true;
				}
				return Vector3.Distance(interactor.Center, __instance.character.Center) <= 2f;
			}

			[HarmonyPatch(typeof(CharacterCarrying), "Update")]
			[HarmonyPrefix]
			private static bool CharacterCarryingUpdatePrefix(Character ___character)
			{
				if (!___character.refs.view.IsMine)
				{
					return true;
				}
				if (!Object.op_Implicit((Object)(object)___character.data.carriedPlayer))
				{
					return true;
				}
				if (Object.op_Implicit((Object)(object)___character.data.carriedPlayer.data.currentItem))
				{
					return true;
				}
				if (IsCharacterDoingIllegalCarryActions(___character.data.carriedPlayer))
				{
					return true;
				}
				if (!___character.data.carriedPlayer.data.dead && !___character.data.fullyPassedOut && !___character.data.dead)
				{
					return false;
				}
				return true;
			}

			[HarmonyPatch(typeof(CharacterCarrying), "CarrierGone")]
			[HarmonyPostfix]
			private static void CharacterCarryingCarrierGonePostfix(Character ___character)
			{
				___character.data.isCarried = false;
			}

			[HarmonyPatch(typeof(CharacterInput), "Sample")]
			[HarmonyPostfix]
			private static void CharacterInputSamplePostfix(CharacterInput __instance)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				if (!Character.localCharacter.data.fullyPassedOut && Character.localCharacter.data.isCarried)
				{
					__instance.movementInput = Vector2.zero;
					__instance.interactWasPressed = false;
					__instance.interactIsPressed = false;
					__instance.emoteIsPressed = false;
					__instance.sprintWasPressed = false;
					__instance.sprintIsPressed = false;
					__instance.sprintToggleIsPressed = false;
					__instance.sprintToggleWasPressed = false;
					__instance.dropWasPressed = false;
					__instance.dropIsPressed = false;
					__instance.usePrimaryWasPressed = false;
					__instance.usePrimaryIsPressed = false;
					__instance.useSecondaryWasPressed = false;
					__instance.useSecondaryIsPressed = false;
					__instance.spectateLeftWasPressed = false;
					__instance.spectateRightWasPressed = false;
					__instance.selectBackpackWasPressed = false;
					__instance.scrollBackwardWasPressed = false;
					__instance.scrollForwardWasPressed = false;
					__instance.scrollBackwardIsPressed = false;
					__instance.scrollForwardIsPressed = false;
					__instance.selectSlotForwardWasPressed = false;
					__instance.selectSlotBackwardWasPressed = false;
					__instance.unselectSlotWasPressed = false;
				}
			}

			[HarmonyPatch(typeof(CharacterInput), "SelectSlotWasPressed")]
			[HarmonyPostfix]
			private static bool CharacterInputSelectSlotWasPressedPostfix(bool originalResult, CharacterInput __instance)
			{
				if (!Character.localCharacter.data.fullyPassedOut && Character.localCharacter.data.isCarried)
				{
					return false;
				}
				return originalResult;
			}

			[HarmonyPatch(typeof(CharacterInteractible), "HoverEnter")]
			[HarmonyPostfix]
			private static void HoverEnterPostfix(CharacterInteractible __instance)
			{
				if (!s_refreshCoroutines.ContainsKey(__instance))
				{
					Coroutine value = ((MonoBehaviour)__instance).StartCoroutine(RefreshPromptCoroutine(__instance));
					s_refreshCoroutines[__instance] = value;
				}
			}

			[HarmonyPatch(typeof(CharacterInteractible), "HoverExit")]
			[HarmonyPostfix]
			private static void HoverExitPostfix(CharacterInteractible __instance)
			{
				if (s_refreshCoroutines.TryGetValue(__instance, out var value))
				{
					((MonoBehaviour)__instance).StopCoroutine(value);
					s_refreshCoroutines.Remove(__instance);
				}
			}
		}

		private class SpectateViewPatch
		{
			private static readonly Func<MainCamera, CameraOverride> GetCamOverride = ExpressionUtils.CreateFieldGetter<MainCamera, CameraOverride>("camOverride");

			private static readonly Action<MainCameraMovement> SpectateDelegate = (Action<MainCameraMovement>)Delegate.CreateDelegate(typeof(Action<MainCameraMovement>), null, typeof(MainCameraMovement).GetMethod("Spectate", BindingFlags.Instance | BindingFlags.NonPublic));

			private static readonly Action<Character> SetSpecCharacter = (Action<Character>)Delegate.CreateDelegate(typeof(Action<Character>), AccessTools.PropertySetter(typeof(MainCameraMovement), "specCharacter"));

			private static float? m_defaultSpectateZoomMax = null;

			private static float m_customSpectateZoomMax = 3f;

			[HarmonyPatch(typeof(MainCameraMovement), "LateUpdate")]
			[HarmonyPostfix]
			private static void MainCameraMovementLateUpdatePostfix(MainCameraMovement __instance, MainCamera ___cam, bool ___isGodCam, ref bool ___isSpectating)
			{
				if (s_spectateViewSetting.Value && !(___isGodCam | ___isSpectating) && Object.op_Implicit((Object)(object)Character.localCharacter) && Character.localCharacter.data.isCarried && !Object.op_Implicit((Object)(object)GetCamOverride(___cam)))
				{
					SpectateDelegate(__instance);
					___isSpectating = true;
				}
			}

			[HarmonyPatch(typeof(MainCameraMovement), "HandleSpecSelection")]
			[HarmonyPrefix]
			private static bool HandleSpecSelectionPrefix(ref bool __result, MainCameraMovement __instance)
			{
				if (!Character.localCharacter.data.fullyPassedOut && Object.op_Implicit((Object)(object)Character.localCharacter.data.carrier))
				{
					if (!Object.op_Implicit((Object)(object)MainCameraMovement.specCharacter))
					{
						SetSpecCharacter(Character.localCharacter.data.carrier);
					}
					float valueOrDefault = m_defaultSpectateZoomMax.GetValueOrDefault();
					if (!m_defaultSpectateZoomMax.HasValue)
					{
						valueOrDefault = __instance.spectateZoomMax;
						m_defaultSpectateZoomMax = valueOrDefault;
					}
					__instance.spectateZoomMax = m_customSpectateZoomMax;
					__result = true;
					return false;
				}
				if (m_defaultSpectateZoomMax.HasValue)
				{
					__instance.spectateZoomMax = m_defaultSpectateZoomMax.Value;
				}
				return true;
			}
		}

		private class HoldToCarryPatch
		{
			private static bool s_isAttemptingToCarry;

			[HarmonyPatch(typeof(CharacterInteractible), "Interact")]
			[HarmonyPrefix]
			private static bool CharacterInteractibleInteractPrefix(CharacterInteractible __instance, Character interactor)
			{
				s_isAttemptingToCarry = false;
				if (CarriedByLocalCharacterDelegate(__instance))
				{
					return true;
				}
				if (__instance.character.refs.customization.isCannibalizable)
				{
					return true;
				}
				if (__instance.character.data.fullyPassedOut || s_holdToCarrySetting.Value == 0f)
				{
					return true;
				}
				s_isAttemptingToCarry = true;
				return false;
			}

			[HarmonyPatch(typeof(CharacterInteractible), "IsConstantlyInteractable")]
			[HarmonyPostfix]
			private static bool CharacterInteractibleIsConstantlyInteractablePostfix(bool originalResult, CharacterInteractible __instance)
			{
				if (!originalResult)
				{
					return CanBeCarriedDelegate(__instance);
				}
				return true;
			}

			[HarmonyPatch(typeof(CharacterInteractible), "GetInteractTime")]
			[HarmonyPostfix]
			private static float CharacterInteractibleGetInteractTimePostfix(float originalResult, CharacterInteractible __instance)
			{
				if (!__instance.character.refs.customization.isCannibalizable)
				{
					return s_holdToCarrySetting.Value;
				}
				return originalResult;
			}

			[HarmonyPatch(typeof(CharacterInteractible), "Interact_CastFinished")]
			[HarmonyPrefix]
			private static bool CharacterInteractibleCastFinishedPrefix(CharacterInteractible __instance, Character interactor)
			{
				if (!interactor.IsLocal)
				{
					return false;
				}
				if (!s_isAttemptingToCarry)
				{
					return true;
				}
				if (CanBeCarriedDelegate(__instance))
				{
					StartCarryDelegate(interactor.refs.carriying, __instance.character);
				}
				s_isAttemptingToCarry = false;
				return false;
			}
		}

		private class BackpackSwapOnCarryPatch
		{
			private static BackpackSlot s_swappedBackpack;

			private static bool WasBackpackSwapped => s_swappedBackpack != null;

			private static bool IsSameBackpack(BackpackSlot a, BackpackSlot b)
			{
				if (a != b)
				{
					if (((ItemSlot)a).data != null && ((ItemSlot)b).data != null)
					{
						return ((ItemSlot)a).data.guid == ((ItemSlot)b).data.guid;
					}
					return false;
				}
				return true;
			}

			[HarmonyPatch(typeof(CharacterCarrying), "StartCarry")]
			[HarmonyPrefix]
			private static bool StartCarryPrefix(ref Character ___character, Character target)
			{
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Expected O, but got Unknown
				//IL_007f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
				if (!s_swapBackpackSetting.Value)
				{
					return true;
				}
				s_swappedBackpack = null;
				BackpackSlot backpackSlot = ___character.player.backpackSlot;
				if (!backpackSlot.hasBackpack || target.player.backpackSlot.hasBackpack)
				{
					return true;
				}
				target.player.backpackSlot = backpackSlot;
				___character.player.backpackSlot = new BackpackSlot((byte)3);
				byte[] array = IBinarySerializable.ToManagedArray<InventorySyncData>(new InventorySyncData(___character.player.itemSlots, ___character.player.backpackSlot, ___character.player.tempFullSlot));
				((MonoBehaviourPun)___character.player).photonView.RPC("SyncInventoryRPC", (RpcTarget)0, new object[2] { array, true });
				byte[] array2 = IBinarySerializable.ToManagedArray<InventorySyncData>(new InventorySyncData(target.player.itemSlots, target.player.backpackSlot, target.player.tempFullSlot));
				((MonoBehaviourPun)target.player).photonView.RPC("SyncInventoryRPC", (RpcTarget)0, new object[2] { array2, true });
				s_swappedBackpack = backpackSlot;
				return true;
			}

			[HarmonyPatch(typeof(CharacterCarrying), "RPCA_Drop")]
			[HarmonyPrefix]
			private static void DropPostfix(ref Character ___character, PhotonView targetView)
			{
				//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c2: Expected O, but got Unknown
				//IL_00e3: 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)
				if (!s_swapBackpackSetting.Value || !WasBackpackSwapped || (Object)(object)Character.localCharacter != (Object)(object)___character)
				{
					return;
				}
				if (___character.player.backpackSlot.hasBackpack)
				{
					s_swappedBackpack = null;
					return;
				}
				Character component = ((Component)targetView).GetComponent<Character>();
				if (!component.player.backpackSlot.hasBackpack)
				{
					if (!PlayerHandler.GetAllPlayers().Any((Player p) => IsSameBackpack(p.backpackSlot, s_swappedBackpack)))
					{
						((ItemSlot)s_swappedBackpack).prefab.Interact(___character);
					}
					s_swappedBackpack = null;
					return;
				}
				BackpackSlot backpackSlot = component.player.backpackSlot;
				___character.player.backpackSlot = backpackSlot;
				component.player.backpackSlot = new BackpackSlot((byte)3);
				byte[] array = IBinarySerializable.ToManagedArray<InventorySyncData>(new InventorySyncData(component.player.itemSlots, component.player.backpackSlot, component.player.tempFullSlot));
				((MonoBehaviourPun)component.player).photonView.RPC("SyncInventoryRPC", (RpcTarget)0, new object[2] { array, true });
				byte[] array2 = IBinarySerializable.ToManagedArray<InventorySyncData>(new InventorySyncData(___character.player.itemSlots, ___character.player.backpackSlot, ___character.player.tempFullSlot));
				((MonoBehaviourPun)___character.player).photonView.RPC("SyncInventoryRPC", (RpcTarget)0, new object[2] { array2, true });
				s_swappedBackpack = null;
			}
		}

		private class WeightPatch
		{
			[HarmonyPatch(typeof(CharacterAfflictions), "UpdateWeight")]
			[HarmonyPostfix]
			private static void UpdateWeightPostfix(CharacterAfflictions __instance)
			{
				if (!s_accurateWeightSetting.Value || !Object.op_Implicit((Object)(object)__instance.character.data.carriedPlayer))
				{
					return;
				}
				float currentStatus = __instance.GetCurrentStatus((STATUSTYPE)7);
				currentStatus -= 0.2f;
				if (currentStatus < 0f)
				{
					currentStatus = 0f;
				}
				int num = 0;
				Character carriedPlayer = __instance.character.data.carriedPlayer;
				if (Object.op_Implicit((Object)(object)carriedPlayer))
				{
					int num2 = 8;
					for (int i = 0; i < carriedPlayer.player.itemSlots.Length; i++)
					{
						ItemSlot val = carriedPlayer.player.itemSlots[i];
						if (Object.op_Implicit((Object)(object)val.prefab))
						{
							num2 += val.prefab.CarryWeight;
						}
					}
					BackpackSlot backpackSlot = carriedPlayer.player.backpackSlot;
					BackpackData val2 = default(BackpackData);
					if (!((ItemSlot)backpackSlot).IsEmpty() && ((ItemSlot)backpackSlot).data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val2))
					{
						for (int j = 0; j < val2.itemSlots.Length; j++)
						{
							ItemSlot val3 = val2.itemSlots[j];
							if (!val3.IsEmpty())
							{
								num2 += val3.prefab.CarryWeight;
							}
						}
					}
					num += num2;
				}
				float num3 = 0.025f * (float)num;
				float num4 = currentStatus + num3;
				__instance.SetStatus((STATUSTYPE)7, num4);
			}
		}

		internal static ManualLogSource Logger;

		private readonly Harmony m_harmony = new Harmony("nakazora.peak.piggyback");

		private static ConfigEntry<bool> s_enablePiggybackSetting;

		private static ConfigEntry<bool> s_allowPiggybackByOthersSetting;

		private static ConfigEntry<bool> s_spectateViewSetting;

		private static ConfigEntry<float> s_holdToCarrySetting;

		private static ConfigEntry<bool> s_swapBackpackSetting;

		private static ConfigEntry<bool> s_accurateWeightSetting;

		private static ConfigEntry<string> s_gamepadDropKeyBindingSetting;

		private static readonly Dictionary<string, string> GamepadKeysToControlPath = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "DpadUp", "dpad/up" },
			{ "DpadDown", "dpad/down" },
			{ "DpadLeft", "dpad/left" },
			{ "DpadRight", "dpad/right" },
			{ "North", "buttonSouth" },
			{ "East", "buttonEast" },
			{ "South", "buttonSouth" },
			{ "West", "buttonWest" },
			{ "LeftStickButton", "leftStickPress" },
			{ "RightStickButton", "rightStickPress" },
			{ "LeftShoulder", "leftShoulder" },
			{ "RightShoulder", "rightShoulder" },
			{ "LeftTrigger", "leftTrigger" },
			{ "RightTrigger", "rightTrigger" },
			{ "Start", "start" },
			{ "Select", "select" }
		};

		private static List<InputAction> s_gamepadDropActions = new List<InputAction>();

		private static readonly Action<CharacterCarrying, Character> DropFromCarryDelegate = (Action<CharacterCarrying, Character>)Delegate.CreateDelegate(typeof(Action<CharacterCarrying, Character>), null, typeof(CharacterCarrying).GetMethod("Drop", BindingFlags.Instance | BindingFlags.NonPublic));

		private static readonly Func<CharacterInteractible, bool> CarriedByLocalCharacterDelegate = (Func<CharacterInteractible, bool>)Delegate.CreateDelegate(typeof(Func<CharacterInteractible, bool>), null, typeof(CharacterInteractible).GetMethod("CarriedByLocalCharacter", BindingFlags.Instance | BindingFlags.NonPublic));

		private static readonly Func<CharacterInteractible, bool> CanBeCarriedDelegate = (Func<CharacterInteractible, bool>)Delegate.CreateDelegate(typeof(Func<CharacterInteractible, bool>), null, typeof(CharacterInteractible).GetMethod("CanBeCarried", BindingFlags.Instance | BindingFlags.NonPublic));

		private static readonly Action<CharacterCarrying, Character> StartCarryDelegate = (Action<CharacterCarrying, Character>)Delegate.CreateDelegate(typeof(Action<CharacterCarrying, Character>), null, typeof(CharacterCarrying).GetMethod("StartCarry", BindingFlags.Instance | BindingFlags.NonPublic));

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			SetupConfig();
			if (s_enablePiggybackSetting.Value)
			{
				m_harmony.PatchAll(typeof(CanBeCarriedPatch));
				m_harmony.PatchAll(typeof(SpectateViewPatch));
				m_harmony.PatchAll(typeof(HoldToCarryPatch));
			}
			m_harmony.PatchAll(typeof(BackpackSwapOnCarryPatch));
			m_harmony.PatchAll(typeof(WeightPatch));
			Logger.LogInfo((object)"Plugin Piggyback loaded");
		}

		private void SetupConfig()
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			s_enablePiggybackSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnablePiggyback", true, "If false, you won't be able to piggyback others.\nThe AllowPiggybackByOthers, SwapBackpack, and GamepadDropKeybind settings will still take effect, but you won't be able to carry players that are not passed out.");
			s_allowPiggybackByOthersSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowPiggybackByOthers", true, "If false, you'll be immediately dropped whenever a player attempts to carry you while you're not passed out. Use this if you want to fully prevent players from picking you up.");
			s_spectateViewSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SpectateView", true, "If true, the camera will switch to the spectate view while being carried.\nIf false, the camera will remain in the first-person view while being carried.\nNote that you'll only be able to spectate the player carrying you.");
			s_holdToCarrySetting = ((BaseUnityPlugin)this).Config.Bind<float>("General", "HoldToCarryTime", 1.5f, new ConfigDescription("The time in seconds you need to hold the interact button to start carrying another player.\nIf 0, you will start carrying the player immediately upon pressing the interact button.\nIf the player is passed out, you will start carrying them immediately even if this is set to a value greater than 0.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			s_swapBackpackSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SwapBackpack", true, "If true, if you have a backpack and start carrying another player who does not have a backpack, the player you're carrying will automatically equip your backpack.\nThe backpack will be returned to you when you drop the player.\nIf false or if the player you want to carry already has a backpack, you must manually drop your backpack before you can carry that player.");
			s_accurateWeightSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AccurateWeight", false, "If true, the full weight of the player you're carrying, including the items they are carrying, will be added to your own weight.\nThis will also consider the weight reduction provided by any balloons that the carried player may have.\nIf false, it won't add the weight of the items they are carrying (vanilla behaviour).");
			s_gamepadDropKeyBindingSetting = ((BaseUnityPlugin)this).Config.Bind<string>("Controls", "GamepadDropKeybind", "LeftShoulder+RightShoulder", "The key binding to drop the player you're carrying. This only applies to Gamepad, the binding on keyboard should be the Number 4 key by default.\nYou can combine multiple keys by separating them with a plus (+) sign. This would require you to press all the given keys at the same time to drop the player.\nAcceptable Gamepad Keys:\nNone, " + string.Join(", ", GamepadKeysToControlPath.Keys));
			s_gamepadDropKeyBindingSetting.SettingChanged += delegate
			{
				SetupGamepadDropAction();
			};
			SetupGamepadDropAction();
		}

		private static void SetupGamepadDropAction()
		{
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Expected O, but got Unknown
			string text = s_gamepadDropKeyBindingSetting.Value.Trim();
			if (s_gamepadDropActions.Count > 0)
			{
				foreach (InputAction s_gamepadDropAction in s_gamepadDropActions)
				{
					s_gamepadDropAction.Disable();
					s_gamepadDropAction.Dispose();
				}
				s_gamepadDropActions.Clear();
			}
			if (text.ToLower() == "none")
			{
				Logger.LogInfo((object)"Gamepad drop key binding is set to 'None'. Disabling custom drop key binding.");
				return;
			}
			HashSet<string> hashSet = new HashSet<string>();
			bool flag = false;
			string[] array = text.Split('+');
			foreach (string text2 in array)
			{
				if (GamepadKeysToControlPath.TryGetValue(text2.Trim(), out var value))
				{
					hashSet.Add("<Gamepad>/" + value);
					continue;
				}
				Logger.LogWarning((object)("Unknown gamepad key: " + text2.Trim()));
				flag = true;
			}
			if (flag)
			{
				string text3 = (string)((ConfigEntryBase)s_gamepadDropKeyBindingSetting).DefaultValue;
				Logger.LogError((object)("Invalid gamepad key binding detected. Falling back to default binding: " + text3));
				hashSet.Clear();
				array = text3.Split('+');
				foreach (string text4 in array)
				{
					if (GamepadKeysToControlPath.TryGetValue(text4.Trim(), out var value2))
					{
						hashSet.Add("<Gamepad>/" + value2);
					}
					else
					{
						Logger.LogError((object)("Unknown default gamepad key: " + text4.Trim()));
					}
				}
			}
			foreach (string item in hashSet)
			{
				InputAction val = new InputAction("DropCarry_" + item, (InputActionType)1, item, (string)null, (string)null, (string)null);
				s_gamepadDropActions.Add(val);
				val.Enable();
			}
			Logger.LogInfo((object)("Custom drop key binding set to: " + string.Join(" + ", hashSet)));
		}

		private void Update()
		{
			if (Object.op_Implicit((Object)(object)Character.localCharacter))
			{
				if (Object.op_Implicit((Object)(object)Character.localCharacter.data.carriedPlayer) && s_gamepadDropActions.Count > 0 && ((s_gamepadDropActions.Count == 1 && s_gamepadDropActions[0].WasPressedThisFrame()) || s_gamepadDropActions.All((InputAction action) => action.IsPressed())))
				{
					DropPlayerFromCarry(Character.localCharacter.data.carriedPlayer);
				}
				if (!s_allowPiggybackByOthersSetting.Value && !Character.localCharacter.data.fullyPassedOut && Character.localCharacter.data.isCarried)
				{
					DropPlayerFromCarry(Character.localCharacter);
				}
				else if (s_enablePiggybackSetting.Value && !Character.localCharacter.data.fullyPassedOut && Character.localCharacter.data.isCarried && IsCharacterDoingIllegalCarryActions(Character.localCharacter))
				{
					DropPlayerFromCarry(Character.localCharacter);
				}
			}
		}

		private static void DropPlayerFromCarry(Character character)
		{
			if (Object.op_Implicit((Object)(object)character.data.carrier))
			{
				DropFromCarryDelegate(character.data.carrier.refs.carriying, character);
			}
		}

		private static bool IsCharacterDoingIllegalCarryActions(Character character)
		{
			if (!character.data.isSprinting && !character.data.isJumping && !character.data.isClimbingAnything && !character.data.isCrouching && !character.data.isReaching)
			{
				return Object.op_Implicit((Object)(object)character.data.carriedPlayer);
			}
			return true;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "nakazora.peak.piggyback";

		public const string PLUGIN_NAME = "Piggyback";

		public const string PLUGIN_VERSION = "1.4.2";
	}
}