Decompiled source of BetterPreplacedPitons v1.0.0

plugins/com.github.GABRlEL.BetterPreplacedPitons.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
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 Photon.Pun;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.GABRlEL.BetterPreplacedPitons")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("com.github.GABRlEL.BetterPreplacedPitons")]
[assembly: AssemblyTitle("BetterPreplacedPitons")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BetterPreplacedPitons
{
	[BepInPlugin("com.github.GABRlEL.BetterPreplacedPitons", "BetterPreplacedPitons", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		private Harmony? _harmony;

		public const string Id = "com.github.GABRlEL.BetterPreplacedPitons";

		internal static ManualLogSource Log { get; private set; }

		internal static ConfigEntry<bool> EnablePreplacedPitons { get; private set; }

		internal static ConfigEntry<bool> EnableMesaPickaxes { get; private set; }

		internal static ConfigEntry<float> PreplacedPitonBreakSpeedMultiplier { get; private set; }

		internal static ConfigEntry<float> MesaPickaxeBreakSpeedMultiplier { get; private set; }

		internal static ConfigEntry<bool> ClientSidePersistence { get; private set; }

		public static string Name => "BetterPreplacedPitons";

		public static string Version => "0.1.0";

		private void Awake()
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			EnablePreplacedPitons = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnablePreplacedPitons", true, "If true, applies the configured break-speed behavior to preplaced rope pitons (BreakableRopeAnchor).");
			PreplacedPitonBreakSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "PreplacedPitonBreakSpeedMultiplier", -1f, "Break-speed multiplier for preplaced rope pitons.\n  <= 0 : unbreakable (default)\n   1.0 : vanilla\n   0.5 : 50% slower (lasts 2x longer)\n   2.0 : 2x faster");
			EnableMesaPickaxes = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMesaPickaxes", true, "If true, applies the configured break-speed behavior to mesa pickaxes (ShittyPiton).");
			MesaPickaxeBreakSpeedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MesaPickaxeBreakSpeedMultiplier", -1f, "Break-speed multiplier for mesa pickaxes (ShittyPiton). Same meaning as the piton multiplier.");
			ClientSidePersistence = ((BaseUnityPlugin)this).Config.Bind<bool>("Multiplayer", "ClientSidePersistence", false, "OFF (default) = multiplayer-safe: this mod respects break/detach RPCs from the host/owner.\nON = client-side persistence: ignore host break/detach RPCs locally and keep those objects alive on your client.\n⚠ This will desync you from other players on purpose.");
			_harmony = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
			_harmony.PatchAll();
			BreakableRopeAnchorPatches.ApplyToAllExisting();
			ShittyPitonPatches.ApplyToAllExisting();
			Log.LogInfo((object)("Loaded " + Name + "! " + $"Pitons: enabled={EnablePreplacedPitons.Value}, mult={PreplacedPitonBreakSpeedMultiplier.Value}. " + $"Pickaxes: enabled={EnableMesaPickaxes.Value}, mult={MesaPickaxeBreakSpeedMultiplier.Value}. " + $"ClientSidePersistence={ClientSidePersistence.Value}"));
		}

		private void OnDestroy()
		{
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			_harmony = null;
		}

		internal static float GetMultiplier(bool enabled, float mult)
		{
			if (!enabled)
			{
				return float.NaN;
			}
			if (float.IsNaN(mult) || float.IsInfinity(mult))
			{
				return -1f;
			}
			if (mult <= 0f)
			{
				return -1f;
			}
			return mult;
		}
	}
	[HarmonyPatch(typeof(BreakableRopeAnchor))]
	internal static class BreakableRopeAnchorPatches
	{
		private static FieldInfo? _willBreakInTime;

		private static FieldInfo? _photonView;

		private static FieldInfo? _anchor;

		private static FieldInfo? _isBreaking;

		private static void EnsureFields()
		{
			if ((object)_willBreakInTime == null)
			{
				_willBreakInTime = AccessTools.Field(typeof(BreakableRopeAnchor), "willBreakInTime");
			}
			if ((object)_photonView == null)
			{
				_photonView = AccessTools.Field(typeof(BreakableRopeAnchor), "photonView");
			}
			if ((object)_anchor == null)
			{
				_anchor = AccessTools.Field(typeof(BreakableRopeAnchor), "anchor");
			}
			if ((object)_isBreaking == null)
			{
				_isBreaking = AccessTools.Field(typeof(BreakableRopeAnchor), "isBreaking");
			}
		}

		internal static void ApplyToAllExisting()
		{
			BreakableRopeAnchor[] array = Resources.FindObjectsOfTypeAll<BreakableRopeAnchor>();
			foreach (BreakableRopeAnchor inst in array)
			{
				EnforceUnbreakableIfConfigured(inst);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix(BreakableRopeAnchor __instance)
		{
			EnforceUnbreakableIfConfigured(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch("Update")]
		private static void UpdatePrefix(BreakableRopeAnchor __instance)
		{
			EnsureFields();
			if (_willBreakInTime == null || _photonView == null || _anchor == null)
			{
				return;
			}
			float multiplier = Plugin.GetMultiplier(Plugin.EnablePreplacedPitons.Value, Plugin.PreplacedPitonBreakSpeedMultiplier.Value);
			if (float.IsNaN(multiplier))
			{
				return;
			}
			object? value = _photonView.GetValue(__instance);
			PhotonView val = (PhotonView)((value is PhotonView) ? value : null);
			bool flag = (Object)(object)val != (Object)null && val.IsMine;
			if (multiplier < 0f)
			{
				if (flag)
				{
					_willBreakInTime.SetValue(__instance, float.PositiveInfinity);
					if (_isBreaking != null && (bool)_isBreaking.GetValue(__instance))
					{
						((MonoBehaviour)__instance).StopAllCoroutines();
						_isBreaking.SetValue(__instance, false);
					}
				}
			}
			else
			{
				if (!flag || Mathf.Approximately(multiplier, 1f))
				{
					return;
				}
				object? value2 = _anchor.GetValue(__instance);
				RopeAnchorWithRope val2 = (RopeAnchorWithRope)((value2 is RopeAnchorWithRope) ? value2 : null);
				if ((Object)(object)val2?.rope == (Object)null)
				{
					return;
				}
				int num = 0;
				List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
				for (int i = 0; i < allPlayerCharacters.Count; i++)
				{
					Character val3 = allPlayerCharacters[i];
					if ((Object)(object)val3 != (Object)null && (Object)(object)val3.data != (Object)null && val3.data.isRopeClimbing && (Object)(object)val3.data.heldRope == (Object)(object)val2.rope)
					{
						num++;
					}
				}
				if (num > 0)
				{
					float num2 = (float)_willBreakInTime.GetValue(__instance);
					num2 += Time.deltaTime * (1f - multiplier);
					_willBreakInTime.SetValue(__instance, num2);
				}
			}
		}

		private static void EnforceUnbreakableIfConfigured(BreakableRopeAnchor inst)
		{
			EnsureFields();
			if (_willBreakInTime == null || _photonView == null)
			{
				return;
			}
			float multiplier = Plugin.GetMultiplier(Plugin.EnablePreplacedPitons.Value, Plugin.PreplacedPitonBreakSpeedMultiplier.Value);
			if (!float.IsNaN(multiplier) && multiplier < 0f)
			{
				object? value = _photonView.GetValue(inst);
				PhotonView val = (PhotonView)((value is PhotonView) ? value : null);
				if ((Object)(object)val != (Object)null && val.IsMine)
				{
					_willBreakInTime.SetValue(inst, float.PositiveInfinity);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ShittyPiton))]
	internal static class ShittyPitonPatches
	{
		private static FieldInfo? _totalSecondsOfHang;

		private static FieldInfo? _sinceCrack;

		private static FieldInfo? _isHung;

		private static FieldInfo? _isBreaking;

		private static FieldInfo? _disabled;

		private static FieldInfo? _crackScale;

		private static FieldInfo? _cracksToBreak;

		private static FieldInfo? _view;

		private static FieldInfo? _handle;

		private static void EnsureFields()
		{
			if ((object)_totalSecondsOfHang == null)
			{
				_totalSecondsOfHang = AccessTools.Field(typeof(ShittyPiton), "totalSecondsOfHang");
			}
			if ((object)_sinceCrack == null)
			{
				_sinceCrack = AccessTools.Field(typeof(ShittyPiton), "sinceCrack");
			}
			if ((object)_isHung == null)
			{
				_isHung = AccessTools.Field(typeof(ShittyPiton), "isHung");
			}
			if ((object)_isBreaking == null)
			{
				_isBreaking = AccessTools.Field(typeof(ShittyPiton), "isBreaking");
			}
			if ((object)_disabled == null)
			{
				_disabled = AccessTools.Field(typeof(ShittyPiton), "disabled");
			}
			if ((object)_crackScale == null)
			{
				_crackScale = AccessTools.Field(typeof(ShittyPiton), "crackScale");
			}
			if ((object)_cracksToBreak == null)
			{
				_cracksToBreak = AccessTools.Field(typeof(ShittyPiton), "cracksToBreak");
			}
			if ((object)_view == null)
			{
				_view = AccessTools.Field(typeof(ShittyPiton), "view");
			}
			if ((object)_handle == null)
			{
				_handle = AccessTools.Field(typeof(ShittyPiton), "handle");
			}
		}

		internal static void ApplyToAllExisting()
		{
			ShittyPiton[] array = Resources.FindObjectsOfTypeAll<ShittyPiton>();
			foreach (ShittyPiton inst in array)
			{
				EnforceUnbreakableIfConfigured(inst);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix(ShittyPiton __instance)
		{
			EnforceUnbreakableIfConfigured(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch("Update")]
		private static void UpdatePrefix(ShittyPiton __instance)
		{
			EnsureFields();
			if (_totalSecondsOfHang == null || _sinceCrack == null || _isHung == null || _isBreaking == null || _view == null)
			{
				return;
			}
			float multiplier = Plugin.GetMultiplier(Plugin.EnableMesaPickaxes.Value, Plugin.MesaPickaxeBreakSpeedMultiplier.Value);
			if (float.IsNaN(multiplier))
			{
				return;
			}
			object? value = _view.GetValue(__instance);
			PhotonView val = (PhotonView)((value is PhotonView) ? value : null);
			bool flag = (Object)(object)val != (Object)null && val.IsMine;
			if (multiplier < 0f)
			{
				if (flag)
				{
					_totalSecondsOfHang.SetValue(__instance, float.PositiveInfinity);
				}
				_isBreaking.SetValue(__instance, false);
				if (_disabled != null)
				{
					_disabled.SetValue(__instance, false);
				}
				if (_crackScale != null)
				{
					_crackScale.SetValue(__instance, 0f);
				}
				if (_sinceCrack != null)
				{
					_sinceCrack.SetValue(__instance, 0f);
				}
				if (_cracksToBreak != null)
				{
					_cracksToBreak.SetValue(__instance, 4);
				}
				try
				{
					if ((Object)(object)__instance.crack != (Object)null && __instance.crack.activeSelf)
					{
						__instance.crack.SetActive(false);
					}
					return;
				}
				catch
				{
					return;
				}
			}
			if (Mathf.Approximately(multiplier, 1f))
			{
				return;
			}
			bool flag2 = (bool)_isHung.GetValue(__instance);
			bool flag3 = (bool)_isBreaking.GetValue(__instance);
			float deltaTime = Time.deltaTime;
			if (flag3)
			{
				if (flag2)
				{
					float num = (float)_sinceCrack.GetValue(__instance);
					num += deltaTime * (multiplier - 1f);
					_sinceCrack.SetValue(__instance, num);
				}
			}
			else if (flag && flag2)
			{
				float num2 = (float)_totalSecondsOfHang.GetValue(__instance);
				num2 += deltaTime * (1f - multiplier);
				_totalSecondsOfHang.SetValue(__instance, num2);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("Crack")]
		private static bool CrackPrefix(ShittyPiton __instance)
		{
			float multiplier = Plugin.GetMultiplier(Plugin.EnableMesaPickaxes.Value, Plugin.MesaPickaxeBreakSpeedMultiplier.Value);
			if (float.IsNaN(multiplier) || multiplier >= 0f)
			{
				return true;
			}
			try
			{
				if ((Object)(object)((MonoBehaviourPun)__instance).photonView != (Object)null && ((MonoBehaviourPun)__instance).photonView.IsMine)
				{
					return false;
				}
			}
			catch
			{
			}
			return true;
		}

		private static void EnforceUnbreakableIfConfigured(ShittyPiton inst)
		{
			EnsureFields();
			if (_totalSecondsOfHang == null || _view == null)
			{
				return;
			}
			float multiplier = Plugin.GetMultiplier(Plugin.EnableMesaPickaxes.Value, Plugin.MesaPickaxeBreakSpeedMultiplier.Value);
			if (!float.IsNaN(multiplier) && multiplier < 0f)
			{
				object? value = _view.GetValue(inst);
				PhotonView val = (PhotonView)((value is PhotonView) ? value : null);
				if ((Object)(object)val != (Object)null && val.IsMine)
				{
					_totalSecondsOfHang.SetValue(inst, float.PositiveInfinity);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class ClientSidePersistencePatches
	{
		private static FieldInfo? _ropeAttachedToAnchor;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Rope), "Detach_Rpc")]
		private static bool Rope_Detach_Rpc_Prefix(Rope __instance, float segmentLength)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Invalid comparison between Unknown and I4
			if (!Plugin.ClientSidePersistence.Value)
			{
				return true;
			}
			if (!Plugin.EnablePreplacedPitons.Value)
			{
				return true;
			}
			if ((Object)(object)((MonoBehaviourPun)__instance).photonView != (Object)null && ((MonoBehaviourPun)__instance).photonView.IsMine)
			{
				return true;
			}
			if ((int)__instance.attachmenState != 2)
			{
				return true;
			}
			if ((object)_ropeAttachedToAnchor == null)
			{
				_ropeAttachedToAnchor = AccessTools.Field(typeof(Rope), "attachedToAnchor");
			}
			object? obj = _ropeAttachedToAnchor?.GetValue(__instance);
			RopeAnchor val = (RopeAnchor)((obj is RopeAnchor) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			if ((Object)(object)((Component)val).GetComponent<BreakableRopeAnchor>() != (Object)null)
			{
				return false;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(ShittyPiton), "RPCA_StartBreaking")]
		private static bool ShittyPiton_RPCA_StartBreaking_Prefix(ShittyPiton __instance)
		{
			if (!Plugin.ClientSidePersistence.Value)
			{
				return true;
			}
			if (!Plugin.EnableMesaPickaxes.Value)
			{
				return true;
			}
			if ((Object)(object)((MonoBehaviourPun)__instance).photonView != (Object)null && ((MonoBehaviourPun)__instance).photonView.IsMine)
			{
				return true;
			}
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(ShittyPiton), "RPCA_Break")]
		private static bool ShittyPiton_RPCA_Break_Prefix(ShittyPiton __instance)
		{
			if (!Plugin.ClientSidePersistence.Value)
			{
				return true;
			}
			if (!Plugin.EnableMesaPickaxes.Value)
			{
				return true;
			}
			if ((Object)(object)((MonoBehaviourPun)__instance).photonView != (Object)null && ((MonoBehaviourPun)__instance).photonView.IsMine)
			{
				return true;
			}
			return false;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}