Decompiled source of AnywhereBuild v1.2.5

AnywhereBuild.dll

Decompiled 2 weeks 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;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("AnywhereBuild")]
[assembly: AssemblyProduct("AnywhereBuild")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("0.0.0.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 AnywhereBuild
{
	internal static class BuildRequirementPatches
	{
		private sealed class StationFieldChange
		{
			internal object Piece;

			internal FieldInfo Field;

			internal object OriginalValue;
		}

		private sealed class StationBypassState
		{
			internal readonly List<StationFieldChange> Changes = new List<StationFieldChange>();
		}

		private static ManualLogSource _log;

		private static Type _pieceType;

		private static FieldInfo _pieceCraftingStationField;

		private static FieldInfo _playerBuildPiecesField;

		private static FieldInfo _playerPlacementGhostField;

		private static MethodInfo _pieceTableGetSelectedPrefab;

		private static Type _wearNTearType;

		private static MethodInfo _getMaxSupportMethod;

		private static FieldInfo _supportField;

		public static void Install(Harmony harmony, ManualLogSource log)
		{
			_log = log;
			InstallCraftingStationBypass(harmony);
			InstallCraftingStationHudCleanup(harmony);
			InstallStructuralSupportBypass(harmony);
		}

		private static void InstallCraftingStationBypass(Harmony harmony)
		{
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			//IL_01b3: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("Player");
			_pieceType = AccessTools.TypeByName("Piece");
			if (type == null || _pieceType == null)
			{
				_log.LogError((object)"AnywhereBuild: Player/Piece type not found; crafting-station bypass unavailable.");
				return;
			}
			_pieceCraftingStationField = AccessTools.Field(_pieceType, "m_craftingStation");
			_playerBuildPiecesField = AccessTools.Field(type, "m_buildPieces");
			_playerPlacementGhostField = AccessTools.Field(type, "m_placementGhost");
			Type type2 = AccessTools.TypeByName("PieceTable");
			if (type2 != null)
			{
				_pieceTableGetSelectedPrefab = AccessTools.Method(type2, "GetSelectedPrefab", (Type[])null, (Type[])null);
			}
			if (_pieceCraftingStationField == null)
			{
				_log.LogError((object)"AnywhereBuild: Piece.m_craftingStation not found; crafting-station bypass unavailable.");
				return;
			}
			string[] array = new string[4] { "SetupPlacementGhost", "UpdatePlacementGhost", "UpdatePlacement", "PlacePiece" };
			HashSet<MethodBase> hashSet = new HashSet<MethodBase>();
			string[] array2 = array;
			foreach (string methodName in array2)
			{
				foreach (MethodInfo item in from m in AccessTools.GetDeclaredMethods(type)
					where m.Name == methodName
					select m)
				{
					if (!hashSet.Add(item))
					{
						continue;
					}
					try
					{
						harmony.Patch((MethodBase)item, new HarmonyMethod(typeof(BuildRequirementPatches), "StationBypassPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(BuildRequirementPatches), "StationBypassFinalizer", (Type[])null), (HarmonyMethod)null);
						_log.LogInfo((object)("AnywhereBuild: crafting-station bypass scoped around Player." + item.Name + "(" + string.Join(", ", from p in item.GetParameters()
							select p.ParameterType.Name) + ")."));
					}
					catch (Exception ex)
					{
						_log.LogWarning((object)("AnywhereBuild: failed to patch " + item.Name + " for crafting-station bypass: " + ex));
					}
				}
			}
		}

		private static void StationBypassPrefix(object __instance, object[] __args, out StationBypassState __state)
		{
			__state = null;
			if (!ShouldIgnoreCraftingStations() || __instance == null)
			{
				return;
			}
			StationBypassState state = (__state = new StationBypassState());
			try
			{
				ClearSelectedPieceStation(__instance, state);
				ClearPlacementGhostStation(__instance, state);
				if (__args != null)
				{
					foreach (object candidate in __args)
					{
						ClearStationRequirement(candidate, state);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogWarning((object)("AnywhereBuild: temporary crafting-station bypass failed: " + ex));
				}
			}
		}

		private static Exception StationBypassFinalizer(Exception __exception, StationBypassState __state)
		{
			if (__state != null)
			{
				for (int num = __state.Changes.Count - 1; num >= 0; num--)
				{
					StationFieldChange stationFieldChange = __state.Changes[num];
					if (stationFieldChange != null && stationFieldChange.Piece != null && !(stationFieldChange.Field == null))
					{
						try
						{
							stationFieldChange.Field.SetValue(stationFieldChange.Piece, stationFieldChange.OriginalValue);
						}
						catch
						{
						}
					}
				}
			}
			return __exception;
		}

		private static void ClearSelectedPieceStation(object player, StationBypassState state)
		{
			if (_playerBuildPiecesField == null || _pieceTableGetSelectedPrefab == null)
			{
				return;
			}
			object value = _playerBuildPiecesField.GetValue(player);
			if (value != null)
			{
				object? obj = _pieceTableGetSelectedPrefab.Invoke(value, null);
				GameObject val = (GameObject)((obj is GameObject) ? obj : null);
				if ((Object)(object)val != (Object)null)
				{
					ClearStationRequirement(val, state);
				}
			}
		}

		private static void ClearPlacementGhostStation(object player, StationBypassState state)
		{
			if (!(_playerPlacementGhostField == null))
			{
				object? value = _playerPlacementGhostField.GetValue(player);
				GameObject val = (GameObject)((value is GameObject) ? value : null);
				if ((Object)(object)val != (Object)null)
				{
					ClearStationRequirement(val, state);
				}
			}
		}

		private static void ClearStationRequirement(object candidate, StationBypassState state)
		{
			if (candidate == null || state == null || _pieceCraftingStationField == null || _pieceType == null)
			{
				return;
			}
			object piece = null;
			if (_pieceType.IsInstanceOfType(candidate))
			{
				piece = candidate;
			}
			else
			{
				GameObject val = (GameObject)((candidate is GameObject) ? candidate : null);
				if (val != null)
				{
					piece = val.GetComponent(_pieceType);
				}
				else
				{
					Component val2 = (Component)((candidate is Component) ? candidate : null);
					if (val2 != null)
					{
						piece = val2.gameObject.GetComponent(_pieceType);
					}
				}
			}
			if (piece != null && !state.Changes.Any((StationFieldChange c) => c.Piece == piece))
			{
				object value = _pieceCraftingStationField.GetValue(piece);
				if (value != null)
				{
					state.Changes.Add(new StationFieldChange
					{
						Piece = piece,
						Field = _pieceCraftingStationField,
						OriginalValue = value
					});
					_pieceCraftingStationField.SetValue(piece, null);
				}
			}
		}

		private static void InstallCraftingStationHudCleanup(Harmony harmony)
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("Hud");
			if (type == null)
			{
				_log.LogWarning((object)"AnywhereBuild: Hud type not found; crafting-station 'None' text cleanup unavailable.");
				return;
			}
			string[] array = new string[3] { "UpdateBuild", "UpdatePieceList", "UpdatePieceSelection" };
			HashSet<MethodBase> hashSet = new HashSet<MethodBase>();
			string[] array2 = array;
			foreach (string methodName in array2)
			{
				foreach (MethodInfo item in from m in AccessTools.GetDeclaredMethods(type)
					where m.Name == methodName
					select m)
				{
					if (hashSet.Add(item))
					{
						try
						{
							harmony.Patch((MethodBase)item, (HarmonyMethod)null, new HarmonyMethod(typeof(BuildRequirementPatches), "CraftingStationHudPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
							_log.LogInfo((object)("AnywhereBuild: crafting-station HUD cleanup patched Hud." + item.Name + "()."));
						}
						catch (Exception ex)
						{
							_log.LogWarning((object)("AnywhereBuild: failed to patch Hud." + item.Name + " for station-text cleanup: " + ex));
						}
					}
				}
			}
		}

		private static void CraftingStationHudPostfix(object __instance)
		{
			if (!ShouldIgnoreCraftingStations() || __instance == null)
			{
				return;
			}
			Component val = (Component)((__instance is Component) ? __instance : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				Component[] componentsInChildren = val.GetComponentsInChildren<Component>(true);
				Component[] array = componentsInChildren;
				foreach (Component val2 in array)
				{
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					Type type = ((object)val2).GetType();
					PropertyInfo property = type.GetProperty("text", BindingFlags.Instance | BindingFlags.Public);
					if (property == null || property.PropertyType != typeof(string) || !property.CanRead || !property.CanWrite)
					{
						continue;
					}
					string text;
					try
					{
						text = property.GetValue(val2, null) as string;
					}
					catch
					{
						continue;
					}
					if (string.Equals(text?.Trim(), "None", StringComparison.OrdinalIgnoreCase))
					{
						try
						{
							property.SetValue(val2, string.Empty, null);
						}
						catch
						{
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogDebug((object)("AnywhereBuild: crafting-station HUD text cleanup skipped: " + ex.Message));
				}
			}
		}

		private static void InstallStructuralSupportBypass(Harmony harmony)
		{
			_wearNTearType = AccessTools.TypeByName("WearNTear");
			if (_wearNTearType == null)
			{
				_log.LogError((object)"AnywhereBuild: WearNTear type not found; structural-support bypass unavailable.");
				return;
			}
			_getMaxSupportMethod = AccessTools.Method(_wearNTearType, "GetMaxSupport", (Type[])null, (Type[])null);
			_supportField = AccessTools.Field(_wearNTearType, "m_support") ?? AccessTools.Field(_wearNTearType, "m_currentSupport");
			PatchWearMethod(harmony, "HaveSupport", "HaveSupportPrefix", typeof(bool));
			PatchWearMethod(harmony, "GetSupport", "GetSupportPrefix", typeof(float));
			PatchWearMethod(harmony, "UpdateSupport", "UpdateSupportPrefix", null);
		}

		private static void PatchWearMethod(Harmony harmony, string methodName, string prefixName, Type expectedReturnType)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(BuildRequirementPatches), prefixName, (Type[])null, (Type[])null);
			MethodInfo[] array = (from m in AccessTools.GetDeclaredMethods(_wearNTearType)
				where m.Name == methodName && (expectedReturnType == null || m.ReturnType == expectedReturnType)
				select m).ToArray();
			if (array.Length == 0)
			{
				_log.LogWarning((object)("AnywhereBuild: WearNTear." + methodName + " not found."));
				return;
			}
			MethodInfo[] array2 = array;
			foreach (MethodInfo methodInfo2 in array2)
			{
				try
				{
					harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					_log.LogInfo((object)("AnywhereBuild: structural-support bypass patched WearNTear." + methodName + "()."));
				}
				catch (Exception ex)
				{
					_log.LogWarning((object)("AnywhereBuild: failed to patch WearNTear." + methodName + ": " + ex));
				}
			}
		}

		private static bool HaveSupportPrefix(ref bool __result)
		{
			if (!ShouldIgnoreStructuralSupport())
			{
				return true;
			}
			__result = true;
			return false;
		}

		private static bool GetSupportPrefix(object __instance, ref float __result)
		{
			if (!ShouldIgnoreStructuralSupport())
			{
				return true;
			}
			__result = GetMaximumSupport(__instance);
			return false;
		}

		private static bool UpdateSupportPrefix(object __instance)
		{
			if (!ShouldIgnoreStructuralSupport())
			{
				return true;
			}
			if (__instance != null && _supportField != null)
			{
				try
				{
					_supportField.SetValue(__instance, GetMaximumSupport(__instance));
				}
				catch
				{
				}
			}
			return false;
		}

		private static float GetMaximumSupport(object wearNTear)
		{
			if (wearNTear != null && _getMaxSupportMethod != null)
			{
				try
				{
					if (_getMaxSupportMethod.Invoke(wearNTear, null) is float num && !float.IsNaN(num) && !float.IsInfinity(num) && num > 0f)
					{
						return num;
					}
				}
				catch
				{
				}
			}
			return 1000000f;
		}

		private static bool ShouldIgnoreCraftingStations()
		{
			return Plugin.Enabled != null && Plugin.Enabled.Value && Plugin.IgnoreCraftingStationRequirement != null && Plugin.IgnoreCraftingStationRequirement.Value;
		}

		private static bool ShouldIgnoreStructuralSupport()
		{
			return Plugin.Enabled != null && Plugin.Enabled.Value && Plugin.AllowUnsupportedStructures != null && Plugin.AllowUnsupportedStructures.Value;
		}
	}
	internal static class PlacementPatches
	{
		private static ManualLogSource _log;

		public static void Install(Harmony harmony, ManualLogSource log)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			_log = log;
			Type type = AccessTools.TypeByName("Player");
			if (type == null)
			{
				_log.LogError((object)"AnywhereBuild: Player type not found.");
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(type, "UpdatePlacementGhost", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				_log.LogError((object)"AnywhereBuild: Player.UpdatePlacementGhost not found.");
				return;
			}
			harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(PlacementPatches), "UpdatePlacementGhostPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_log.LogInfo((object)"AnywhereBuild: placement ghost patch installed (always blue).");
		}

		private static void UpdatePlacementGhostPostfix(object __instance)
		{
			if (!Plugin.Enabled.Value || __instance == null)
			{
				return;
			}
			try
			{
				Type type = __instance.GetType();
				FieldInfo fieldInfo = AccessTools.Field(type, "m_placementStatus");
				if (fieldInfo != null && fieldInfo.FieldType.IsEnum)
				{
					object obj = FindEnumValue(fieldInfo.FieldType, "Valid");
					if (obj != null)
					{
						fieldInfo.SetValue(__instance, obj);
					}
				}
				MethodInfo methodInfo = AccessTools.Method(type, "SetPlacementGhostValid", new Type[1] { typeof(bool) }, (Type[])null);
				if (methodInfo != null)
				{
					object? obj2 = AccessTools.Field(type, "m_placementGhost")?.GetValue(__instance);
					GameObject val = (GameObject)((obj2 is GameObject) ? obj2 : null);
					if ((Object)(object)val != (Object)null)
					{
						methodInfo.Invoke(__instance, new object[1] { true });
					}
				}
				else
				{
					_log.LogWarning((object)"AnywhereBuild: SetPlacementGhostValid(bool) was not found; blue ghost could not be forced.");
				}
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("AnywhereBuild: blue placement ghost update failed: " + ex));
			}
		}

		private static object FindEnumValue(Type enumType, string name)
		{
			string[] names = Enum.GetNames(enumType);
			foreach (string text in names)
			{
				if (string.Equals(text, name, StringComparison.OrdinalIgnoreCase))
				{
					return Enum.Parse(enumType, text);
				}
			}
			return null;
		}
	}
	[BepInPlugin("Moopfam.AnywhereBuild", "AnywhereBuild", "1.2.5")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "Moopfam.AnywhereBuild";

		public const string PluginName = "AnywhereBuild";

		public const string PluginVersion = "1.2.5";

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<KeyCode> ToggleKey;

		internal static ConfigEntry<bool> IgnoreCraftingStationRequirement;

		internal static ConfigEntry<bool> AllowUnsupportedStructures;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Moopfam", "Enabled", true, "Enable or disable AnywhereBuild.");
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Moopfam", "ToggleKey", (KeyCode)0, "Key used to toggle AnywhereBuild on or off. Disabled by default.");
			IgnoreCraftingStationRequirement = ((BaseUnityPlugin)this).Config.Bind<bool>("Moopfam", "IgnoreCraftingStationRequirement", true, "Allow building without a Workbench, Stonecutter, Forge, Artisan Table, or other required crafting station in range.");
			AllowUnsupportedStructures = ((BaseUnityPlugin)this).Config.Bind<bool>("Moopfam", "AllowUnsupportedStructures", true, "Allow structures to be built without structural support, including floating and unsupported pieces.");
			_harmony = new Harmony("Moopfam.AnywhereBuild");
			PlacementPatches.Install(_harmony, ((BaseUnityPlugin)this).Logger);
			RemovalPatches.Install(_harmony, ((BaseUnityPlugin)this).Logger);
			BuildRequirementPatches.Install(_harmony, ((BaseUnityPlugin)this).Logger);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"AnywhereBuild 1.2.5 loaded.");
		}

		private void Update()
		{
			//IL_000d: 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)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (ToggleKey != null && (int)ToggleKey.Value != 0 && Input.GetKeyDown(ToggleKey.Value))
			{
				Enabled.Value = !Enabled.Value;
				((BaseUnityPlugin)this).Config.Save();
				((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("AnywhereBuild: {0} via {1}.", Enabled.Value ? "ENABLED" : "DISABLED", ToggleKey.Value));
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class RemovalPatches
	{
		private static ManualLogSource _log;

		[ThreadStatic]
		private static int _removePieceDepth;

		public static void Install(Harmony harmony, ManualLogSource log)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected O, but got Unknown
			//IL_00d0: Expected O, but got Unknown
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Expected O, but got Unknown
			_log = log;
			Type type = AccessTools.TypeByName("Player");
			if (type == null)
			{
				_log.LogError((object)"AnywhereBuild: Player type not found.");
				return;
			}
			MethodInfo[] array = (from m in AccessTools.GetDeclaredMethods(type)
				where m.Name == "RemovePiece"
				select m).ToArray();
			if (array.Length == 0)
			{
				_log.LogError((object)"AnywhereBuild: Player.RemovePiece not found.");
				return;
			}
			MethodInfo[] array2 = array;
			foreach (MethodInfo methodInfo in array2)
			{
				try
				{
					harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(RemovalPatches), "RemovePiecePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(RemovalPatches), "RemovePieceFinalizer", (Type[])null), (HarmonyMethod)null);
					_log.LogInfo((object)("AnywhereBuild: scoped mystical-force bypass around Player.RemovePiece(" + string.Join(", ", from p in methodInfo.GetParameters()
						select p.ParameterType.Name) + ")."));
				}
				catch (Exception ex)
				{
					_log.LogError((object)("AnywhereBuild: failed to patch Player.RemovePiece: " + ex));
				}
			}
			Type type2 = AccessTools.TypeByName("Location");
			if (type2 == null)
			{
				_log.LogError((object)"AnywhereBuild: Location type not found.");
				return;
			}
			MethodInfo[] array3 = (from m in AccessTools.GetDeclaredMethods(type2)
				where m.Name == "IsInsideNoBuildLocation" && m.ReturnType == typeof(bool)
				select m).ToArray();
			if (array3.Length == 0)
			{
				_log.LogError((object)"AnywhereBuild: Location.IsInsideNoBuildLocation not found.");
				return;
			}
			MethodInfo[] array4 = array3;
			foreach (MethodInfo methodInfo2 in array4)
			{
				try
				{
					harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(RemovalPatches), "NoBuildLocationPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					_log.LogInfo((object)("AnywhereBuild: patched Location.IsInsideNoBuildLocation(" + string.Join(", ", from p in methodInfo2.GetParameters()
						select p.ParameterType.Name) + ")."));
				}
				catch (Exception ex2)
				{
					_log.LogError((object)("AnywhereBuild: failed to patch IsInsideNoBuildLocation: " + ex2));
				}
			}
		}

		private static void RemovePiecePrefix()
		{
			if (Plugin.Enabled.Value)
			{
				_removePieceDepth++;
			}
		}

		private static Exception RemovePieceFinalizer(Exception __exception)
		{
			if (_removePieceDepth > 0)
			{
				_removePieceDepth--;
			}
			return __exception;
		}

		private static void NoBuildLocationPostfix(ref bool __result)
		{
			if (Plugin.Enabled.Value && _removePieceDepth > 0)
			{
				__result = false;
			}
		}
	}
}