Decompiled source of ZenConstruction v0.4.1

plugins\ZenConstruction.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using JetBrains.Annotations;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using Zen.Config;
using Zen.Controls;
using Zen.Lib;
using Zen.Logging;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ZenConstruction")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ZenConstruction")]
[assembly: AssemblyCopyright("Copyright \ufffd  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 ZenConstruction
{
	public static class BuildRotation
	{
		private static readonly (int Segments, string Label)[] Divisions = new(int, string)[2]
		{
			(8, "Default"),
			(12, "Advanced")
		};

		private static int _currentIndex;

		public static void HandleInput()
		{
			if (Configs.EnableRotationChange.Value && UI.IsBuildModeActive)
			{
				if (ZInput.GetKey((KeyCode)304, true) && ZInput.GetKeyDown((KeyCode)275, true))
				{
					SetNextBuildRotation();
				}
				if (ZInput.GetButton(ControlInputs.JoyAlt) && ZInput.GetButtonDown("JoyDPadRight"))
				{
					SetNextBuildRotation();
				}
			}
		}

		private static void SetNextBuildRotation()
		{
			_currentIndex++;
			_currentIndex %= Divisions.Length;
			(int, string) tuple = Divisions[_currentIndex];
			Player localPlayer = Player.m_localPlayer;
			localPlayer.m_placeRotationDegrees = 180f / (float)tuple.Item1;
			((Character)localPlayer).Message((MessageType)2, $"{tuple.Item2} build rotation: {360f / (float)tuple.Item1:n1} degrees", 0, (Sprite)null);
		}
	}
	internal static class Configs
	{
		internal static readonly ConfigEntry<bool> AllowTorchWithHammer;

		internal static readonly ConfigEntry<bool> EnableRotationChange;

		internal static readonly ConfigEntry<KeyCode> HammerKey;

		public static readonly ConfigEntry<bool> EnableSmelterSupports;

		public static readonly ConfigEntry<bool> EnableTreeSupports;

		public static readonly ConfigEntry<StringList> BuildOnTreesException;

		public static readonly ConfigEntry<StringList> NoSupportPrefabs;

		public static readonly ConfigEntry<StringList> NoBuildLocations;

		public static readonly ConfigEntry<float> NoBuildLocationsRadius;

		public static readonly ConfigEntry<float> StationExtensionDistanceMultiplier;

		static Configs()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_009d: Expected O, but got Unknown
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			//IL_010e: Expected O, but got Unknown
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			//IL_0138: Expected O, but got Unknown
			AllowTorchWithHammer = Config.Define<bool>(true, "General", "Allow Torch With Hammer", true, "When enabled allows the a torch to be equipped in the offhand while using the Hammer. (Vanilla: false)");
			EnableRotationChange = Config.Define<bool>(true, "Input", "Enable Rotation Degree Change", true, "Enable rotation degree adjustment for smoother curves of 30 degrees instead of 45.\r\nEquip your hammer then press:\r\nKeyboard: Press LeftShift + RightArrow to cycle modes.\r\nGamepad: Press Alt Interact + D-Pad Right to cycle modes.");
			HammerKey = Config.Define<KeyCode>(false, "Input", "Hammer Hotkey", (KeyCode)98, "When pressed it searches your inventory for your highest level Hammer and equips it.\r\nPress again to unequip.  Press and hold to quick select repair. \r\nThis frees up a slot on your hotbar.\r\nGamepad is always Select(Nintendo) aka Window(Xbox) aka Create(PS).");
			EnableSmelterSupports = Config.Define<bool>(true, "Structure", "Enable Smelter Supports", true, "Enable structure support on Smelters, Blast Furnaces, Kilns, etc.\nCan the player attach construction to those pieces? (Vanilla: True)");
			StringList val = new StringList();
			((List<string>)val).Add("sign");
			((List<string>)val).Add("piece_shieldgenerator");
			NoSupportPrefabs = Config.Define<StringList>(true, "Structure", "No Support Prefabs", val, "List of prefabs which will always have support removed");
			EnableTreeSupports = Config.Define<bool>(true, "Structure", "Tree Supports", false, "Do trees support construction? (Vanilla: True)");
			StringList val2 = new StringList();
			((List<string>)val2).Add("sign");
			((List<string>)val2).Add("piece_walltorch");
			((List<string>)val2).Add("piece_dvergr_lantern");
			((List<string>)val2).Add("itemstand");
			((List<string>)val2).Add("piece_beehive");
			BuildOnTreesException = Config.Define<StringList>(true, "Structure", "Allow Build On Trees Prefabs", val2, "These items can always be built on trees.  NOTE: These items will lose any support capability they may have had.");
			StringList val3 = new StringList();
			((List<string>)val3).Add("Bonemass");
			NoBuildLocations = Config.Define<StringList>(true, "Structure", "No Build Locations", val3, "List of locations that prohibit building.\r\nDefaults to Bonemass because otherwise the palyer can cheese the boss fight by standing on top of the boss alter.\r\nExample, All Boss Locations:\r\nEikthyrnir, GDKing, Bonemass, Dragonqueen, GoblinKing, FaderLocation ");
			NoBuildLocationsRadius = Config.Define<float>(true, "Structure", "No Build Locations Radius", 25f, Config.AcceptRange<float>(0.1f, 200f), "Distance around No Build Locations that building is prohibited.");
			StationExtensionDistanceMultiplier = Config.Define<float>(true, "Structure", "Station Extension Distance Multiplier", 1.17f, Config.AcceptRange<float>(1f, 2f), "Multiplier for max distance that workstation extensions can be spread out. (Vanilla: 1)\nLarger values allow extensions to be further away from the workstation. More elbow room.");
		}
	}
	[HarmonyPatch]
	public static class QuickSelectBuild
	{
		public static readonly ActionString InputRepair = new ActionString("InputRepair", "$hud_repair $radial_hold", true);

		public static readonly ActionString InputBuild = new ActionString("InputBuild", "$item_hammer", true);

		private static Vector2Int? _origPieceIndex;

		private static bool IsUsingHammer
		{
			get
			{
				Player localPlayer = Player.m_localPlayer;
				object obj;
				if (localPlayer == null)
				{
					obj = null;
				}
				else
				{
					ItemData rightItem = ((Humanoid)localPlayer).RightItem;
					obj = ((rightItem != null) ? ItemDataExt.GetPrefabName(rightItem) : null);
				}
				return (string?)obj == "Hammer";
			}
		}

		public static void RegisterInputs()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			InputRepair.AddButton(Configs.HammerKey.Value, false, false, false, 0f, 0f);
			InputRepair.AddButton((GamepadInput)19, false, false, false, 0f, 0f);
			InputBuild.AddButton(Configs.HammerKey.Value, false, false, false, 0f, 0f);
			InputBuild.AddButton((GamepadInput)19, false, true, false, 0f, 0f);
		}

		public static void CreateKeyHints()
		{
			KeyHint.Create((HintType)0, InputRepair, 2, false);
			KeyHint.SetEvent((HintType)0, (Action)OnUpdateHints);
		}

		private static void OnUpdateHints()
		{
			KeyHint.SetVisible(InputRepair, IsUsingHammer);
			KeyHint.SetVisible("Place", !Hud.IsPieceSelectionVisible());
		}

		public static void HandleInput()
		{
			CheckRepairPressed();
			CheckBuildPressed();
		}

		private static void CheckRepairPressed()
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (!IsUsingHammer)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!(ZInput.GetButtonPressedTimer(ActionString.op_Implicit(InputBuild)) < 0.8f))
			{
				ZInput.ResetButtonStatus(ActionString.op_Implicit(InputBuild));
				if (_origPieceIndex.HasValue)
				{
					localPlayer.SetSelectedPiece(_origPieceIndex.Value);
					localPlayer.UpdatePlacementGhost(false);
					_origPieceIndex = null;
				}
				else
				{
					_origPieceIndex = localPlayer.m_buildPieces.GetSelectedIndex();
					PlayerExt.SelectRepairTool(localPlayer);
				}
			}
		}

		private static void CheckBuildPressed()
		{
			if (!((Character)Player.m_localPlayer).TakeInput())
			{
				return;
			}
			if (UI.IsBuildModeActive)
			{
				if (!ZInput.GetButtonUp(ActionString.op_Implicit(InputBuild)))
				{
					return;
				}
			}
			else if (!ZInput.GetButtonDown(ActionString.op_Implicit(InputBuild)))
			{
				return;
			}
			if (!(ZInput.GetButtonLastPressedTimer(ActionString.op_Implicit(InputBuild)) > 0.3f))
			{
				ItemData val = (from item in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems()
					where ItemDataExt.GetPrefabName(item) == "Hammer"
					select item into hammer
					orderby hammer.m_quality descending
					select hammer).FirstOrDefault();
				if (val == null)
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_missingitem: $item_hammer", 0, (Sprite)null);
				}
				else
				{
					ToolEquip.ToggleHammer(val);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Hud), "SelectPiece")]
		private static void Hud_SelectPiece()
		{
			_origPieceIndex = null;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "Awake")]
		private static void Player_Awake(Player __instance)
		{
			if (IsUsingHammer)
			{
				PlayerExt.SelectRepairTool(__instance);
				((Humanoid)__instance).HideHandItems(false, true);
			}
		}
	}
	[BepInPlugin("ZenDragon.ZenConstruction", "ZenConstruction", "0.4.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class Plugin : ZenMod<Plugin>
	{
		public const string PluginGUID = "ZenDragon.ZenConstruction";

		public const string PluginName = "ZenConstruction";

		public const string PluginVersion = "0.4.1";

		protected override void Setup()
		{
			((ZenMod)this).RequireGamepadRemap = true;
			((ZenMod)this).RegisterInputs += QuickSelectBuild.RegisterInputs;
			((ZenMod)this).ConfigSync += OnConfigSync;
		}

		private static void OnConfigSync()
		{
			Structure.SetupPrefabs();
		}

		protected override void TitleScene(bool isFirstBoot)
		{
		}

		protected override void WorldStart()
		{
			QuickSelectBuild.CreateKeyHints();
		}

		protected override void Shutdown()
		{
		}

		private void Update()
		{
			if (ZenMod<Plugin>.Initialized && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				QuickSelectBuild.HandleInput();
				BuildRotation.HandleInput();
			}
		}
	}
	[HarmonyPatch]
	public static class Structure
	{
		private static readonly RaycastHit[] RaycastHitInfoBuffer = (RaycastHit[])(object)new RaycastHit[8];

		internal static void SetupPrefabs()
		{
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				if (!Configs.EnableSmelterSupports.Value)
				{
					RemoveSmelterStructureSupports(prefab);
				}
				if (Configs.NoSupportPrefabs.Value.Contains(((Object)prefab).name, true))
				{
					RemoveStructureSupports(prefab);
				}
				if (!Configs.EnableTreeSupports.Value && Configs.BuildOnTreesException.Value.Contains(((Object)prefab).name, true))
				{
					RemoveStructureSupports(prefab);
				}
			}
		}

		private static void CheckIfNoBuild(Location location)
		{
			string prefabName = Utils.GetPrefabName(((Component)location).gameObject);
			if (Configs.NoBuildLocations.Value.Contains(prefabName, true))
			{
				location.m_noBuild = true;
				location.m_noBuildRadiusOverride = Configs.NoBuildLocationsRadius.Value;
			}
		}

		private static void RemoveSmelterStructureSupports(GameObject prefab)
		{
			Smelter[] componentsInChildren = prefab.GetComponentsInChildren<Smelter>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				RemoveStructureSupports(((Component)componentsInChildren[i]).gameObject);
			}
		}

		private static void RemoveStructureSupports(GameObject prefab)
		{
			WearNTear val = default(WearNTear);
			if (prefab.TryGetComponent<WearNTear>(ref val))
			{
				Log.Info((object)("Remove WearNTear Supports: " + ((Object)prefab).name), (ushort)0);
				val.m_supports = false;
			}
		}

		private static bool IsPlacementTree()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			Transform transform = ((Component)GameCamera.instance).transform;
			Vector3 position = transform.position;
			Vector3 forward = transform.forward;
			int placeRayMask = localPlayer.m_placeRayMask;
			int num = Physics.RaycastNonAlloc(position, forward, RaycastHitInfoBuffer, 50f, placeRayMask);
			for (int i = 0; i < num; i++)
			{
				RaycastHit val = RaycastHitInfoBuffer[i];
				Transform transform2 = ((RaycastHit)(ref val)).transform;
				if (((Object)transform2).name.Contains("Tree") || (Object.op_Implicit((Object)(object)transform2.parent) && ((Object)transform2.parent).name.Contains("Tree")))
				{
					return false;
				}
				if (Object.op_Implicit((Object)(object)((Component)transform2).GetComponentInParent<TreeBase>()))
				{
					return false;
				}
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(StationExtension), "Awake")]
		private static void StationExtension_Awake(StationExtension __instance)
		{
			__instance.m_maxStationDistance *= Configs.StationExtensionDistanceMultiplier.Value;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "SetPlacementGhostValid")]
		private static void Player_SetPlacementGhostValid(Player __instance, ref bool valid)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (valid && !Configs.BuildOnTreesException.Value.Contains(Utils.GetPrefabName(((Object)__instance.m_placementGhost).name), true))
			{
				if (!Configs.EnableTreeSupports.Value)
				{
					valid = IsPlacementTree();
				}
				if (!valid)
				{
					__instance.m_placementStatus = (PlacementStatus)1;
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Location), "Awake")]
		private static void Location_Awake(Location __instance)
		{
			CheckIfNoBuild(__instance);
		}
	}
	[HarmonyPatch]
	internal static class ToolEquip
	{
		[HarmonyPatch(typeof(Humanoid), "EquipItem")]
		[HarmonyPriority(200)]
		private static class Humanoid_EquipItem
		{
			[UsedImplicitly]
			private static void Prefix(Humanoid __instance, ItemData? item, ref (ItemData? Left, ItemData? Right) __state)
			{
				__state.Left = __instance.LeftItem;
				__state.Right = __instance.RightItem;
			}

			[UsedImplicitly]
			private static void Postfix(Humanoid __instance, ItemData? item, (ItemData? Left, ItemData? Right) __state)
			{
				if (Configs.AllowTorchWithHammer.Value && item != null && !(ItemDataExt.GetPrefabName(item) != "Hammer"))
				{
					var (val, val2) = __state;
					if (val != null && ItemDataExt.IsItemType(val, (ItemType)15))
					{
						__instance.m_leftItem = val;
					}
					else if (val2 != null && ItemDataExt.IsItemType(val2, (ItemType)15))
					{
						__instance.m_leftItem = val2;
					}
					if (__instance.m_leftItem != null)
					{
						__instance.m_leftItem.m_equipped = true;
						__instance.SetupEquipment();
					}
				}
			}
		}

		private const float ToolEquipDuration = 0.3f;

		internal const string HammerTool = "Hammer";

		private static (ItemData? Left, ItemData? Right) _prevEquip;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static void ObjectDB_CopyOtherDB(ObjectDB __instance)
		{
			SetToolEquipDuration(__instance, 0.3f);
		}

		private static void SetToolEquipDuration(ObjectDB db, float duration)
		{
			foreach (GameObject item in db.m_items)
			{
				ItemData itemData = item.GetComponent<ItemDrop>().m_itemData;
				if (ItemDataExt.IsItemType(itemData, (ItemType)19))
				{
					if (itemData.m_shared.m_equipDuration <= 0f)
					{
						itemData.m_shared.m_equipDuration = duration;
					}
					Log.Info((object)(ItemDataExt.GetPrefabName(itemData) + " equip duration: " + itemData.m_shared.m_equipDuration), (ushort)0);
				}
			}
		}

		internal static void ToggleHammer(ItemData hammer)
		{
			if (!(ItemDataExt.GetPrefabName(hammer) != "Hammer"))
			{
				if (hammer.m_equipped)
				{
					RestoreEquip(hammer);
					return;
				}
				CacheEquip();
				((Humanoid)Player.m_localPlayer).ToggleEquipped(hammer);
			}
		}

		private static void CacheEquip()
		{
			_prevEquip.Left = ((Humanoid)Player.m_localPlayer).LeftItem;
			_prevEquip.Right = ((Humanoid)Player.m_localPlayer).RightItem;
		}

		private static void RestoreEquip(ItemData hammer)
		{
			ItemData val = FindItem(_prevEquip.Right);
			ItemData val2 = FindItem(_prevEquip.Left);
			if (val != null && val2 != null)
			{
				((Humanoid)Player.m_localPlayer).ToggleEquipped(val);
				((Humanoid)Player.m_localPlayer).EquipItem(val2, true);
			}
			else if (val != null && val2 == null)
			{
				((Humanoid)Player.m_localPlayer).ToggleEquipped((ItemData)(ItemDataExt.IsItemType(val, (ItemType)15) ? ((object)hammer) : ((object)val)));
			}
			else if (val == null && val2 != null)
			{
				((Humanoid)Player.m_localPlayer).ToggleEquipped((ItemData)(ItemDataExt.IsItemType(val2, (ItemType)15) ? ((object)hammer) : ((object)val2)));
			}
			else if (val == null && val2 == null)
			{
				((Humanoid)Player.m_localPlayer).ToggleEquipped(hammer);
			}
			_prevEquip = default((ItemData, ItemData));
			static ItemData? FindItem(ItemData? original)
			{
				ItemData original2 = original;
				if (original2 != null)
				{
					return ((IEnumerable<ItemData>)((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData item) => ItemDataExt.IsEqual(item, original2)));
				}
				return null;
			}
		}
	}
}