Decompiled source of ExtendedCruiserMagnet v0.1.1

ExtendedCruiserMagnet/extendedcruisermagnet.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ExtendedCruiserMagnet")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1")]
[assembly: AssemblyProduct("ExtendedCruiserMagnet")]
[assembly: AssemblyTitle("ExtendedCruiserMagnet")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 ExtendedCruiserMagnet
{
	[BepInPlugin("achachala.extendedcruisermagnet", "Extended Cruiser Magnet", "0.1.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "achachala.extendedcruisermagnet";

		public const string Version = "0.1.1";

		private static ManualLogSource log;

		private Harmony harmony;

		private static int patchedChecks;

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			log = ((BaseUnityPlugin)this).Logger;
			patchedChecks = 0;
			harmony = new Harmony("achachala.extendedcruisermagnet");
			HarmonyMethod val = new HarmonyMethod(typeof(Plugin), "ExtendRange", (Type[])null)
			{
				priority = 0
			};
			try
			{
				string[] array = new string[3] { "Update", "FixedUpdate", "LateUpdate" };
				foreach (string text in array)
				{
					MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(VehicleController), text, (Type[])null, (Type[])null);
					if (methodInfo != null)
					{
						harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null);
					}
				}
				if (patchedChecks == 0)
				{
					harmony.UnpatchSelf();
					((BaseUnityPlugin)this).Logger.LogError((object)"No compatible Cruiser magnet capture check was found. Range has NOT been changed. Send BepInEx/LogOutput.log with the game version and vehicle mods.");
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("Extended Cruiser Magnet {0} loaded: 4x capture range ({1} checks). Install on host AND all clients. Existing line-of-sight and attachment rules still apply.", "0.1.1", patchedChecks));
				}
			}
			catch (Exception ex)
			{
				harmony.UnpatchSelf();
				((BaseUnityPlugin)this).Logger.LogError((object)("Could not patch Cruiser magnet range; changes removed: " + ex));
			}
		}

		private static IEnumerable<CodeInstruction> ExtendRange(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
		{
			List<CodeInstruction> list = instructions.ToList();
			foreach (RangeChange item in RangeScanner.Find(list.Select(Project).ToArray()))
			{
				list[item.Index].operand = item.Replacement;
				patchedChecks++;
				log.LogInfo((object)$"Extended magnet capture check in {__originalMethod.DeclaringType?.Name}.{__originalMethod.Name}: {item.Original} -> {item.Replacement} (distance threshold; squared thresholds scale by 16).");
			}
			return list;
		}

		private static ScanInstruction Project(CodeInstruction instruction)
		{
			string text = instruction.opcode.Name ?? "";
			string member = ((instruction.operand is MemberInfo memberInfo) ? (memberInfo.DeclaringType?.FullName + "." + memberInfo.Name) : "");
			string local = "";
			if (text.StartsWith("ldloc", StringComparison.Ordinal) || text.StartsWith("stloc", StringComparison.Ordinal))
			{
				if (instruction.operand is LocalBuilder { LocalIndex: var localIndex })
				{
					local = localIndex.ToString();
				}
				else if (instruction.operand != null)
				{
					local = instruction.operand.ToString();
				}
				else if (text.Length > 6)
				{
					local = text.Substring(6);
				}
			}
			return new ScanInstruction(text, member, (instruction.operand is float num) ? num : 0f, local);
		}
	}
	internal readonly struct ScanInstruction
	{
		internal readonly string Op;

		internal readonly string Member;

		internal readonly string Local;

		internal readonly float Number;

		internal ScanInstruction(string op, string member = "", float number = 0f, string local = "")
		{
			Op = op;
			Member = member;
			Number = number;
			Local = local;
		}
	}
	internal readonly struct RangeChange
	{
		internal readonly int Index;

		internal readonly float Original;

		internal readonly float Replacement;

		internal RangeChange(int index, float original, float replacement)
		{
			Index = index;
			Original = original;
			Replacement = replacement;
		}
	}
	internal static class RangeScanner
	{
		internal const float Multiplier = 4f;

		internal static List<RangeChange> Find(IReadOnlyList<ScanInstruction> code)
		{
			List<RangeChange> list = new List<RangeChange>();
			bool flag = false;
			foreach (ScanInstruction item in code)
			{
				if (item.Member == "VehicleController.StartMagneting")
				{
					flag = true;
				}
			}
			if (!flag)
			{
				return list;
			}
			for (int i = 0; i < code.Count; i++)
			{
				bool flag2 = code[i].Member == "UnityEngine.Vector3.get_sqrMagnitude";
				if (!flag2 && code[i].Member != "UnityEngine.Vector3.Distance" && code[i].Member != "UnityEngine.Vector3.get_magnitude")
				{
					continue;
				}
				bool flag3 = false;
				int num = i - 1;
				while (num >= 0 && num >= i - 20)
				{
					ScanInstruction scanInstruction = code[num];
					if (scanInstruction.Op.StartsWith("b", StringComparison.Ordinal) || scanInstruction.Op == "ret" || scanInstruction.Member == "UnityEngine.Vector3.Distance" || scanInstruction.Member == "UnityEngine.Vector3.get_magnitude" || scanInstruction.Member == "UnityEngine.Vector3.get_sqrMagnitude")
					{
						break;
					}
					if (scanInstruction.Op == "ldfld" && scanInstruction.Member == "StartOfRound.magnetPoint")
					{
						flag3 = true;
						break;
					}
					num--;
				}
				if (!flag3)
				{
					continue;
				}
				int num2 = SkipNops(code, i + 1);
				if (num2 < code.Count && code[num2].Op.StartsWith("stloc", StringComparison.Ordinal))
				{
					ScanInstruction scanInstruction2 = code[num2];
					num2 = SkipNops(code, num2 + 1);
					if (num2 >= code.Count || !code[num2].Op.StartsWith("ldloc", StringComparison.Ordinal) || code[num2].Local != scanInstruction2.Local)
					{
						continue;
					}
					num2 = SkipNops(code, num2 + 1);
				}
				if (num2 >= code.Count || code[num2].Op != "ldc.r4")
				{
					continue;
				}
				float number = code[num2].Number;
				if (number <= 0f || float.IsNaN(number) || float.IsInfinity(number))
				{
					continue;
				}
				int num3 = SkipNops(code, num2 + 1);
				if (num3 < code.Count && IsRangeComparison(code[num3].Op))
				{
					float num4 = number * (flag2 ? 16f : 4f);
					if (!float.IsInfinity(num4))
					{
						list.Add(new RangeChange(num2, number, num4));
					}
				}
			}
			return list;
		}

		private static int SkipNops(IReadOnlyList<ScanInstruction> code, int index)
		{
			while (index < code.Count && code[index].Op == "nop")
			{
				index++;
			}
			return index;
		}

		private static bool IsRangeComparison(string op)
		{
			if (!op.StartsWith("bge", StringComparison.Ordinal) && !op.StartsWith("bgt", StringComparison.Ordinal) && !op.StartsWith("ble", StringComparison.Ordinal) && !op.StartsWith("blt", StringComparison.Ordinal) && !op.StartsWith("clt", StringComparison.Ordinal))
			{
				return op.StartsWith("cgt", StringComparison.Ordinal);
			}
			return true;
		}
	}
}