Decompiled source of Piercer Wallbang v1.0.0

PiercerWallbang.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PluginConfig.API;
using PluginConfig.API.Fields;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("PiercerWallbang")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PiercerWallbang")]
[assembly: AssemblyTitle("PiercerWallbang")]
[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 PiercerWallbang
{
	[BepInPlugin("codex.ultrakill.piercerwallbang", "Piercer Wallbang", "1.0.0")]
	[BepInProcess("ULTRAKILL.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string ModGuid = "codex.ultrakill.piercerwallbang";

		public const string ModName = "Piercer Wallbang";

		public const string ModVersion = "1.0.0";

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> MaxDistance;

		internal static ConfigEntry<float> StandardDamage;

		internal static ConfigEntry<float> SlabDamage;

		internal static ConfigEntry<float> Force;

		internal static ConfigEntry<float> TraceRadius;

		internal static ConfigEntry<bool> HitEachEnemyOnce;

		internal static ConfigEntry<bool> RequireWallBeforeEnemy;

		internal static ConfigEntry<bool> DebugLogging;

		internal static ManualLogSource Log;

		private Harmony harmony;

		private PluginConfigurator pluginConfigurator;

		private BoolField enabledField;

		private void Awake()
		{
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enables the Piercer charged-shot wallbang behavior.");
			MaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MaxDistance", 10000f, "Maximum wallbang ray distance.");
			StandardDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "StandardPiercerDamage", 3f, "Damage applied to enemies behind walls by the standard Piercer charged shot.");
			SlabDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "SlabPiercerDamage", 5f, "Damage applied to enemies behind walls by the Slab Piercer charged shot.");
			Force = ((BaseUnityPlugin)this).Config.Bind<float>("Damage", "Force", 10000f, "Force applied in the shot direction when wallbang damage is delivered.");
			TraceRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "TraceRadius", 0.35f, "Radius around the charged shot ray used to catch enemy hitboxes behind walls.");
			HitEachEnemyOnce = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "HitEachEnemyOnce", true, "Prevents multiple colliders on one enemy from causing duplicate damage from one wallbang shot.");
			RequireWallBeforeEnemy = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "RequireWallBeforeEnemy", true, "When enabled, only enemies behind at least one blocking collider are damaged.");
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", false, "Logs wallbang ray hits to BepInEx/LogOutput.log.");
			harmony = new Harmony("codex.ultrakill.piercerwallbang");
			harmony.PatchAll();
			CreatePluginConfiguratorMenu();
			Log.LogInfo((object)"Piercer Wallbang 1.0.0 loaded.");
		}

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

		private void CreatePluginConfiguratorMenu()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			try
			{
				pluginConfigurator = PluginConfigurator.Create("Piercer Wallbang", "codex.ultrakill.piercerwallbang");
				pluginConfigurator.saveToFile = false;
				enabledField = new BoolField(pluginConfigurator.rootPanel, "Enabled", "enabled", Enabled.Value, false);
				enabledField.onValueChange += (BoolValueChangeEventDelegate)delegate(BoolValueChangeEvent data)
				{
					Enabled.Value = data.value;
					((BaseUnityPlugin)this).Config.Save();
				};
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("PluginConfigurator menu was not created: " + ex.Message));
			}
		}

		internal static bool IsPlayerOrWeaponCollider(Collider collider)
		{
			if ((Object)(object)collider == (Object)null)
			{
				return true;
			}
			if ((Object)(object)((Component)collider).GetComponentInParent<NewMovement>() != (Object)null)
			{
				return true;
			}
			WeaponIdentifier componentInParent = ((Component)collider).GetComponentInParent<WeaponIdentifier>();
			return (Object)(object)componentInParent != (Object)null;
		}
	}
	[HarmonyPatch(typeof(Revolver), "Shoot")]
	internal static class RevolverShootPatch
	{
		private struct ShotState
		{
			public bool ShouldWallbang;

			public bool IsSlab;

			public float Charge;

			public bool PierceReady;

			public int ShotType;

			public GameObject SourceWeapon;
		}

		private static void Prefix(Revolver __instance, int shotType, out ShotState __state)
		{
			__state = default(ShotState);
			if (!Plugin.Enabled.Value || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			bool value = Traverse.Create((object)__instance).Field("pierceReady").GetValue<bool>();
			__state.ShouldWallbang = __instance.gunVariation == 0 && shotType == 2;
			__state.IsSlab = __instance.altVersion;
			__state.Charge = __instance.pierceShotCharge;
			__state.PierceReady = value;
			__state.ShotType = shotType;
			try
			{
				__state.SourceWeapon = MonoSingleton<GunControl>.Instance?.currentWeapon;
			}
			catch
			{
				__state.SourceWeapon = ((Component)__instance).gameObject;
			}
		}

		private static void Postfix(Revolver __instance, int shotType, ShotState __state)
		{
			if (!__state.ShouldWallbang)
			{
				if (Plugin.DebugLogging.Value && (Object)(object)__instance != (Object)null && __instance.gunVariation == 0)
				{
					Plugin.Log.LogInfo((object)$"Piercer shot ignored. shotType={shotType}, charge={__state.Charge:F2}, ready={__state.PierceReady}, slab={__state.IsSlab}");
				}
				return;
			}
			if (Plugin.DebugLogging.Value)
			{
				Plugin.Log.LogInfo((object)$"Piercer wallbang trace started. shotType={__state.ShotType}, charge={__state.Charge:F2}, ready={__state.PierceReady}, slab={__state.IsSlab}");
			}
			FireWallbang(__instance, __state);
		}

		private static void FireWallbang(Revolver revolver, ShotState state)
		{
			//IL_0083: 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)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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_00d8: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_033c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			Camera val = Traverse.Create((object)revolver).Field("cam").GetValue<Camera>() ?? Camera.main;
			if ((Object)(object)val == (Object)null)
			{
				CameraController instance = MonoSingleton<CameraController>.Instance;
				val = (((Object)(object)instance != (Object)null && (Object)(object)instance.cam != (Object)null) ? instance.cam : null);
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Could not find a camera for Piercer wallbang ray.");
				return;
			}
			Vector3 position = ((Component)val).transform.position;
			Vector3 forward = ((Component)val).transform.forward;
			float num = Mathf.Max(1f, Plugin.MaxDistance.Value);
			float num2 = Mathf.Max(0f, Plugin.TraceRadius.Value);
			RaycastHit[] array = ((num2 > 0f) ? Physics.SphereCastAll(position, num2, forward, num, -1, (QueryTriggerInteraction)2) : Physics.RaycastAll(position, forward, num, -1, (QueryTriggerInteraction)2));
			if (array == null || array.Length == 0)
			{
				if (Plugin.DebugLogging.Value)
				{
					Plugin.Log.LogInfo((object)"Piercer wallbang trace found no colliders.");
				}
				return;
			}
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			if (Plugin.DebugLogging.Value)
			{
				Plugin.Log.LogInfo((object)$"Piercer wallbang trace found {array.Length} colliders.");
			}
			float num3 = (state.IsSlab ? Plugin.SlabDamage.Value : Plugin.StandardDamage.Value);
			Vector3 val2 = forward * Plugin.Force.Value;
			HashSet<EnemyIdentifier> hashSet = new HashSet<EnemyIdentifier>();
			bool flag = false;
			RaycastHit[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				RaycastHit val3 = array2[i];
				if ((Object)(object)((RaycastHit)(ref val3)).collider == (Object)null)
				{
					continue;
				}
				EnemyIdentifier enemy = GetEnemy(((RaycastHit)(ref val3)).collider);
				if ((Object)(object)enemy == (Object)null)
				{
					if (!Plugin.IsPlayerOrWeaponCollider(((RaycastHit)(ref val3)).collider) && !((RaycastHit)(ref val3)).collider.isTrigger)
					{
						flag = true;
						if (Plugin.DebugLogging.Value)
						{
							Plugin.Log.LogInfo((object)$"Wallbang blocker: {((Object)((RaycastHit)(ref val3)).collider).name} layer={((Component)((RaycastHit)(ref val3)).collider).gameObject.layer} distance={((RaycastHit)(ref val3)).distance:F2}");
						}
					}
				}
				else
				{
					if ((Object)(object)enemy == (Object)null || enemy.dead)
					{
						continue;
					}
					if (Plugin.RequireWallBeforeEnemy.Value && !flag)
					{
						if (Plugin.DebugLogging.Value)
						{
							Plugin.Log.LogInfo((object)("Enemy " + ((Object)enemy).name + " is visible before any blocker; skipping duplicate wallbang damage."));
						}
					}
					else if (!Plugin.HitEachEnemyOnce.Value || hashSet.Add(enemy))
					{
						enemy.hitter = "piercer";
						enemy.DeliverDamage(((Component)((RaycastHit)(ref val3)).collider).gameObject, val2, ((RaycastHit)(ref val3)).point, num3, false, 0f, state.SourceWeapon, false, false);
						if (Plugin.DebugLogging.Value)
						{
							Plugin.Log.LogInfo((object)$"Wallbang hit {((Object)enemy).name} at {((RaycastHit)(ref val3)).distance:F2}m for {num3:F2} damage. shotType={state.ShotType}, charge={state.Charge:F2}, ready={state.PierceReady}");
						}
					}
				}
			}
		}

		private static EnemyIdentifier GetEnemy(Collider collider)
		{
			EnemyIdentifierIdentifier componentInParent = ((Component)collider).GetComponentInParent<EnemyIdentifierIdentifier>();
			if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.eid != (Object)null)
			{
				return componentInParent.eid;
			}
			return ((Component)collider).GetComponentInParent<EnemyIdentifier>();
		}
	}
}