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 Enabled; internal static ConfigEntry DebugLogging; internal static ConfigEntry RotationStepDegrees; internal static ConfigEntry MatchVanillaYawStep; internal static ConfigEntry AllowAnySurface; internal static ConfigEntry AlignToSurface; internal static ConfigEntry SuppressSnapWhileRotating; internal static ConfigEntry ResetRotationKey; internal static void Bind(ConfigFile config) { Enabled = config.Bind("General", "Enabled", true, "Enable free placement rotation while building."); DebugLogging = config.Bind("General", "DebugLogging", false, "Log rotation changes to BepInEx."); RotationStepDegrees = config.Bind("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("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("Placement", "AllowAnySurface", true, "Allow placing on walls, ceilings, slopes, and other surfaces vanilla would reject."); AlignToSurface = config.Bind("Placement", "AlignToSurface", true, "Align the placement ghost to the surface you are aiming at."); SuppressSnapWhileRotating = config.Bind("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("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(); 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(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(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 LastPieceIdByPlayer = new Dictionary(); 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()); 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(); int value2 = obj.Field("m_placeRotation").GetValue(); 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 ExtraEulerByPlayer = new Dictionary(); 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(); 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(); } 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(); int value2 = obj.Field("m_placeRotation").GetValue(); 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(); 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(); 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()); } } } [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable 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 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() : 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; } } } }