using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Lamb.UI; using Lamb.UI.BuildMenu; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Better Build Backout")] [assembly: AssemblyProduct("Better Build Backout")] [assembly: ComVisible(false)] [assembly: Guid("ce3ea138-0f05-4b72-88a5-e0493434a508")] [assembly: AssemblyFileVersion("0.1.10.0")] [assembly: AssemblyVersion("0.1.10.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 BetterBuildBackout { [BepInPlugin("com.cotl.betterbuildertools.betterbuildbackout", "Better Build Backout", "0.1.11")] public sealed class BetterBuildBackoutPlugin : BaseUnityPlugin { public const string PluginGuid = "com.cotl.betterbuildertools.betterbuildbackout"; public const string PluginName = "Better Build Backout"; public const string PluginVersion = "0.1.11"; private Harmony _harmony; private bool _hasLastChosen; private float _lastReopenTime; private float _nextAutoCleanupCheck; private float _staleSince; private bool _sawBuildActivity; private bool _reconciledAfterBuild; private float _lastBuildActivityAt; private bool _preservingCameraForCatalogue; private float _suspendAutoCleanupUntil; private int _lastCancelFrame = -1; private KeyCode _reopenKey; private Interaction_PlacementRegion _lastBuilderInteraction; private static readonly MethodInfo OpenBuildMenuMethod = AccessTools.Method(typeof(Interaction_PlacementRegion), "OpenBuildMenu", (Type[])null, (Type[])null); private static readonly MethodInfo ClearPrefabsMethod = AccessTools.Method(typeof(PlacementRegion), "ClearPrefabs", (Type[])null, (Type[])null); private static readonly FieldInfo TilesField = AccessTools.Field(typeof(PlacementRegion), "Tiles"); private static readonly FieldInfo TilesInitiatedField = AccessTools.Field(typeof(PlacementRegion), "tilesInitiated"); private static readonly FieldInfo PlacementObjectField = AccessTools.Field(typeof(PlacementRegion), "placementObject"); private static readonly FieldInfo PlacementUiField = AccessTools.Field(typeof(PlacementRegion), "placementUI"); private static readonly FieldInfo IsEditingBuildingsField = AccessTools.Field(typeof(PlacementRegion), "isEditingBuildings"); internal static ManualLogSource Log { get; private set; } internal static BetterBuildBackoutPlugin Instance { get; private set; } private void Awake() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0043: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; BetterBuildBackoutConfig.Bind(((BaseUnityPlugin)this).Config); _reopenKey = ParseKey(BetterBuildBackoutConfig.ReopenKey.Value, (KeyCode)114); _harmony = new Harmony("com.cotl.betterbuildertools.betterbuildbackout"); _harmony.PatchAll(typeof(BetterBuildBackoutPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Better Build Backout 0.1.11 loaded."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; Instance = null; } internal void RememberChoice(TYPES structureType) { _hasLastChosen = true; } internal void RememberBuilderInteraction(Interaction_PlacementRegion interaction) { if ((Object)(object)interaction != (Object)null) { _lastBuilderInteraction = interaction; } } internal void QueueReopen() { if (BetterBuildBackoutConfig.Enabled.Value && _hasLastChosen && BetterBuildBackoutConfig.AutoReopenAfterPlacement.Value && !(Time.unscaledTime - _lastReopenTime < 0.25f)) { _lastReopenTime = Time.unscaledTime; ((MonoBehaviour)this).StartCoroutine(ReopenRoutine()); } } private void Update() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (BetterBuildBackoutConfig.Enabled.Value) { bool num = IsActiveBuildPlacement(); if (num) { _sawBuildActivity = true; _staleSince = 0f; } if (num && Input.GetKeyDown(_reopenKey)) { ((MonoBehaviour)this).StartCoroutine(ReopenRoutine()); } if (EditModeTogglePressed()) { _suspendAutoCleanupUntil = Time.unscaledTime + 2.5f; _staleSince = 0f; } if (BetterBuildBackoutConfig.AutoCleanup.Value) { CheckAutoCleanup(); } } } internal bool TryHandleCancelBackout() { if (!BetterBuildBackoutConfig.Enabled.Value || !BetterBuildBackoutConfig.CancelReopensBuildMenu.Value || !IsActiveBuildPlacement()) { return false; } if ((Object)(object)PlacementRegion.Instance != (Object)null && IsEditBuildingsMode(PlacementRegion.Instance)) { return false; } if (_lastCancelFrame == Time.frameCount) { return true; } _lastCancelFrame = Time.frameCount; ((MonoBehaviour)this).StartCoroutine(ReopenRoutine()); return true; } private IEnumerator ReopenRoutine() { if (!IsActiveBuildPlacement() || Time.unscaledTime - _lastReopenTime < 0.25f) { yield break; } _lastReopenTime = Time.unscaledTime; if (!CancelActivePlacementIfNeeded(BetterBuildBackoutConfig.PreserveCameraForCatalogue.Value)) { yield break; } _preservingCameraForCatalogue = BetterBuildBackoutConfig.PreserveCameraForCatalogue.Value; yield return (object)new WaitForSecondsRealtime(BetterBuildBackoutConfig.ReopenDelay.Value); if ((Object)(object)_lastBuilderInteraction != (Object)null && OpenBuildMenuMethod != null && OpenBuildMenuMethod.Invoke(_lastBuilderInteraction, null) is IEnumerator enumerator) { ((MonoBehaviour)_lastBuilderInteraction).StartCoroutine(enumerator); yield break; } Log.LogWarning((object)"Could not reopen through Interaction_PlacementRegion; falling back to UIManager."); if ((Object)(object)MonoSingleton.Instance != (Object)null && (Object)(object)MonoSingleton.Instance.BuildMenuTemplate != (Object)null) { Time.timeScale = 0f; MonoSingleton.Instance.ShowBuildMenu((TYPES)0); } } internal void MarkBuildMenuSelection() { _preservingCameraForCatalogue = false; } internal void HandleBuildMenuCancel() { if (_preservingCameraForCatalogue) { _preservingCameraForCatalogue = false; RestoreWorldState(resetCameraToPlayer: true); } } private static bool CancelActivePlacementIfNeeded(bool preserveCamera) { //IL_0010: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 PlacementRegion instance = PlacementRegion.Instance; if ((Object)(object)instance == (Object)null || (int)instance.CurrentMode == 0) { return true; } if ((int)instance.CurrentMode == 4 || (int)instance.CurrentMode == 2) { Log.LogWarning((object)"Backout ignored while moving/upgrading a structure to avoid losing that edit."); return false; } ((MonoBehaviour)instance).StopAllCoroutines(); GameObject val = (((Object)(object)PlacementObject.Instance != (Object)null) ? ((Component)PlacementObject.Instance).gameObject : null); try { DestroyPlacementTiles(instance); ClearPrefabsMethod?.Invoke(instance, null); DestroyPrivateObject(instance, PlacementObjectField); DestroyPrivateObject(instance, PlacementUiField); } catch (Exception ex) { Log.LogWarning((object)("Placement cleanup failed: " + ex.Message)); } instance.CurrentMode = (Mode)0; instance.PlacementPosition = Vector3.zero; TilesInitiatedField?.SetValue(instance, false); if ((Object)(object)DLCLandController.Instance != (Object)null) { DLCLandController.Instance.ShowBridge(); } if ((Object)(object)HUD_Manager.Instance != (Object)null) { HUD_Manager.Instance.Show(1, false); HUD_Manager.Instance.ShowEditMode(false); } if ((Object)(object)WeatherSystemController.Instance != (Object)null) { WeatherSystemController.Instance.ShowWeather(false, true); } if ((Object)(object)LightingManager.Instance != (Object)null) { LightingManager.Instance.inOverride = false; LightingManager.Instance.overrideSettings = null; LightingManager.Instance.transitionDurationMultiplier = 0.2f; LightingManager.Instance.lerpActive = false; LightingManager.Instance.UpdateLighting(true, false, false); LightingManager.Instance.PrepareLightingSettings(false); } if ((Object)(object)GameManager.GetInstance() != (Object)null) { if ((Object)(object)GameManager.GetInstance().CamFollowTarget != (Object)null) { ((Behaviour)GameManager.GetInstance().CamFollowTarget).enabled = !preserveCamera; } if ((Object)(object)val != (Object)null) { GameManager.GetInstance().RemoveFromCamera(val); } if (!preserveCamera) { GameManager.GetInstance().RemoveAllFromCamera(); GameManager.GetInstance().AddPlayerToCamera(); GameManager.GetInstance().CameraResetTargetZoom(); } } GameManager.overridePlayerPosition = false; Time.timeScale = 1f; return true; } private void CheckAutoCleanup() { if (Time.unscaledTime < _suspendAutoCleanupUntil) { _staleSince = 0f; } else { if (Time.unscaledTime < _nextAutoCleanupCheck) { return; } _nextAutoCleanupCheck = Time.unscaledTime + 0.25f; if (IsActiveBuildPlacement()) { _sawBuildActivity = true; _reconciledAfterBuild = false; _lastBuildActivityAt = Time.unscaledTime; _staleSince = 0f; return; } if (_sawBuildActivity && !_reconciledAfterBuild && !AnyMenuOpen() && Time.unscaledTime - _lastBuildActivityAt >= 0.4f) { int num = RepairOrphanBuildTiles(); _reconciledAfterBuild = true; if (num > 0) { Log.LogWarning((object)("Cleared " + num + " orphaned build-grid tile(s) after placement ended.")); } } if (!_sawBuildActivity || _preservingCameraForCatalogue || AnyMenuOpen() || !HasStaleBuildSymptoms()) { _staleSince = 0f; } else if (_staleSince <= 0f) { _staleSince = Time.unscaledTime; } else if (!(Time.unscaledTime - _staleSince < BetterBuildBackoutConfig.AutoCleanupDelay.Value)) { RecoverStaleBuildState(); _sawBuildActivity = false; _staleSince = 0f; Log.LogInfo((object)"Auto-cleaned stale build placement state."); } } } private static void RecoverStaleBuildState() { PlacementRegion[] array = PlacementRegion.PlacementRegions.ToArray(); for (int i = 0; i < array.Length; i++) { RecoverPlacementRegion(array[i]); } if ((Object)(object)PlacementObject.Instance != (Object)null) { Object.Destroy((Object)(object)((Component)PlacementObject.Instance).gameObject); } RestoreWorldState(resetCameraToPlayer: true); RestorePlayers(); } private static void RecoverPlacementRegion(PlacementRegion region) { //IL_0060: 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) if (!((Object)(object)region == (Object)null)) { ((MonoBehaviour)region).StopAllCoroutines(); try { DestroyPlacementTiles(region); DestroyPrivateObject(region, PlacementObjectField); DestroyPrivateObject(region, PlacementUiField); ClearPrefabsMethod?.Invoke(region, null); } catch (Exception ex) { Log.LogWarning((object)("Auto cleanup placement-region recovery failed: " + ex.Message)); } region.CurrentMode = (Mode)0; region.PlacementPosition = Vector3.zero; TilesInitiatedField?.SetValue(region, false); } } private static void RestoreWorldState(bool resetCameraToPlayer) { GameManager.overridePlayerPosition = false; Time.timeScale = 1f; if ((Object)(object)DLCLandController.Instance != (Object)null) { DLCLandController.Instance.ShowBridge(); } if ((Object)(object)HUD_Manager.Instance != (Object)null) { HUD_Manager.Instance.Show(1, false); HUD_Manager.Instance.ShowEditMode(false); } if ((Object)(object)WeatherSystemController.Instance != (Object)null) { WeatherSystemController.Instance.ShowWeather(false, true); } if ((Object)(object)LightingManager.Instance != (Object)null) { LightingManager.Instance.inOverride = false; LightingManager.Instance.overrideSettings = null; LightingManager.Instance.transitionDurationMultiplier = 0.2f; LightingManager.Instance.lerpActive = false; LightingManager.Instance.UpdateLighting(true, false, false); LightingManager.Instance.PrepareLightingSettings(false); } if ((Object)(object)GameManager.GetInstance() != (Object)null) { if ((Object)(object)GameManager.GetInstance().CamFollowTarget != (Object)null) { ((Behaviour)GameManager.GetInstance().CamFollowTarget).enabled = true; } if (resetCameraToPlayer) { GameManager.GetInstance().RemoveAllFromCamera(); GameManager.GetInstance().AddPlayerToCamera(); GameManager.GetInstance().CameraResetTargetZoom(); } } } private static void RestorePlayers() { foreach (PlayerFarming player in PlayerFarming.players) { if (!((Object)(object)player == (Object)null)) { ((Component)player).gameObject.SetActive(true); player.GoToAndStopping = false; if ((Object)(object)player.state != (Object)null) { player.state.CURRENT_STATE = (State)0; } if ((Object)(object)player.interactor != (Object)null) { player.interactor.CurrentInteraction = null; player.interactor.PreviousInteraction = null; } if ((Object)(object)player.indicator != (Object)null) { ((TMP_Text)player.indicator.text).text = ""; ((TMP_Text)player.indicator.SecondaryText).text = ""; ((TMP_Text)player.indicator.Thirdtext).text = ""; ((TMP_Text)player.indicator.Fourthtext).text = ""; player.indicator.Reset(); player.indicator.HideTopInfo(); } } } } private static int RepairOrphanBuildTiles() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Invalid comparison between Unknown and I4 //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) if ((int)PlayerFarming.Location != 1 || (Object)(object)PlacementRegion.Instance == (Object)null || PlacementRegion.Instance.Grid == null) { return 0; } HashSet hashSet = new HashSet(); Structure[] array = Structure.Structures.ToArray(); foreach (Structure val in array) { if ((Object)(object)val != (Object)null && val.Brain != null && val.Brain.Data != null && (int)val.Brain.Data.Location == 1) { hashSet.Add(val.Brain.Data.ID); } } int num = 0; foreach (TileGridTile item in PlacementRegion.Instance.Grid) { if (item != null && item.ObjectID >= 0 && !hashSet.Contains(item.ObjectID) && IsBuildSiteTile(item.ObjectOnTile)) { item.Occupied = false; item.Obstructed = false; item.ReservedForWaste = false; item.IsUpgrade = false; item.Collapsed = false; item.ObjectID = -1; item.ObjectOnTile = (TYPES)0; num++; } } return num; } private static bool IsBuildSiteTile(TYPES type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)type != 31) { return (int)type == 118; } return true; } private static void DestroyPlacementTiles(PlacementRegion region) { if (!(TilesField?.GetValue(region) is List list)) { return; } PlacementTile[] array = list.ToArray(); foreach (PlacementTile val in array) { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } list.Clear(); } private static void DestroyPrivateObject(PlacementRegion region, FieldInfo field) where T : Component { object? obj = field?.GetValue(region); T val = (T)((obj is T) ? obj : null); if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); field.SetValue(region, null); } } private static bool IsActiveBuildPlacement() { //IL_0011: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Invalid comparison between Unknown and I4 //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 PlacementRegion instance = PlacementRegion.Instance; if ((Object)(object)instance == (Object)null) { return false; } if (GameManager.IsDungeon(PlayerFarming.Location)) { return false; } if (IsEditBuildingsMode(instance)) { return true; } if ((int)instance.CurrentMode == 0) { return false; } Mode currentMode = instance.CurrentMode; if ((int)currentMode != 1 && (int)currentMode != 5) { return (int)currentMode == 3; } return true; } private static bool IsEditBuildingsMode(PlacementRegion region) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Invalid comparison between Unknown and I4 if ((Object)(object)region == (Object)null) { return false; } if ((int)region.StructureType == 215) { return true; } try { if (IsEditingBuildingsField != null && (bool)IsEditingBuildingsField.GetValue(region)) { return true; } } catch { } return (int)region.CurrentMode == 3; } private static bool EditModeTogglePressed() { if (Input.GetKeyDown((KeyCode)99)) { return true; } try { return InputManager.UI.GetEditBuildingsButtonDown((PlayerFarming)null); } catch { return false; } } private static bool AnyMenuOpen() { if (UIMenuBase.ActiveMenus != null) { return UIMenuBase.ActiveMenus.Count > 0; } return false; } private static bool HasStaleBuildSymptoms() { if (GameManager.overridePlayerPosition || Time.timeScale == 0f) { return true; } if ((Object)(object)LightingManager.Instance != (Object)null && LightingManager.Instance.inOverride) { return true; } if ((Object)(object)PlayerFarming.Instance == (Object)null || (Object)(object)PlayerFarming.Instance.CameraBone == (Object)null || (Object)(object)GameManager.GetInstance() == (Object)null) { return false; } return !GameManager.GetInstance().CameraContains(PlayerFarming.Instance.CameraBone); } private static KeyCode ParseKey(string raw, KeyCode fallback) { //IL_0011: 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) //IL_001a: 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_001e: Unknown result type (might be due to invalid IL or missing references) try { return (KeyCode)Enum.Parse(typeof(KeyCode), raw, ignoreCase: true); } catch { return fallback; } } } [HarmonyPatch(typeof(Interaction_PlacementRegion), "OnInteract")] internal static class InteractionPlacementRegionOnInteractPatch { private static void Prefix(Interaction_PlacementRegion __instance) { BetterBuildBackoutPlugin.Instance?.RememberBuilderInteraction(__instance); } } internal static class BetterBuildBackoutConfig { internal static ConfigEntry Enabled; internal static ConfigEntry AutoReopenAfterPlacement; internal static ConfigEntry ReopenKey; internal static ConfigEntry ReopenDelay; internal static ConfigEntry CancelReopensBuildMenu; internal static ConfigEntry ShowToolPrompt; internal static ConfigEntry AutoCleanup; internal static ConfigEntry AutoCleanupDelay; internal static ConfigEntry PreserveCameraForCatalogue; internal static void Bind(ConfigFile config) { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Expected O, but got Unknown Enabled = config.Bind("General", "Enabled", true, "Enable Better Build Backout."); AutoReopenAfterPlacement = config.Bind("Build Menu", "ReopenAfterPlacement", false, "Automatically reopen the build catalogue after successfully placing a structure. This is off by default; use ReopenKey for manual return."); if (AutoReopenAfterPlacement.Value) { AutoReopenAfterPlacement.Value = false; } ReopenKey = config.Bind("Controls", "ReopenKey", "R", "KeyCode used to reopen the build catalogue after placing a structure."); ReopenDelay = config.Bind("Build Menu", "ReopenDelay", 0.15f, new ConfigDescription("Delay before reopening the build catalogue.", (AcceptableValueBase)(object)new AcceptableValueRange(0.02f, 1f), Array.Empty())); CancelReopensBuildMenu = config.Bind("Controls", "CancelReopensBuildMenu", true, "When placing a structure, the first UI cancel/back press returns to the build catalogue instead of leaving build mode."); AutoCleanup = config.Bind("Cleanup", "AutoCleanup", true, "Automatically recover stale build tint/camera/player-lock state after leaving build placement."); AutoCleanupDelay = config.Bind("Cleanup", "AutoCleanupDelay", 0.75f, new ConfigDescription("Seconds stale build symptoms must persist before auto cleanup runs.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 5f), Array.Empty())); PreserveCameraForCatalogue = config.Bind("Build Menu", "PreserveCameraForCatalogue", true, "Keep the current build camera position when returning to the catalogue for a quick structure swap."); ShowToolPrompt = config.Bind("UI", "ShowToolPrompt", false, "Deprecated. Better Build Backout no longer appends text to the vanilla placement indicator."); } } [HarmonyPatch(typeof(RewiredUIInputSource), "GetCancelButtonDown")] internal static class RewiredUICancelButtonDownPatch { private static void Postfix(ref bool __result) { if (__result && (Object)(object)BetterBuildBackoutPlugin.Instance != (Object)null && BetterBuildBackoutPlugin.Instance.TryHandleCancelBackout()) { __result = false; } } } [HarmonyPatch(typeof(UIBuildMenuController), "ChosenBuilding")] internal static class BuildMenuChosenBuildingPatch { private static void Prefix(TYPES structure) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) BetterBuildBackoutPlugin.Instance?.RememberChoice(structure); BetterBuildBackoutPlugin.Instance?.MarkBuildMenuSelection(); } } [HarmonyPatch(typeof(UIBuildMenuController), "OnCancelButtonInput")] internal static class BuildMenuCancelButtonInputPatch { private static void Prefix() { BetterBuildBackoutPlugin.Instance?.HandleBuildMenuCancel(); } } [HarmonyPatch(typeof(PlacementRegion), "Play", new Type[] { typeof(Vector3) })] internal static class PlacementRegionPlayVectorPatch { private static void Prefix() { BetterBuildBackoutPlugin.Instance?.MarkBuildMenuSelection(); } } [HarmonyPatch(typeof(PlacementRegion), "Play", new Type[] { typeof(int) })] internal static class PlacementRegionPlayIntPatch { private static void Prefix() { BetterBuildBackoutPlugin.Instance?.MarkBuildMenuSelection(); } } [HarmonyPatch(typeof(PlacementRegion), "Build")] internal static class PlacementRegionBuildPatch { private static void Postfix() { BetterBuildBackoutPlugin.Instance?.QueueReopen(); } } }