Decompiled source of FlipIt v0.3.7

FlipIt.dll

Decompiled 12 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
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 UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("FlipIt")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Shift + scroll to tilt hammer placement pieces on the horizontal axis.")]
[assembly: AssemblyFileVersion("0.3.3.0")]
[assembly: AssemblyInformationalVersion("0.3.3+889b28dd83d35f0fe1c5ba4de79c6e36d8725391")]
[assembly: AssemblyProduct("FlipIt")]
[assembly: AssemblyTitle("FlipIt")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.3.3.0")]
[module: UnverifiableCode]
[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 FlipIt
{
	[BepInPlugin("hardwire99.flipit", "Flip It", "0.3.7")]
	public sealed class FlipItPlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			if (!ModConfig.Enabled.Value)
			{
				Log.LogInfo((object)"Flip It 0.3.7 is disabled in config.");
				return;
			}
			harmony = new Harmony("hardwire99.flipit");
			harmony.PatchAll(typeof(FlipItPlugin).Assembly);
			Log.LogInfo((object)("Flip It 0.3.7 loaded (reset-key-j, dll " + GetDllTimestamp() + ")."));
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		private static string GetDllTimestamp()
		{
			string location = Assembly.GetExecutingAssembly().Location;
			if (!File.Exists(location))
			{
				return "unknown";
			}
			return File.GetLastWriteTime(location).ToString("yyyy-MM-dd HH:mm:ss");
		}
	}
	internal static class ModConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> DebugLogging;

		internal static ConfigEntry<float> RotationStepDegrees;

		internal static ConfigEntry<bool> MatchVanillaYawStep;

		internal static ConfigEntry<bool> AllowAnySurface;

		internal static ConfigEntry<bool> AlignToSurface;

		internal static ConfigEntry<bool> SuppressSnapWhileRotating;

		internal static ConfigEntry<KeyCode> ResetRotationKey;

		internal static void Bind(ConfigFile config)
		{
			Enabled = config.Bind<bool>("General", "Enabled", true, "Enable free placement rotation while building.");
			DebugLogging = config.Bind<bool>("General", "DebugLogging", false, "Log rotation changes to BepInEx.");
			RotationStepDegrees = config.Bind<float>("Placement", "RotationStepDegrees", 22.5f, "Degrees per Shift/Ctrl+scroll step on pitch and roll. Used when MatchVanillaYawStep is false (for example, set to 90 for quarter-turn steps).");
			MatchVanillaYawStep = config.Bind<bool>("Placement", "MatchVanillaYawStep", true, "Use the game's native rotation step (22.5 by default) for Shift/Ctrl+scroll. Set false to use RotationStepDegrees instead.");
			AllowAnySurface = config.Bind<bool>("Placement", "AllowAnySurface", true, "Allow placing on walls, ceilings, slopes, and other surfaces vanilla would reject.");
			AlignToSurface = config.Bind<bool>("Placement", "AlignToSurface", true, "Align the placement ghost to the surface you are aiming at.");
			SuppressSnapWhileRotating = config.Bind<bool>("Placement", "SuppressSnapWhileRotating", true, "While Shift or Ctrl is held, skip surface snap so rotation does not jump to a new attach point.");
			ResetRotationKey = config.Bind<KeyCode>("Controls", "ResetRotationKey", (KeyCode)106, "While placing, press this key to reset the current piece to vanilla upright orientation.");
		}

		internal static void LogRotation(Player player, PlacementAxis axis, float delta)
		{
			if (DebugLogging.Value)
			{
				float rotationStep = PlacementSurfaceHelper.GetRotationStep(player);
				string text = ((axis == PlacementAxis.X) ? "pitch (Shift+scroll)" : "roll (Ctrl+scroll)");
				FlipItPlugin.Log.LogInfo((object)string.Format("{0} {1}{2} deg -> pitch {3}, roll {4}", text, (delta > 0f) ? "+" : "-", rotationStep, PlacementRotationState.GetPitchDegrees(player), PlacementRotationState.GetRollDegrees(player)));
			}
		}
	}
	internal static class ModConstants
	{
		public const string ModGuid = "hardwire99.flipit";

		public const string ModName = "Flip It";

		public const string ModVersion = "0.3.7";

		public const string BuildLabel = "reset-key-j";
	}
	internal struct PiecePlacementFlagsBackup
	{
		internal bool HasBackup;

		internal bool GroundOnly;

		internal bool GroundPiece;

		internal bool CultivatedGroundOnly;

		internal bool VegetationGroundOnly;

		internal bool NotOnFloor;

		internal bool InCeilingOnly;

		internal bool NotOnTiltingSurface;
	}
	internal static class PiecePlacementFlags
	{
		internal static PiecePlacementFlagsBackup Relax(Player player, Piece piece)
		{
			PiecePlacementFlagsBackup result = default(PiecePlacementFlagsBackup);
			if ((Object)(object)piece == (Object)null || !ModConfig.AllowAnySurface.Value || !PlacementRotationState.HasExtraRotation(player))
			{
				return result;
			}
			result.HasBackup = true;
			result.GroundOnly = piece.m_groundOnly;
			result.GroundPiece = piece.m_groundPiece;
			result.CultivatedGroundOnly = piece.m_cultivatedGroundOnly;
			result.VegetationGroundOnly = piece.m_vegetationGroundOnly;
			result.NotOnFloor = piece.m_notOnFloor;
			result.InCeilingOnly = piece.m_inCeilingOnly;
			result.NotOnTiltingSurface = piece.m_notOnTiltingSurface;
			piece.m_groundOnly = false;
			piece.m_groundPiece = false;
			piece.m_cultivatedGroundOnly = false;
			piece.m_vegetationGroundOnly = false;
			piece.m_notOnFloor = false;
			piece.m_inCeilingOnly = false;
			piece.m_notOnTiltingSurface = false;
			return result;
		}

		internal static void Restore(Piece piece, PiecePlacementFlagsBackup backup)
		{
			if (!((Object)(object)piece == (Object)null) && backup.HasBackup)
			{
				piece.m_groundOnly = backup.GroundOnly;
				piece.m_groundPiece = backup.GroundPiece;
				piece.m_cultivatedGroundOnly = backup.CultivatedGroundOnly;
				piece.m_vegetationGroundOnly = backup.VegetationGroundOnly;
				piece.m_notOnFloor = backup.NotOnFloor;
				piece.m_inCeilingOnly = backup.InCeilingOnly;
				piece.m_notOnTiltingSurface = backup.NotOnTiltingSurface;
			}
		}
	}
	internal static class PlacementCompatibility
	{
		private static readonly string[] SkippedPieceNameTokens = new string[6] { "prefab", "blueprint", "planbuild", "plan_", "_plan", "infinityhammer" };

		internal static bool ShouldSkipFlipIt(Player player, GameObject ghost)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)ghost == (Object)null)
			{
				return false;
			}
			if (HasSkippedComponent(ghost))
			{
				return true;
			}
			Piece component = ghost.GetComponent<Piece>();
			if ((Object)(object)component == (Object)null)
			{
				return CountChildPieces(ghost) > 1;
			}
			if (ContainsSkippedToken(component.m_name) || ContainsSkippedToken(((Object)ghost).name))
			{
				return true;
			}
			return CountChildPieces(ghost) > 1;
		}

		internal static void ClearRotationIfSkipped(Player player, GameObject ghost)
		{
			if (ShouldSkipFlipIt(player, ghost))
			{
				PlacementRotationState.Reset(player);
			}
		}

		private static bool HasSkippedComponent(GameObject ghost)
		{
			MonoBehaviour[] componentsInChildren = ghost.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					string text = ((object)val).GetType().FullName ?? string.Empty;
					if (text.IndexOf("PrefabHammer", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("PlanBuild", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Blueprint", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static int CountChildPieces(GameObject ghost)
		{
			return ghost.GetComponentsInChildren<Piece>(true).Length;
		}

		private static bool ContainsSkippedToken(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			string[] skippedPieceNameTokens = SkippedPieceNameTokens;
			foreach (string value2 in skippedPieceNameTokens)
			{
				if (value.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class PlacementFrameState
	{
		internal static int SavedPlaceRotation;

		internal static bool ShiftActive;

		internal static bool CtrlActive;

		internal static bool ModifierActive
		{
			get
			{
				if (!ShiftActive)
				{
					return CtrlActive;
				}
				return true;
			}
		}

		internal static void BeginFrame(int placeRotation, bool shiftActive, bool ctrlActive)
		{
			SavedPlaceRotation = placeRotation;
			ShiftActive = shiftActive;
			CtrlActive = ctrlActive;
		}
	}
	internal static class PlacementInputHelper
	{
		internal static bool IsShiftHeld()
		{
			if (!ZInput.GetButton("AltPlace") && !ZInput.GetButton("LShift") && !ZInput.GetKey((KeyCode)304, true))
			{
				return ZInput.GetKey((KeyCode)303, true);
			}
			return true;
		}

		internal static bool IsCtrlHeld()
		{
			if (!ZInput.GetKey((KeyCode)306, true))
			{
				return ZInput.GetKey((KeyCode)305, true);
			}
			return true;
		}

		internal static bool IsRotationModifierHeld()
		{
			if (!IsShiftHeld())
			{
				return IsCtrlHeld();
			}
			return true;
		}

		internal static bool TryResetRotation(Player player)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || !ModConfig.Enabled.Value || !((Character)player).InPlaceMode() || Hud.IsPieceSelectionVisible())
			{
				return false;
			}
			if (!Input.GetKeyDown(ModConfig.ResetRotationKey.Value))
			{
				return false;
			}
			PlacementResetHelper.ResetToVanilla(player);
			return true;
		}
	}
	internal static class PlacementPieceTracker
	{
		private static readonly Dictionary<long, int> LastPieceIdByPlayer = new Dictionary<long, int>();

		internal static void Clear(Player player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				LastPieceIdByPlayer.Remove(player.GetPlayerID());
			}
		}

		internal static void OnGhostSetup(Player player, GameObject ghost)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)ghost == (Object)null))
			{
				int pieceId = GetPieceId(ghost.GetComponent<Piece>());
				long playerID = player.GetPlayerID();
				if (!LastPieceIdByPlayer.TryGetValue(playerID, out var value) || value != pieceId)
				{
					LastPieceIdByPlayer[playerID] = pieceId;
					PlacementResetHelper.ResetToVanilla(player);
				}
			}
		}

		private static int GetPieceId(Piece piece)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return 0;
			}
			if (!string.IsNullOrEmpty(piece.m_name))
			{
				return piece.m_name.GetHashCode();
			}
			return ((Object)piece).name.GetHashCode();
		}
	}
	internal static class PlacementResetHelper
	{
		internal static void ResetToVanilla(Player player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				PlacementRotationState.Reset(player);
				Traverse.Create((object)player).Field("m_placeRotation").SetValue((object)0);
			}
		}
	}
	internal static class PlacementRotation
	{
		internal static Quaternion GetGhostRotation(Player player)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			Traverse obj = Traverse.Create((object)player);
			float value = obj.Field("m_placeRotationDegrees").GetValue<float>();
			int value2 = obj.Field("m_placeRotation").GetValue<int>();
			float num = value * (float)value2;
			object value3 = obj.Field("m_placementGhost").GetValue();
			GameObject val = (GameObject)((value3 is GameObject) ? value3 : null);
			if (PlacementCompatibility.ShouldSkipFlipIt(player, val))
			{
				PlacementCompatibility.ClearRotationIfSkipped(player, val);
				return Quaternion.Euler(0f, num, 0f);
			}
			if (!ModConfig.Enabled.Value || !PlacementRotationState.HasExtraRotation(player))
			{
				return Quaternion.Euler(0f, num, 0f);
			}
			if (ShouldUseFreeRotation(player))
			{
				return Quaternion.Euler(PlacementRotationState.GetPitchDegrees(player), num, PlacementRotationState.GetRollDegrees(player));
			}
			if ((Object)(object)val != (Object)null && PlacementSurfaceHelper.TryRayTest(player, val, out var _, out var normal))
			{
				return PlacementSurfaceHelper.BuildRotation(player, normal);
			}
			return Quaternion.Euler(PlacementRotationState.GetPitchDegrees(player), num, PlacementRotationState.GetRollDegrees(player));
		}

		private static bool ShouldUseFreeRotation(Player player)
		{
			if (ModConfig.SuppressSnapWhileRotating.Value)
			{
				if (!PlacementFrameState.ModifierActive)
				{
					return PlacementInputHelper.IsRotationModifierHeld();
				}
				return true;
			}
			return false;
		}
	}
	internal static class PlacementRotationState
	{
		private static readonly Dictionary<long, Vector2> ExtraEulerByPlayer = new Dictionary<long, Vector2>();

		internal static Vector2 GetExtraEuler(Player player)
		{
			//IL_0009: 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)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return Vector2.zero;
			}
			if (!ExtraEulerByPlayer.TryGetValue(player.GetPlayerID(), out var value))
			{
				return Vector2.zero;
			}
			return value;
		}

		internal static bool HasExtraRotation(Player player)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			Vector2 extraEuler = GetExtraEuler(player);
			if (Mathf.Approximately(extraEuler.x, 0f))
			{
				return !Mathf.Approximately(extraEuler.y, 0f);
			}
			return true;
		}

		internal static void Reset(Player player)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)player == (Object)null))
			{
				ExtraEulerByPlayer[player.GetPlayerID()] = Vector2.zero;
			}
		}

		internal static void AddAxisRotation(Player player, PlacementAxis axis, float delta)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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)
			if (!((Object)(object)player == (Object)null) && !Mathf.Approximately(delta, 0f))
			{
				float num = PlacementSurfaceHelper.GetRotationStep(player) * delta;
				Vector2 extraEuler = GetExtraEuler(player);
				switch (axis)
				{
				case PlacementAxis.X:
					extraEuler.x = NormalizeAngle(extraEuler.x + num);
					break;
				case PlacementAxis.Z:
					extraEuler.y = NormalizeAngle(extraEuler.y + num);
					break;
				}
				ExtraEulerByPlayer[player.GetPlayerID()] = extraEuler;
			}
		}

		internal static float GetPitchDegrees(Player player)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return GetExtraEuler(player).x;
		}

		internal static float GetRollDegrees(Player player)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return GetExtraEuler(player).y;
		}

		private static float NormalizeAngle(float angle)
		{
			angle %= 360f;
			if (angle < 0f)
			{
				angle += 360f;
			}
			return angle;
		}
	}
	internal enum PlacementAxis
	{
		None,
		X,
		Z
	}
	internal static class PlacementSurfaceHelper
	{
		private static readonly MethodInfo PieceRayTestMethod = AccessTools.Method(typeof(Player), "PieceRayTest", (Type[])null, (Type[])null);

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

		internal static bool TryRayTest(Player player, GameObject ghost, out Vector3 point, out Vector3 normal)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			point = Vector3.zero;
			normal = Vector3.up;
			if ((Object)(object)player == (Object)null || (Object)(object)ghost == (Object)null || PieceRayTestMethod == null)
			{
				return false;
			}
			Piece component = ghost.GetComponent<Piece>();
			bool flag = (Object)(object)component != (Object)null && (component.m_waterPiece || component.m_noInWater);
			object[] array = new object[6]
			{
				Vector3.zero,
				Vector3.up,
				null,
				null,
				null,
				flag
			};
			bool num = (bool)PieceRayTestMethod.Invoke(player, array);
			point = (Vector3)array[0];
			Vector3 val = (Vector3)array[1];
			normal = ((Vector3)(ref val)).normalized;
			if (num)
			{
				return ((Vector3)(ref normal)).sqrMagnitude > 0.001f;
			}
			return false;
		}

		internal static float GetRotationStep(Player player)
		{
			if (ModConfig.MatchVanillaYawStep.Value && (Object)(object)player != (Object)null)
			{
				return Traverse.Create((object)player).Field("m_placeRotationDegrees").GetValue<float>();
			}
			return ModConfig.RotationStepDegrees.Value;
		}

		internal static Quaternion BuildRotation(Player player, Vector3 surfaceNormal)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			Traverse obj = Traverse.Create((object)player);
			float value = obj.Field("m_placeRotationDegrees").GetValue<float>();
			int value2 = obj.Field("m_placeRotation").GetValue<int>();
			float num = value * (float)value2;
			float pitchDegrees = PlacementRotationState.GetPitchDegrees(player);
			float rollDegrees = PlacementRotationState.GetRollDegrees(player);
			Quaternion val = Quaternion.Euler(pitchDegrees, num, rollDegrees);
			if (!ModConfig.AlignToSurface.Value || !PlacementRotationState.HasExtraRotation(player) || ((Vector3)(ref surfaceNormal)).sqrMagnitude < 0.001f)
			{
				return val;
			}
			return Quaternion.FromToRotation(Vector3.up, surfaceNormal) * val;
		}

		internal static bool ShouldBypassPlacementStatus(PlacementStatus status)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			if (!ModConfig.AllowAnySurface.Value)
			{
				return false;
			}
			if ((int)status <= 5)
			{
				if ((int)status == 1 || (int)status == 5)
				{
					goto IL_0028;
				}
			}
			else if (status - 9 <= 1 || (int)status == 12)
			{
				goto IL_0028;
			}
			return false;
			IL_0028:
			return true;
		}

		internal static void ApplySurfacePlacement(Player player, GameObject ghost, ref PlacementStatus placementStatus)
		{
			//IL_005c: 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_0068: 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 (ModConfig.Enabled.Value && !((Object)(object)ghost == (Object)null) && ((Character)player).InPlaceMode() && PlacementRotationState.HasExtraRotation(player) && !ShouldSuppressSnap() && TryRayTest(player, ghost, out var point, out var normal) && ShouldBypassPlacementStatus(placementStatus))
			{
				Piece component = ghost.GetComponent<Piece>();
				ghost.SetActive(true);
				ghost.transform.rotation = BuildRotation(player, normal);
				SnapGhostToPoint(ghost, point, normal, component);
				placementStatus = (PlacementStatus)0;
				SetPlacementGhostValidMethod?.Invoke(player, new object[1] { true });
			}
		}

		internal static void SnapGhostToPoint(GameObject ghost, Vector3 point, Vector3 normal, Piece piece)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_002a: 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_0039: 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_00aa: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00da: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//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_0081: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			Collider[] componentsInChildren = ghost.GetComponentsInChildren<Collider>();
			if (componentsInChildren.Length == 0)
			{
				ghost.transform.position = point;
				return;
			}
			ghost.transform.position = point + normal * 50f;
			Vector3 val = Vector3.zero;
			float num = float.MaxValue;
			Collider[] array = componentsInChildren;
			foreach (Collider val2 in array)
			{
				if (val2.isTrigger || !val2.enabled)
				{
					continue;
				}
				MeshCollider val3 = (MeshCollider)(object)((val2 is MeshCollider) ? val2 : null);
				if (val3 == null || val3.convex)
				{
					Vector3 val4 = val2.ClosestPoint(point);
					float num2 = Vector3.Distance(val4, point);
					if (num2 < num)
					{
						val = val4;
						num = num2;
					}
				}
			}
			Vector3 val5 = ghost.transform.position - val;
			if ((Object)(object)piece != (Object)null && piece.m_waterPiece)
			{
				val5.y = 3f;
			}
			ghost.transform.position = point + val5;
		}

		private static bool ShouldSuppressSnap()
		{
			if (ModConfig.SuppressSnapWhileRotating.Value)
			{
				if (!PlacementFrameState.ModifierActive)
				{
					return PlacementInputHelper.IsRotationModifierHeld();
				}
				return true;
			}
			return false;
		}
	}
}
namespace FlipIt.Patches
{
	[HarmonyPatch(typeof(Player), "FindClosestSnappoint")]
	internal static class PlayerFindClosestSnappointPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ref bool __result)
		{
			if (!ModConfig.Enabled.Value || !ModConfig.SuppressSnapWhileRotating.Value || !PlacementRotationState.HasExtraRotation(Player.m_localPlayer))
			{
				return true;
			}
			if (!PlacementFrameState.ModifierActive && !PlacementInputHelper.IsRotationModifierHeld())
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "PlacePiece")]
	internal static class PlayerPlacePiecePatch
	{
		[HarmonyPostfix]
		private static void Postfix(Player __instance, GameObject ___m_placementGhost)
		{
			if (ModConfig.Enabled.Value && !((Object)(object)__instance == (Object)null) && PlacementCompatibility.ShouldSkipFlipIt(__instance, ___m_placementGhost))
			{
				PlacementRotationState.Reset(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "SetPlaceMode")]
	internal static class PlayerSetPlaceModePatch
	{
		[HarmonyPostfix]
		private static void Postfix(Player __instance)
		{
			PlacementPieceTracker.Clear(__instance);
			PlacementResetHelper.ResetToVanilla(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "SetupPlacementGhost")]
	internal static class PlayerSetupPlacementGhostPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Player __instance, GameObject ___m_placementGhost)
		{
			PlacementPieceTracker.OnGhostSetup(__instance, ___m_placementGhost);
		}
	}
	[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
	internal static class PlayerUpdatePlacementGhostPatch
	{
		private static readonly MethodInfo QuaternionEulerMethod = AccessTools.Method(typeof(Quaternion), "Euler", new Type[3]
		{
			typeof(float),
			typeof(float),
			typeof(float)
		}, (Type[])null);

		private static readonly MethodInfo GetGhostRotationMethod = AccessTools.Method(typeof(PlacementRotation), "GetGhostRotation", (Type[])null, (Type[])null);

		[HarmonyPrefix]
		private static void Prefix(Player __instance, GameObject ___m_placementGhost, ref PiecePlacementFlagsBackup __state)
		{
			if (!((Object)(object)___m_placementGhost == (Object)null))
			{
				PlacementCompatibility.ClearRotationIfSkipped(__instance, ___m_placementGhost);
				if (!PlacementCompatibility.ShouldSkipFlipIt(__instance, ___m_placementGhost))
				{
					__state = PiecePlacementFlags.Relax(__instance, ___m_placementGhost.GetComponent<Piece>());
				}
			}
		}

		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 0; i < list.Count; i++)
			{
				if (CodeInstructionExtensions.Calls(list[i], QuaternionEulerMethod))
				{
					list[i - 1] = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
					list[i] = new CodeInstruction(OpCodes.Call, (object)GetGhostRotationMethod);
					list.RemoveRange(i - 8, 7);
					break;
				}
			}
			return list;
		}

		[HarmonyPostfix]
		private static void Postfix(Player __instance, GameObject ___m_placementGhost, ref PlacementStatus ___m_placementStatus, PiecePlacementFlagsBackup __state)
		{
			PiecePlacementFlags.Restore(((Object)(object)___m_placementGhost != (Object)null) ? ___m_placementGhost.GetComponent<Piece>() : null, __state);
			if (ModConfig.Enabled.Value && ((Character)__instance).InPlaceMode() && !((Object)(object)___m_placementGhost == (Object)null) && !PlacementCompatibility.ShouldSkipFlipIt(__instance, ___m_placementGhost))
			{
				PlacementSurfaceHelper.ApplySurfacePlacement(__instance, ___m_placementGhost, ref ___m_placementStatus);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdatePlacement")]
	internal static class PlayerUpdatePlacementPatch
	{
		[HarmonyPrefix]
		private static void Prefix(Player __instance, ref int ___m_placeRotation)
		{
			bool flag = ModConfig.Enabled.Value && ((Character)__instance).InPlaceMode() && PlacementInputHelper.IsShiftHeld();
			bool ctrlActive = ModConfig.Enabled.Value && ((Character)__instance).InPlaceMode() && PlacementInputHelper.IsCtrlHeld() && !flag;
			PlacementFrameState.BeginFrame(___m_placeRotation, flag, ctrlActive);
		}

		[HarmonyPostfix]
		private static void Postfix(Player __instance, bool takeInput, ref int ___m_placeRotation, ref float ___m_scrollCurrAmount)
		{
			if (ModConfig.Enabled.Value && ((Character)__instance).InPlaceMode() && takeInput && !PlacementInputHelper.TryResetRotation(__instance) && !Hud.IsPieceSelectionVisible() && PlacementFrameState.ModifierActive)
			{
				PlacementAxis axis = (PlacementFrameState.ShiftActive ? PlacementAxis.X : PlacementAxis.Z);
				float axis2 = Input.GetAxis("Mouse ScrollWheel");
				int num = ___m_placeRotation - PlacementFrameState.SavedPlaceRotation;
				float num2 = 0f;
				if (!Mathf.Approximately(axis2, 0f))
				{
					num2 = ((axis2 > 0f) ? 1f : (-1f));
				}
				else if (num != 0)
				{
					num2 = ((num > 0) ? 1f : (-1f));
				}
				if (!Mathf.Approximately(num2, 0f))
				{
					PlacementRotationState.AddAxisRotation(__instance, axis, num2);
					ModConfig.LogRotation(__instance, axis, num2);
				}
				___m_placeRotation = PlacementFrameState.SavedPlaceRotation;
				___m_scrollCurrAmount = 0f;
			}
		}
	}
}