Decompiled source of Capes Precision Drop v1.0.1

CapesPrecisionDrop.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
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 UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("CapesPrecisionDrop")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("CapesPrecisionDrop")]
[assembly: AssemblyTitle("CapesPrecisionDrop")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 CapesPrecisionDrop
{
	internal static class GhostBuilder
	{
		public static GameObject Build(GameObject prefab)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: 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)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("CapesPrecisionDrop_Ghost");
			if ((Object)(object)prefab != (Object)null)
			{
				Transform transform = prefab.transform;
				MeshFilter[] componentsInChildren = prefab.GetComponentsInChildren<MeshFilter>(true);
				foreach (MeshFilter val2 in componentsInChildren)
				{
					MeshRenderer component = ((Component)val2).GetComponent<MeshRenderer>();
					if (!((Object)(object)component == (Object)null) && ((Renderer)component).enabled && !((Object)(object)val2.sharedMesh == (Object)null) && ((Component)val2).gameObject.activeSelf)
					{
						GameObject val3 = new GameObject(((Object)val2).name);
						val3.transform.SetParent(val.transform, false);
						val3.transform.localPosition = transform.InverseTransformPoint(((Component)val2).transform.position);
						val3.transform.localRotation = Quaternion.Inverse(transform.rotation) * ((Component)val2).transform.rotation;
						val3.transform.localScale = ((Component)val2).transform.lossyScale;
						val3.AddComponent<MeshFilter>().sharedMesh = val2.sharedMesh;
						MeshRenderer obj = val3.AddComponent<MeshRenderer>();
						((Renderer)obj).sharedMaterials = ((Renderer)component).sharedMaterials;
						((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
					}
				}
			}
			if (val.transform.childCount == 0)
			{
				GameObject obj2 = GameObject.CreatePrimitive((PrimitiveType)0);
				Object.Destroy((Object)(object)obj2.GetComponent<Collider>());
				obj2.transform.SetParent(val.transform, false);
				obj2.transform.localScale = Vector3.one * 0.25f;
			}
			return val;
		}
	}
	[HarmonyPatch(typeof(Humanoid), "DropItem")]
	internal static class Humanoid_DropItem_Patch
	{
		private static readonly MethodInfo SetupDragItem = AccessTools.Method(typeof(InventoryGui), "SetupDragItem", (Type[])null, (Type[])null);

		private static bool Prefix(Humanoid __instance, Inventory __0, ItemData __1, int __2, ref bool __result)
		{
			if (PlacementController.PendingTarget.HasValue)
			{
				return true;
			}
			PlacementController instance = PlacementController.Instance;
			if ((Object)(object)instance == (Object)null || !instance.IsArmed)
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)__instance != (Object)(object)localPlayer || __0 == null || __0 != ((Humanoid)localPlayer).GetInventory() || __1 == null || !__0.ContainsItem(__1) || __1.m_shared.m_questItem || __2 <= 0)
			{
				return true;
			}
			int amount = Math.Min(__2, __1.m_stack);
			instance.Begin(__0, __1, amount);
			InventoryGui instance2 = InventoryGui.instance;
			if ((Object)(object)instance2 != (Object)null)
			{
				SetupDragItem.Invoke(instance2, new object[3] { null, null, 1 });
				instance2.Hide();
			}
			__result = false;
			return false;
		}

		private static void Postfix(bool __result)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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)
			if (!__result || !PlacementController.PendingTarget.HasValue)
			{
				return;
			}
			ItemDrop lastSpawned = PlacementController.LastSpawned;
			if (!((Object)(object)lastSpawned == (Object)null))
			{
				Vector3 value = PlacementController.PendingTarget.Value;
				Quaternion pendingRotation = PlacementController.PendingRotation;
				((Component)lastSpawned).transform.SetPositionAndRotation(value, pendingRotation);
				Rigidbody val = default(Rigidbody);
				if (((Component)lastSpawned).TryGetComponent<Rigidbody>(ref val))
				{
					val.position = value;
					val.rotation = pendingRotation;
					val.linearVelocity = Vector3.zero;
					val.angularVelocity = Vector3.zero;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ItemDrop), "DropItem", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(Vector3),
		typeof(Quaternion)
	})]
	internal static class ItemDrop_DropItem_Patch
	{
		private static void Postfix(ItemDrop __result)
		{
			if (PlacementController.PendingTarget.HasValue)
			{
				PlacementController.LastSpawned = __result;
			}
		}
	}
	[HarmonyPatch(typeof(ZInput), "GetMouseScrollWheel")]
	internal static class ZInput_GetMouseScrollWheel_Patch
	{
		private static void Postfix(ref float __result)
		{
			if (PlacementController.IsPlacing && !PlacementController.ReadingScroll)
			{
				__result = 0f;
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "StartAttack")]
	internal static class Humanoid_StartAttack_Patch
	{
		private static bool Prefix(Humanoid __instance, ref bool __result)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (!PlacementController.IsPlacing && Time.frameCount > PlacementController.SuppressAttackUntilFrame)
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	public class PlacementController : MonoBehaviour
	{
		internal static Vector3? PendingTarget;

		internal static Quaternion PendingRotation = Quaternion.identity;

		internal static ItemDrop LastSpawned;

		internal static int SuppressAttackUntilFrame;

		internal static bool ReadingScroll;

		private static readonly MethodInfo PieceRayTestMethod = AccessTools.Method(typeof(Player), "PieceRayTest", (Type[])null, (Type[])null);

		private static readonly FieldInfo PlaceRotationDegreesField = AccessTools.Field(typeof(Player), "m_placeRotationDegrees");

		private static readonly FieldInfo ScrollThresholdField = AccessTools.Field(typeof(Player), "m_scrollAmountThreshold");

		private static readonly FieldInfo PlaceMarkerField = AccessTools.Field(typeof(Player), "m_placeMarker");

		private static readonly FieldInfo MaxPlaceDistanceField = AccessTools.Field(typeof(Player), "m_maxPlaceDistance");

		private static bool _useGameRayTest = true;

		private bool _active;

		private int _startFrame;

		private Inventory _inventory;

		private ItemData _item;

		private int _amount;

		private string _flashText;

		private float _flashUntil;

		private string _itemLabel = "";

		private GUIStyle _indicatorStyle;

		private GameObject _ghost;

		private GameObject _marker;

		private bool _hasValidSpot;

		private Vector3 _hitPoint;

		private Vector3 _normal;

		private Vector3 _spot;

		private float _baseYaw;

		private int _rotationSteps;

		private float _stepDegrees = 22.5f;

		private float _scrollThreshold;

		private float _scrollAccum;

		private float _rotateTimer;

		private static int _fallbackRayMask;

		private const float RecordTimeout = 10f;

		private bool _recording;

		private bool _waitingForRelease;

		private float _recordStart;

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

		private static readonly Color Gold = new Color(1f, 0.82f, 0.4f);

		private static readonly Color Dim = new Color(0.75f, 0.72f, 0.66f, 0.85f);

		private static readonly Color Attention = new Color(1f, 0.55f, 0.25f);

		private static readonly Color Info = new Color(1f, 0.95f, 0.85f);

		public static PlacementController Instance { get; private set; }

		public static bool IsPlacing
		{
			get
			{
				if ((Object)(object)Instance != (Object)null)
				{
					return Instance._active;
				}
				return false;
			}
		}

		public bool IsArmed { get; private set; }

		private Quaternion CurrentRotation => Quaternion.Euler(0f, _baseYaw + (float)_rotationSteps * _stepDegrees, 0f);

		private void Awake()
		{
			Instance = this;
			_fallbackRayMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "terrain", "vehicle" });
		}

		private void Update()
		{
			Plugin.UpdateControllerCombo();
			if (Plugin.RecordPlaceButton.Value)
			{
				if (_active)
				{
					End();
				}
				UpdateRecording();
			}
			else
			{
				_recording = false;
				if (_active)
				{
					UpdatePlacing();
				}
				else
				{
					UpdateArming();
				}
			}
		}

		private void UpdateRecording()
		{
			if (!_recording)
			{
				_recording = true;
				_waitingForRelease = true;
				_recorded.Clear();
				_recordStart = Time.unscaledTime;
			}
			if (ZInput.GetKeyDown((KeyCode)27, true) || Time.unscaledTime - _recordStart > 10f)
			{
				FinishRecording(null);
				return;
			}
			bool flag = false;
			string[] controllerButtons = Plugin.ControllerButtons;
			foreach (string text in controllerButtons)
			{
				if (ZInput.GetButton(text))
				{
					flag = true;
					if (!_waitingForRelease && _recorded.Count < 3)
					{
						_recorded.Add(text);
					}
				}
			}
			if (_waitingForRelease)
			{
				if (!flag)
				{
					_waitingForRelease = false;
				}
			}
			else if (!flag && _recorded.Count > 0)
			{
				FinishRecording(Plugin.FormatCombo(_recorded));
			}
		}

		private void FinishRecording(string combo)
		{
			_recording = false;
			if (combo != null)
			{
				Plugin.PlaceButton.Value = combo;
			}
			Plugin.RecordPlaceButton.Value = false;
			string text = ((combo != null) ? ("Place button set to " + combo) : "Recording cancelled");
			Plugin.Log.LogInfo((object)text);
			_flashText = "Precision Drop: " + text;
			_flashUntil = Time.unscaledTime + 4f;
		}

		private string RecordingText()
		{
			if (_waitingForRelease)
			{
				return "Precision Drop: let go of all controller buttons...";
			}
			int num = Mathf.CeilToInt(10f - (Time.unscaledTime - _recordStart));
			string arg = ((_recorded.Count > 0) ? (" (" + Plugin.FormatCombo(_recorded) + ")") : "");
			return $"Precision Drop: press and hold your button or combination, then let go{arg}  [{num}s, Esc cancels]";
		}

		private void UpdateArming()
		{
			if (InventoryGui.IsVisible() && Plugin.HasAnyPlaceBinding && Plugin.PlacePressed())
			{
				SetArmed(!IsArmed);
			}
		}

		private void SetArmed(bool armed)
		{
			IsArmed = armed;
		}

		public void Begin(Inventory inventory, ItemData item, int amount)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			End();
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				_inventory = inventory;
				_item = item;
				_amount = amount;
				_ghost = GhostBuilder.Build(item.m_dropPrefab);
				_ghost.SetActive(false);
				object? obj = PlaceMarkerField?.GetValue(localPlayer);
				GameObject val = (GameObject)((obj is GameObject) ? obj : null);
				if (val != null)
				{
					_marker = Object.Instantiate<GameObject>(val);
					_marker.SetActive(false);
				}
				_baseYaw = ((Component)localPlayer).transform.eulerAngles.y;
				_rotationSteps = 0;
				_stepDegrees = ((PlaceRotationDegreesField?.GetValue(localPlayer) is float num && num > 0f) ? num : 22.5f);
				_scrollThreshold = ((ScrollThresholdField?.GetValue(localPlayer) is float num2) ? num2 : 0f);
				_scrollAccum = 0f;
				_rotateTimer = 0f;
				_startFrame = Time.frameCount;
				_active = true;
				_itemLabel = $"{Localization.instance.Localize(item.m_shared.m_name)} x{amount}";
				((Character)localPlayer).Message((MessageType)1, "Placing " + _itemLabel + ". Use your build controls to place and rotate. Remove cancels.", 0, (Sprite)null, false);
			}
		}

		private void UpdatePlacing()
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			bool flag = Time.frameCount <= _startFrame + 5;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || _inventory == null || !_inventory.ContainsItem(_item) || Menu.IsVisible() || Minimap.IsOpen() || (!flag && InventoryGui.IsVisible()))
			{
				End();
				return;
			}
			UpdateSpot(localPlayer);
			if (!flag)
			{
				UpdateRotation(Time.deltaTime);
			}
			Quaternion currentRotation = CurrentRotation;
			_ghost.SetActive(_hasValidSpot);
			if (_hasValidSpot)
			{
				_ghost.transform.SetPositionAndRotation(_spot, currentRotation);
			}
			if ((Object)(object)_marker != (Object)null)
			{
				_marker.SetActive(_hasValidSpot);
				if (_hasValidSpot)
				{
					_marker.transform.SetPositionAndRotation(_hitPoint, Quaternion.LookRotation(_normal, currentRotation * Vector3.forward));
				}
			}
			if (!flag)
			{
				if (CancelPressed())
				{
					End();
				}
				else if (_hasValidSpot && ConfirmPressed())
				{
					Confirm(localPlayer);
				}
			}
		}

		private void UpdateRotation(float dt)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Invalid comparison between Unknown and I4
			ReadingScroll = true;
			float mouseScrollWheel;
			try
			{
				mouseScrollWheel = ZInput.GetMouseScrollWheel();
			}
			finally
			{
				ReadingScroll = false;
			}
			_scrollAccum += mouseScrollWheel;
			if (_scrollAccum > _scrollThreshold)
			{
				_scrollAccum = 0f;
				_rotationSteps++;
			}
			if (_scrollAccum < 0f - _scrollThreshold)
			{
				_scrollAccum = 0f;
				_rotationSteps--;
			}
			float num = 0f;
			bool flag = false;
			if (ZInput.IsGamepadActive())
			{
				InputLayout inputLayout = ZInput.InputLayout;
				if ((int)inputLayout != 0)
				{
					if (inputLayout - 1 <= 1)
					{
						bool button = ZInput.GetButton("JoyRotate");
						bool button2 = ZInput.GetButton("JoyRotateRight");
						flag = button || button2;
						if (button)
						{
							num = 0.5f;
						}
						else if (button2)
						{
							num = -0.5f;
						}
					}
				}
				else
				{
					num = ZInput.GetJoyRightStickX();
					flag = ZInput.GetButton("JoyRotate") && Mathf.Abs(num) > 0.5f;
				}
			}
			if (flag)
			{
				if (_rotateTimer == 0f)
				{
					_rotationSteps += ((num < 0f) ? 1 : (-1));
				}
				else if (_rotateTimer > 0.25f)
				{
					_rotationSteps += ((num < 0f) ? 1 : (-1));
					_rotateTimer = 0.17f;
				}
				_rotateTimer += dt;
			}
			else
			{
				_rotateTimer = 0f;
			}
		}

		private void UpdateSpot(Player player)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			_hasValidSpot = false;
			if (_useGameRayTest && PieceRayTestMethod != null)
			{
				object[] array = new object[6] { null, null, null, null, null, false };
				try
				{
					if ((bool)PieceRayTestMethod.Invoke(player, array))
					{
						_hitPoint = (Vector3)array[0];
						_normal = (Vector3)array[1];
						_spot = _hitPoint + _normal * 0.15f;
						_hasValidSpot = true;
					}
					return;
				}
				catch (Exception ex)
				{
					_useGameRayTest = false;
					Plugin.Log.LogWarning((object)("Couldn't use the game's build aiming, falling back to our own: " + ex.GetBaseException().Message));
				}
			}
			if (!((Object)(object)GameCamera.instance == (Object)null))
			{
				Transform transform = ((Component)GameCamera.instance).transform;
				float num = ((MaxPlaceDistanceField?.GetValue(player) is float num2 && num2 > 0f) ? num2 : 8f);
				float num3 = num + Vector3.Distance(transform.position, ((Component)player).transform.position);
				RaycastHit val = default(RaycastHit);
				if (Physics.Raycast(transform.position, transform.forward, ref val, num3, _fallbackRayMask) && Vector3.Distance(((RaycastHit)(ref val)).point, ((Component)player).transform.position) <= num)
				{
					_hitPoint = ((RaycastHit)(ref val)).point;
					_normal = ((RaycastHit)(ref val)).normal;
					_spot = ((RaycastHit)(ref val)).point + ((RaycastHit)(ref val)).normal * 0.15f;
					_hasValidSpot = true;
				}
			}
		}

		private bool TryGetIndicator(out string text, out Color color)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
			text = null;
			color = Gold;
			if (_recording && Plugin.RecordPlaceButton.Value)
			{
				text = RecordingText();
				return true;
			}
			if (Menu.IsVisible())
			{
				return false;
			}
			if (_flashText != null && Time.unscaledTime < _flashUntil)
			{
				text = _flashText;
				color = Info;
				return true;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null || !Plugin.ShowIndicator.Value)
			{
				return false;
			}
			bool flag = InventoryGui.IsVisible();
			if (!Plugin.HasAnyPlaceBinding)
			{
				if (!flag)
				{
					return false;
				}
				text = "Precision Drop: set a place key or button in F1 to use it";
				color = Attention;
				return true;
			}
			if (PrecisionDropAPI.IsBuiltInIndicatorHidden)
			{
				return false;
			}
			if (_active)
			{
				text = "Precision Drop: placing " + _itemLabel;
				return true;
			}
			if (IsArmed)
			{
				text = "Precision Drop: ON";
				return true;
			}
			if (flag)
			{
				text = "Precision Drop: OFF";
				color = Dim;
				return true;
			}
			return false;
		}

		private void OnGUI()
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_0025: 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)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			if (TryGetIndicator(out var text, out var color))
			{
				if (_indicatorStyle == null)
				{
					_indicatorStyle = new GUIStyle(GUI.skin.label)
					{
						alignment = (TextAnchor)4,
						fontStyle = (FontStyle)1,
						wordWrap = false
					};
				}
				float num = (float)Screen.height / 1080f;
				_indicatorStyle.fontSize = Mathf.Max(8, Mathf.RoundToInt((float)Plugin.IndicatorSize.Value * num));
				DrawLabel(text, Plugin.IndicatorY.Value * (float)Screen.height, color, color.a, num);
			}
		}

		private float DrawLabel(string text, float centerY, Color color, float alpha, float scale)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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)
			//IL_00db: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: 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_0111: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = _indicatorStyle.CalcSize(new GUIContent(text));
			float num = Mathf.Clamp(Plugin.IndicatorX.Value * (float)Screen.width - val.x / 2f, 0f, (float)Screen.width - val.x);
			float num2 = Mathf.Clamp(centerY - val.y / 2f, 0f, (float)Screen.height - val.y);
			_indicatorStyle.normal.textColor = new Color(0f, 0f, 0f, 0.8f * alpha);
			GUI.Label(new Rect(num + 2f * scale, num2 + 2f * scale, val.x, val.y), text, _indicatorStyle);
			_indicatorStyle.normal.textColor = new Color(color.r, color.g, color.b, alpha);
			GUI.Label(new Rect(num, num2, val.x, val.y), text, _indicatorStyle);
			return val.y;
		}

		private static bool ConfirmPressed()
		{
			if ((!ZInput.GetButtonDown("Attack") && !ZInput.GetButtonDown("JoyPlace")) || Hud.InRadial())
			{
				return Plugin.PlacePressed();
			}
			return true;
		}

		private static bool CancelPressed()
		{
			if (!ZInput.GetButtonDown("Remove") && !ZInput.GetButtonDown("JoyRemove"))
			{
				return ZInput.GetKeyDown((KeyCode)27, true);
			}
			return true;
		}

		private void Confirm(Player player)
		{
			//IL_0016: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			Inventory inventory = _inventory;
			ItemData item = _item;
			int amount = _amount;
			Vector3 spot = _spot;
			Quaternion currentRotation = CurrentRotation;
			End();
			SuppressAttackUntilFrame = Time.frameCount + 1;
			PendingTarget = spot;
			PendingRotation = currentRotation;
			try
			{
				((Humanoid)player).DropItem(inventory, item, amount);
			}
			finally
			{
				PendingTarget = null;
				LastSpawned = null;
			}
		}

		public void End()
		{
			_active = false;
			_inventory = null;
			_item = null;
			if ((Object)(object)_ghost != (Object)null)
			{
				Object.Destroy((Object)(object)_ghost);
			}
			if ((Object)(object)_marker != (Object)null)
			{
				Object.Destroy((Object)(object)_marker);
			}
			_ghost = null;
			_marker = null;
		}
	}
	[BepInPlugin("th3cap3.valheim.capesprecisiondrop", "Capes Precision Drop", "1.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "th3cap3.valheim.capesprecisiondrop";

		public const string PluginName = "Capes Precision Drop";

		public const string PluginVersion = "1.0.1";

		internal static readonly string[] ControllerButtons = new string[16]
		{
			"JoyLTrigger", "JoyRTrigger", "JoyLBumper", "JoyRBumper", "JoyButtonA", "JoyButtonB", "JoyButtonX", "JoyButtonY", "JoyDPadUp", "JoyDPadDown",
			"JoyDPadLeft", "JoyDPadRight", "JoyLStick", "JoyRStick", "JoyBack", "JoyStart"
		};

		internal static ConfigEntry<KeyboardShortcut> PlaceKey;

		internal static ConfigEntry<string> PlaceButton;

		internal static ConfigEntry<bool> RecordPlaceButton;

		internal static ConfigEntry<bool> ShowIndicator;

		internal static ConfigEntry<float> IndicatorX;

		internal static ConfigEntry<float> IndicatorY;

		internal static ConfigEntry<int> IndicatorSize;

		internal static ManualLogSource Log;

		private static string _parsedFrom;

		private static string[] _combo = new string[0];

		private static bool _comboWasHeld;

		private static bool _comboDownThisFrame;

		private Harmony _harmony;

		internal static bool HasAnyPlaceBinding
		{
			get
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				KeyboardShortcut value = PlaceKey.Value;
				if ((int)((KeyboardShortcut)(ref value)).MainKey == 0)
				{
					return ControllerCombo.Length != 0;
				}
				return true;
			}
		}

		internal static string[] ControllerCombo
		{
			get
			{
				string text = PlaceButton.Value ?? "";
				if (text != _parsedFrom)
				{
					_parsedFrom = text;
					_combo = ParseCombo(text);
				}
				return _combo;
			}
		}

		internal static string[] ParseCombo(string raw)
		{
			List<string> list = new List<string>();
			string[] array = raw.Split(new char[1] { '+' });
			foreach (string text in array)
			{
				string name = text.Trim();
				if (name.Length != 0 && !name.Equals("None", StringComparison.OrdinalIgnoreCase))
				{
					string text2 = ControllerButtons.FirstOrDefault((string b) => b.Equals(name, StringComparison.OrdinalIgnoreCase));
					if (text2 == null)
					{
						Log.LogWarning((object)("Unknown controller button '" + name + "' in PlaceButton. Valid names: " + string.Join(", ", ControllerButtons)));
					}
					else if (!list.Contains(text2))
					{
						list.Add(text2);
					}
				}
			}
			return list.ToArray();
		}

		internal static string FormatCombo(IEnumerable<string> buttons)
		{
			return string.Join(" + ", ControllerButtons.Where((string b) => buttons.Contains(b)));
		}

		internal static void UpdateControllerCombo()
		{
			string[] controllerCombo = ControllerCombo;
			int num;
			int comboDownThisFrame;
			if (controllerCombo.Length != 0)
			{
				num = (((IEnumerable<string>)controllerCombo).All((Func<string, bool>)ZInput.GetButton) ? 1 : 0);
				if (num != 0)
				{
					comboDownThisFrame = ((!_comboWasHeld) ? 1 : 0);
					goto IL_003c;
				}
			}
			else
			{
				num = 0;
			}
			comboDownThisFrame = 0;
			goto IL_003c;
			IL_003c:
			_comboDownThisFrame = (byte)comboDownThisFrame != 0;
			_comboWasHeld = (byte)num != 0;
		}

		internal static bool PlacePressed()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = PlaceKey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey != 0 && ZInput.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey, true) && ((KeyboardShortcut)(ref value)).Modifiers.All((KeyCode key) => ZInput.GetKey(key, true)))
			{
				return true;
			}
			return _comboDownThisFrame;
		}

		private void Awake()
		{
			//IL_001b: 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)
			//IL_00df: Expected O, but got Unknown
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Expected O, but got Unknown
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			PlaceKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keyboard", "PlaceKey", KeyboardShortcut.Empty, "With the inventory open, press to toggle place mode. While it's on, every drop is placed instead of tossed, until you press it again. While placing, your normal build controls place, rotate, and cancel (Remove).");
			PlaceButton = ((BaseUnityPlugin)this).Config.Bind<string>("Controller", "PlaceButton", "", "Controller button or combination that does the same as PlaceKey. Easiest to set with RecordPlaceButton. Can also be typed, for example: JoyLBumper + JoyButtonY. A combination avoids clashing with the buttons' normal actions. Valid names: " + string.Join(", ", ControllerButtons));
			RecordPlaceButton = ((BaseUnityPlugin)this).Config.Bind<bool>("Controller", "RecordPlaceButton", false, "Tick this, then press and hold your button or combination on the controller and let go. It's saved to PlaceButton and this unticks itself. Esc or waiting 10 seconds cancels.");
			ShowIndicator = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowIndicator", true, "Show a small on-screen label while place mode is on, so you always know whether your next drop will be placed or tossed.");
			IndicatorX = ((BaseUnityPlugin)this).Config.Bind<float>("General", "IndicatorX", 0.5f, new ConfigDescription("Horizontal position of the indicator: 0 = left edge, 0.5 = center, 1 = right edge.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			IndicatorY = ((BaseUnityPlugin)this).Config.Bind<float>("General", "IndicatorY", 0.07f, new ConfigDescription("Vertical position of the indicator: 0 = top edge, 0.5 = middle, 1 = bottom edge.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			IndicatorSize = ((BaseUnityPlugin)this).Config.Bind<int>("General", "IndicatorSize", 20, new ConfigDescription("Text size of the indicator (at 1080p; it scales with your resolution).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 48), Array.Empty<object>()));
			RecordPlaceButton.Value = false;
			((Component)this).gameObject.AddComponent<PlacementController>();
			_harmony = new Harmony("th3cap3.valheim.capesprecisiondrop");
			_harmony.PatchAll();
			Log.LogInfo((object)"Capes Precision Drop 1.0.1 loaded");
			if (!HasAnyPlaceBinding)
			{
				Log.LogWarning((object)"No place key or button is bound. Set one in the F1 menu or the config file to use the mod.");
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	public static class PrecisionDropAPI
	{
		public const string PluginGuid = "th3cap3.valheim.capesprecisiondrop";

		private static readonly HashSet<string> HideRequests = new HashSet<string>();

		public static bool IsPlaceModeOn
		{
			get
			{
				if ((Object)(object)PlacementController.Instance != (Object)null)
				{
					return PlacementController.Instance.IsArmed;
				}
				return false;
			}
		}

		public static bool IsPlacing => PlacementController.IsPlacing;

		public static bool IsBuiltInIndicatorHidden => HideRequests.Count > 0;

		public static void HideBuiltInIndicator(string requesterGuid)
		{
			if (!string.IsNullOrEmpty(requesterGuid) && HideRequests.Add(requesterGuid))
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("Built-in indicator hidden at the request of " + requesterGuid));
				}
			}
		}

		public static void ShowBuiltInIndicator(string requesterGuid)
		{
			if (!string.IsNullOrEmpty(requesterGuid) && HideRequests.Remove(requesterGuid))
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)(requesterGuid + " no longer hides the built-in indicator"));
				}
			}
		}
	}
}