Decompiled source of LaserCutterImprovements v1.0.1

LaserCutterImprovements.dll

Decompiled a day ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.Engi.EngiWeapon;
using IL.EntityStates.Engi.EngiWeapon;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using On.EntityStates.Engi.EngiWeapon;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
using UnityEngine;
using UnityEngine.Rendering;

[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("LaserCutterImprovements")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("LaserCutterImprovements")]
[assembly: AssemblyTitle("LaserCutterImprovements")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.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 LaserCutterImprovements
{
	internal static class EmbeddedSprites
	{
		public static Sprite Load(string resourceName)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			byte[] array;
			using (Stream stream = typeof(EmbeddedSprites).Assembly.GetManifestResourceStream(resourceName))
			{
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				array = memoryStream.ToArray();
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			ImageConversion.LoadImage(val, array);
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Object)val).name = resourceName;
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
		}
	}
	[BepInPlugin("revor.LaserCutterImprovements", "LaserCutterImprovements", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class LaserCutterImprovementsPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "revor.LaserCutterImprovements";

		public const string PluginName = "LaserCutterImprovements";

		public const string PluginVersion = "1.0.1";

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			PluginConfig.Init(((BaseUnityPlugin)this).Config);
			LaserHooks.Init();
			if (RiskOfOptionsCompat.IsInstalled)
			{
				RiskOfOptionsCompat.Init();
			}
		}
	}
	internal static class LaserHits
	{
		private static readonly FilterCallback filterCallback = new FilterCallback(Filter);

		private static readonly HitCallback hitCallback = new HitCallback(Hit);

		private static readonly HitCallback probeHitCallback = new HitCallback(ProbeHit);

		private static readonly BulletAttack probe = new BulletAttack();

		private static Vector3? probeStop;

		public static void Configure(BulletAttack attack)
		{
			attack.filterCallback = filterCallback;
			attack.hitCallback = hitCallback;
		}

		public static bool Probe(EngiLaserCutter laser, Ray aimRay, out Vector3 end)
		{
			//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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			probe.Reset();
			probe.owner = ((EntityState)laser).gameObject;
			probe.weapon = ((EntityState)laser).gameObject;
			probe.origin = ((Ray)(ref aimRay)).origin;
			probe.aimVector = ((Ray)(ref aimRay)).direction;
			probe.maxDistance = laser.laserDistance;
			probe.radius = laser.laserRadius;
			probe.smartCollision = true;
			probe.filterCallback = filterCallback;
			probe.hitCallback = probeHitCallback;
			probeStop = null;
			probe.Fire();
			end = (Vector3)(((??)probeStop) ?? (probe.origin + probe.aimVector * probe.maxDistance));
			return probeStop.HasValue;
		}

		private static bool Filter(BulletAttack attack, ref BulletHit hit)
		{
			if (!BulletAttack.defaultFilterCallback.Invoke(attack, ref hit))
			{
				return false;
			}
			float value = PluginConfig.TurretHitboxScale.Value;
			if (!(value >= 1f) && IsAlliedTurret(attack, hit.hitHurtBox))
			{
				return InScaledHitbox(attack, hit, value);
			}
			return true;
		}

		private static bool Hit(BulletAttack attack, ref BulletHit hit)
		{
			if (!BulletAttack.defaultHitCallback.Invoke(attack, ref hit))
			{
				if (PluginConfig.HealAndDamage.Value)
				{
					return IsHealedAlly(attack, hit.hitHurtBox);
				}
				return false;
			}
			return true;
		}

		private static bool ProbeHit(BulletAttack attack, ref BulletHit hit)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			int num;
			if (((1 << ((Component)hit.collider).gameObject.layer) & LayerMask.op_Implicit(attack.stopperMask)) != 0)
			{
				if (PluginConfig.HealAndDamage.Value)
				{
					num = (IsHealedAlly(attack, hit.hitHurtBox) ? 1 : 0);
					if (num != 0)
					{
						goto IL_008e;
					}
				}
				else
				{
					num = 0;
				}
				Vector3 value;
				if (hit.distance != 0f || !Object.op_Implicit((Object)(object)hit.hitHurtBox))
				{
					value = hit.point;
				}
				else
				{
					Bounds bounds = hit.hitHurtBox.collider.bounds;
					value = ((Bounds)(ref bounds)).center;
				}
				probeStop = value;
			}
			else
			{
				num = 1;
			}
			goto IL_008e;
			IL_008e:
			return (byte)num != 0;
		}

		private static bool IsHealedAlly(BulletAttack attack, HurtBox hurtBox)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)hurtBox) || !Object.op_Implicit((Object)(object)hurtBox.healthComponent))
			{
				return false;
			}
			CharacterBody body = hurtBox.healthComponent.body;
			if ((body.bodyFlags & 2) != 0)
			{
				return body.teamComponent.teamIndex == TeamComponent.GetObjectTeam(attack.owner);
			}
			return false;
		}

		private static bool IsAlliedTurret(BulletAttack attack, HurtBox hurtBox)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)hurtBox) || !Object.op_Implicit((Object)(object)hurtBox.healthComponent))
			{
				return false;
			}
			CharacterBody body = hurtBox.healthComponent.body;
			if (body.bodyIndex == BodyPrefabs.EngiTurretBody.bodyIndex || body.bodyIndex == BodyPrefabs.EngiWalkerTurretBody.bodyIndex)
			{
				return body.teamComponent.teamIndex == TeamComponent.GetObjectTeam(attack.owner);
			}
			return false;
		}

		private static bool InScaledHitbox(BulletAttack attack, BulletHit hit, float scale)
		{
			//IL_001e: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			HurtBox[] hurtBoxes = hit.hitHurtBox.hurtBoxGroup.hurtBoxes;
			foreach (HurtBox obj in hurtBoxes)
			{
				Bounds bounds = obj.collider.bounds;
				Vector3 center = ((Bounds)(ref bounds)).center;
				Vector3 val = center + (((Ray)(ref hit.ray)).origin - center) / scale;
				if (Distance(end: val + ((Ray)(ref hit.ray)).direction * (attack.maxDistance / scale), collider: obj.collider, start: val) <= attack.radius)
				{
					return true;
				}
			}
			return false;
		}

		private static float Distance(Collider collider, Vector3 start, Vector3 end)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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)
			//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_001a: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			Bounds bounds = collider.bounds;
			Vector3 val = ClosestOnSegment(start, end, ((Bounds)(ref bounds)).center);
			for (int i = 0; i < 4; i++)
			{
				val = ClosestOnSegment(start, end, collider.ClosestPoint(val));
			}
			return Vector3.Distance(val, collider.ClosestPoint(val));
		}

		private static Vector3 ClosestOnSegment(Vector3 start, Vector3 end, Vector3 point)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = end - start;
			float num = Mathf.Clamp01(Vector3.Dot(point - start, val) / ((Vector3)(ref val)).sqrMagnitude);
			return start + num * val;
		}
	}
	internal static class LaserHooks
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Manipulator <0>__EngiLaserCutter_FireLaser;

			public static hook_UpdateLaser <1>__EngiLaserCutter_UpdateLaser;

			public static Action<BulletAttack, EngiLaserCutter> <2>__ConfigurePlayerBeam;
		}

		public static void Init()
		{
			//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_001b: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			object obj = <>O.<0>__EngiLaserCutter_FireLaser;
			if (obj == null)
			{
				Manipulator val = EngiLaserCutter_FireLaser;
				<>O.<0>__EngiLaserCutter_FireLaser = val;
				obj = (object)val;
			}
			EngiLaserCutter.FireLaser += (Manipulator)obj;
			object obj2 = <>O.<1>__EngiLaserCutter_UpdateLaser;
			if (obj2 == null)
			{
				hook_UpdateLaser val2 = EngiLaserCutter_UpdateLaser;
				<>O.<1>__EngiLaserCutter_UpdateLaser = val2;
				obj2 = (object)val2;
			}
			EngiLaserCutter.UpdateLaser += (hook_UpdateLaser)obj2;
		}

		private static void EngiLaserCutter_FireLaser(ILContext il)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			ILCursor val = new ILCursor(il);
			if (!val.TryGotoNext(new Func<Instruction, bool>[1]
			{
				(Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<BulletAttack>(x, "Fire")
			}))
			{
				LaserCutterImprovementsPlugin.Log.LogError((object)("IL hook " + ((MemberReference)il.Method).Name + " failed: BulletAttack.Fire not found"));
				return;
			}
			val.Emit(OpCodes.Dup);
			val.Emit(OpCodes.Ldarg_0);
			val.EmitDelegate<Action<BulletAttack, EngiLaserCutter>>((Action<BulletAttack, EngiLaserCutter>)ConfigurePlayerBeam);
		}

		private static void ConfigurePlayerBeam(BulletAttack attack, EngiLaserCutter laser)
		{
			if (((EntityState)laser).characterBody.isPlayerControlled)
			{
				LaserHits.Configure(attack);
			}
		}

		private static void EngiLaserCutter_UpdateLaser(orig_UpdateLaser orig, EngiLaserCutter self, Ray aimRay)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			orig.Invoke(self, aimRay);
			bool value = PluginConfig.BeamStopsAtTarget.Value;
			bool value2 = PluginConfig.RangeIndicator.Value;
			if (!((EntityState)self).isAuthority || !((EntityState)self).characterBody.isPlayerControlled || (!value && !value2))
			{
				return;
			}
			Vector3 end;
			bool flag = LaserHits.Probe(self, aimRay, out end);
			if (value)
			{
				self.laserEndPoint = end;
				if (Object.op_Implicit((Object)(object)self.laserEndL))
				{
					self.laserEndL.position = end;
				}
				if (Object.op_Implicit((Object)(object)self.laserEndR))
				{
					self.laserEndR.position = end;
				}
			}
			if (value2 && !flag)
			{
				RangeIndicator.Show(((EntityState)self).characterBody, ((Ray)(ref aimRay)).origin, end - ((Ray)(ref aimRay)).origin, self.laserDistance);
			}
		}
	}
	internal static class PluginConfig
	{
		private const string Section = "General";

		public static ConfigEntry<bool> RangeIndicator { get; private set; }

		public static ConfigEntry<bool> BeamStopsAtTarget { get; private set; }

		public static ConfigEntry<float> TurretHitboxScale { get; private set; }

		public static ConfigEntry<bool> HealAndDamage { get; private set; }

		public static void Init(ConfigFile config)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			RangeIndicator = config.Bind<bool>("General", "RangeIndicator", true, "While your Laser Cutter reaches its maximum range without hitting anything, show a faint part of its range sphere ahead of you and a line on the ground where the range ends.");
			BeamStopsAtTarget = config.Bind<bool>("General", "BeamStopsAtTarget", true, "Your Laser Cutter's beam ends where the attack stops (for example at an ally it heals) instead of continuing past it.");
			TurretHitboxScale = config.Bind<float>("General", "TurretHitboxScale", 1f, new ConfigDescription("The size of allied Engineer turrets' hitbox for your Laser Cutter, so the beam heals a turret only when you aim at it, not at an enemy next to it. 1 = the game's (100%), 0.5 = half. Enemies, drones and MUL-T keep the game's hitbox.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>()));
			HealAndDamage = config.Bind<bool>("General", "HealAndDamage", false, "Your Laser Cutter heals a mechanical ally (turrets, drones, MUL-T) and goes on through it to damage what is behind it. In the game, healing an ally stops the beam there.");
		}
	}
	internal sealed class RangeIndicator : MonoBehaviour
	{
		private const float HalfWidth = 25f;

		private const float AboveAim = 15f;

		private const int Columns = 24;

		private const int Rows = 24;

		private const float FadeTime = 0.15f;

		private const float BandAlpha = 0.12f;

		private const float LineAlpha = 0.9f;

		private const float LineWidth = 0.4f;

		private const float LineStep = 2.5f;

		private const int LineSide = 10;

		private const float WalkStep = 10f;

		private const float WalkBack = 20f;

		private const float LowestElevation = -89f;

		private const float SoftFade = 20f;

		private const string TintColor = "_TintColor";

		private const float GroundOffset = 0.3f;

		private static readonly Color IndicatorColor = new Color(1f, 0.6f, 0.2f);

		private static Material template;

		private GameObject sphere;

		private GameObject lineObject;

		private LineRenderer line;

		private Material material;

		private Mesh mesh;

		private readonly Vector3[] vertices = (Vector3[])(object)new Vector3[625];

		private readonly Color[] colors = (Color[])(object)new Color[625];

		private readonly Vector3[] linePositions = (Vector3[])(object)new Vector3[21];

		private bool hasLine;

		private float alpha;

		private int shownFrame = -1;

		public static void Show(CharacterBody body, Vector3 origin, Vector3 direction, float range)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			RangeIndicator rangeIndicator = default(RangeIndicator);
			if (!((Component)body).TryGetComponent<RangeIndicator>(ref rangeIndicator))
			{
				rangeIndicator = ((Component)body).gameObject.AddComponent<RangeIndicator>();
			}
			rangeIndicator.Place(origin, direction, range);
		}

		private void Awake()
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Expected O, but got Unknown
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Expected O, but got Unknown
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Expected O, but got Unknown
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)template))
			{
				template = new Material(LegacyShaderAPI.Find("Hopoo Games/FX/Cloud Remap"));
				template.SetFloat("_SrcBlend", 5f);
				template.SetFloat("_DstBlend", 10f);
				template.SetTexture("_MainTex", (Texture)(object)Texture2D.whiteTexture);
				template.SetFloat("_InvFade", 20f);
				SetToggle(template, "_DisableRemapOn", "DISABLEREMAP", on: true);
				SetToggle(template, "_CloudsOn", "USE_CLOUDS", on: false);
				SetToggle(template, "_VertexColorOn", "VERTEXCOLOR", on: true);
				SetToggle(template, "_VertexAlphaOn", "VERTEXALPHA", on: true);
			}
			material = new Material(template);
			mesh = new Mesh
			{
				name = "LaserCutterRangeIndicator"
			};
			mesh.MarkDynamic();
			mesh.vertices = vertices;
			int[] array = new int[3456];
			int num = 0;
			for (int i = 0; i < 24; i++)
			{
				for (int j = 0; j < 24; j++)
				{
					int num2 = i * 25 + j;
					array[num++] = num2;
					array[num++] = num2 + 24 + 1;
					array[num++] = num2 + 1;
					array[num++] = num2 + 1;
					array[num++] = num2 + 24 + 1;
					array[num++] = num2 + 24 + 2;
				}
			}
			mesh.triangles = array;
			sphere = new GameObject("LaserCutterRangeIndicator");
			sphere.AddComponent<MeshFilter>().sharedMesh = mesh;
			MeshRenderer obj = sphere.AddComponent<MeshRenderer>();
			((Renderer)obj).sharedMaterial = material;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)obj).receiveShadows = false;
			sphere.SetActive(false);
			lineObject = new GameObject("LaserCutterRangeLine");
			line = lineObject.AddComponent<LineRenderer>();
			((Renderer)line).sharedMaterial = material;
			line.useWorldSpace = true;
			line.widthMultiplier = 0.4f;
			line.alignment = (LineAlignment)0;
			((Renderer)line).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)line).receiveShadows = false;
			line.numCapVertices = 2;
			Gradient val = new Gradient();
			val.SetKeys((GradientColorKey[])(object)new GradientColorKey[2]
			{
				new GradientColorKey(Color.white, 0f),
				new GradientColorKey(Color.white, 1f)
			}, (GradientAlphaKey[])(object)new GradientAlphaKey[4]
			{
				new GradientAlphaKey(0f, 0f),
				new GradientAlphaKey(0.9f, 0.2f),
				new GradientAlphaKey(0.9f, 0.8f),
				new GradientAlphaKey(0f, 1f)
			});
			line.colorGradient = val;
			lineObject.SetActive(false);
		}

		private static void SetToggle(Material material, string property, string keyword, bool on)
		{
			material.SetFloat(property, on ? 1f : 0f);
			if (on)
			{
				material.EnableKeyword(keyword);
			}
			else
			{
				material.DisableKeyword(keyword);
			}
		}

		private void Place(Vector3 origin, Vector3 direction, float range)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			shownFrame = Time.frameCount;
			Vector3 val = Vector3.ProjectOnPlane(direction, Vector3.up);
			if (((Vector3)(ref val)).sqrMagnitude < 1E-06f)
			{
				return;
			}
			float num = Mathf.Min(90f - Vector3.Angle(Vector3.up, direction) + 15f, 90f);
			for (int i = 0; i <= 24; i++)
			{
				float num2 = Mathf.Lerp(-90f, num, (float)i / 24f);
				float num3 = Mathf.SmoothStep(0f, 1f, (num - num2) / 15f);
				for (int j = 0; j <= 24; j++)
				{
					float num4 = Mathf.Lerp(-1f, 1f, (float)j / 24f);
					Vector3 val2 = Quaternion.Euler(0f - num2, num4 * 25f, 0f) * Vector3.forward;
					int num5 = i * 25 + j;
					vertices[num5] = val2;
					colors[num5] = new Color(1f, 1f, 1f, 0.12f * num3 * (1f - num4 * num4));
				}
			}
			mesh.vertices = vertices;
			mesh.normals = vertices;
			mesh.colors = colors;
			mesh.RecalculateBounds();
			Quaternion val3 = Quaternion.LookRotation(val);
			sphere.transform.SetPositionAndRotation(origin, val3);
			sphere.transform.localScale = new Vector3(range, range, range);
			PlaceLine(origin, val3, range, num);
		}

		private void PlaceLine(Vector3 origin, Quaternion aim, float range, float top)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			hasLine = FindGround(origin, aim, range, 0f, top, out linePositions[10], out var elevation);
			if (hasLine)
			{
				int num = 10;
				int i = 10;
				float elevation2;
				for (elevation2 = elevation; i < linePositions.Length - 1 && FindGround(origin, aim, range, (float)(i + 1 - 10) * 2.5f, Mathf.Min(elevation2 + 20f, top), out linePositions[i + 1], out elevation2); i++)
				{
				}
				elevation2 = elevation;
				while (num > 0 && FindGround(origin, aim, range, (float)(num - 1 - 10) * 2.5f, Mathf.Min(elevation2 + 20f, top), out linePositions[num - 1], out elevation2))
				{
					num--;
				}
				int num2 = i - num + 1;
				hasLine = num2 >= 2;
				if (hasLine)
				{
					Array.Copy(linePositions, num, linePositions, 0, num2);
					line.positionCount = num2;
					line.SetPositions(linePositions);
				}
			}
		}

		private static bool FindGround(Vector3 origin, Quaternion aim, float range, float yaw, float startElevation, out Vector3 ground, out float elevation)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = SpherePoint(origin, aim, range, yaw, startElevation);
			elevation = startElevation;
			RaycastHit val3 = default(RaycastHit);
			while (elevation > -89f)
			{
				elevation = Mathf.Max(elevation - 10f, -89f);
				Vector3 val2 = SpherePoint(origin, aim, range, yaw, elevation);
				if (Physics.Linecast(val, val2, ref val3, LayerMask.op_Implicit(((LayerIndex)(ref LayerIndex.world)).mask), (QueryTriggerInteraction)1))
				{
					ground = ((RaycastHit)(ref val3)).point + ((RaycastHit)(ref val3)).normal * 0.3f;
					return true;
				}
				val = val2;
			}
			ground = default(Vector3);
			return false;
		}

		private static Vector3 SpherePoint(Vector3 origin, Quaternion aim, float range, float yaw, float elevation)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: 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)
			//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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			return origin + aim * (Quaternion.Euler(0f - elevation, yaw, 0f) * Vector3.forward) * range;
		}

		private void LateUpdate()
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			alpha = Mathf.MoveTowards(alpha, (shownFrame == Time.frameCount) ? 1f : 0f, Time.deltaTime / 0.15f);
			sphere.SetActive(alpha > 0f);
			lineObject.SetActive(alpha > 0f && hasLine);
			material.SetColor("_TintColor", new Color(IndicatorColor.r, IndicatorColor.g, IndicatorColor.b, alpha));
		}

		private void OnDestroy()
		{
			Object.Destroy((Object)(object)sphere);
			Object.Destroy((Object)(object)lineObject);
			Object.Destroy((Object)(object)material);
			Object.Destroy((Object)(object)mesh);
		}
	}
	internal static class RiskOfOptionsCompat
	{
		public const string Guid = "com.rune580.riskofoptions";

		private const string IconResource = "LaserCutterImprovements.icon.png";

		public static bool IsInstalled => Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions");

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static void Init()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_003c: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			ModSettingsManager.SetModDescription("Changes to the Engineer's Laser Cutter: a range indicator at maximum range, a beam that ends where it hits, a smaller turret hitbox for your beam, and healing allies while damaging what is behind them. Only your own Laser Cutter changes, and nobody else needs the mod.");
			ModSettingsManager.SetModIcon(EmbeddedSprites.Load("LaserCutterImprovements.icon.png"));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(PluginConfig.RangeIndicator));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(PluginConfig.BeamStopsAtTarget));
			ModSettingsManager.AddOption((BaseOption)new StepSliderOption(PluginConfig.TurretHitboxScale, new StepSliderConfig
			{
				min = 0.1f,
				max = 1f,
				increment = 0.05f,
				FormatString = "{0:0%}"
			}));
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(PluginConfig.HealAndDamage));
		}
	}
}