Decompiled source of FiresClippy v1.0.0

Clippy.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
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("Clippy")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Clippy")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("5bd15a83-6e5a-4ebd-bf0b-231025c0d9a4")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Clippy
{
	[BepInPlugin("com.Fire.Clippy", "Clippy", "1.0.0")]
	public class ClippyPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.Fire.Clippy";

		public const string PluginName = "Clippy";

		public const string PluginVersion = "1.0.0";

		public static ConfigEntry<bool> AutoClipEnabled;

		public static ConfigEntry<bool> SuppressRandomRotationEnabled;

		public static ConfigEntry<KeyboardShortcut> ToggleKey;

		public static ConfigEntry<bool> ToggleMessage;

		public static ClippyPlugin Instance { get; private set; }

		private void Awake()
		{
			//IL_0062: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			AutoClipEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoClipEnabled", true, "When true, every hammer-selected piece has its placement ghost's\nm_clipGround and m_clipEverything flags forced to true. This routes the\nghost-position update through the direct raycast-clip path that vanilla\nuses for terrain modifiers and grounded pieces, instead of the\ncollider-ClosestPoint fallback that misbehaves on modded vegetation\nand prefabs with sparse colliders. Toggle at runtime with the configured\nkeybind; the value persists across sessions.");
			SuppressRandomRotationEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SuppressRandomRotationEnabled", true, "When true, the RandomPieceRotation component on any prefab is skipped\nduring PLAYER PLACEMENT (vanilla hammer placement or ghost setup). The\ncomponent's Awake() normally overwrites transform.localRotation with a\nworld-position-seeded random angle, which stomps on the rotation the\nplayer aimed for. Suppressing it makes player-placed pieces honor the\nrotation chosen with the hammer. Naturally-spawned vegetation in the\nworld (the case the component was designed for) is untouched — only\ncalls inside Player.SetupPlacementGhost / Player.PlacePiece are gated.");
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Keybind to toggle BOTH AutoClipEnabled and SuppressRandomRotationEnabled\nat runtime. Default F8. Modifier keys (Shift/Ctrl/Alt) supported through\nthe in-game config UI. The toggle writes the new state back to config so\nit persists across sessions. To control the two features independently,\nedit their config bools directly instead of using the keybind.");
			ToggleMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ToggleMessage", true, "Show a center-screen Hud message when the toggle is flipped. Turn off\nfor silent operation.");
			new Harmony("com.Fire.Clippy").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Clippy v1.0.0 loaded. " + $"AutoClip={AutoClipEnabled.Value}, ToggleKey={ToggleKey.Value}."));
		}

		private void Update()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = ToggleKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible())
			{
				bool flag = !AutoClipEnabled.Value;
				AutoClipEnabled.Value = flag;
				SuppressRandomRotationEnabled.Value = flag;
				if (ToggleMessage.Value && (Object)(object)Player.m_localPlayer != (Object)null)
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, flag ? "Clippy: ON" : "Clippy: OFF", 0, (Sprite)null);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
	public static class Player_UpdatePlacementGhost_Patch
	{
		private static readonly FieldRef<Player, GameObject> _ghostRef = AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost");

		private static readonly Dictionary<string, (bool clipGround, bool clipEverything)> _prefabDefaults = new Dictionary<string, (bool, bool)>();

		[HarmonyPrefix]
		public static void Prefix(Player __instance)
		{
			GameObject val = _ghostRef.Invoke(__instance);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Piece component = val.GetComponent<Piece>();
			if (!((Object)(object)component == (Object)null))
			{
				if (ClippyPlugin.AutoClipEnabled.Value)
				{
					component.m_clipGround = true;
					component.m_clipEverything = true;
				}
				else
				{
					(component.m_clipGround, component.m_clipEverything) = GetPrefabDefaults(((Object)val).name);
				}
			}
		}

		private static (bool clipGround, bool clipEverything) GetPrefabDefaults(string prefabName)
		{
			if (_prefabDefaults.TryGetValue(prefabName, out (bool, bool) value))
			{
				return value;
			}
			(bool, bool) tuple = (false, false);
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance != (Object)null)
			{
				GameObject prefab = instance.GetPrefab(prefabName);
				if ((Object)(object)prefab != (Object)null)
				{
					Piece component = prefab.GetComponent<Piece>();
					if ((Object)(object)component != (Object)null)
					{
						tuple = (component.m_clipGround, component.m_clipEverything);
					}
				}
			}
			_prefabDefaults[prefabName] = tuple;
			return tuple;
		}
	}
	internal static class RandomRotationSuppress
	{
		public static int Depth;
	}
	[HarmonyPatch(typeof(RandomPieceRotation), "Awake")]
	public static class RandomPieceRotation_Awake_Patch
	{
		[HarmonyPrefix]
		public static bool Prefix()
		{
			if (!ClippyPlugin.SuppressRandomRotationEnabled.Value)
			{
				return true;
			}
			if (RandomRotationSuppress.Depth <= 0)
			{
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "PlacePiece")]
	public static class Player_PlacePiece_Suppress_Patch
	{
		[HarmonyPrefix]
		public static void Prefix()
		{
			RandomRotationSuppress.Depth++;
		}

		[HarmonyPostfix]
		public static void Postfix()
		{
			RandomRotationSuppress.Depth--;
		}
	}
	[HarmonyPatch(typeof(Player), "SetupPlacementGhost")]
	public static class Player_SetupPlacementGhost_Suppress_Patch
	{
		[HarmonyPrefix]
		public static void Prefix()
		{
			RandomRotationSuppress.Depth++;
		}

		[HarmonyPostfix]
		public static void Postfix()
		{
			RandomRotationSuppress.Depth--;
		}
	}
}